ports/178170: [patch] xdb misbehaviour on keyboard layouts switch

Eugene Grosbein eugen at grosbein.net
Fri Apr 26 05:10:01 UTC 2013


>Number:         178170
>Category:       ports
>Synopsis:       [patch] xdb misbehaviour on keyboard layouts switch
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Apr 26 05:10:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Eugene Grosbein
>Release:        FreeBSD 8.4-BETA1 amd64
>Organization:
RDTC JSC
>Environment:
System: FreeBSD eg.sd.rdtc.ru 8.4-BETA1 FreeBSD 8.4-BETA1 #1: Tue Apr 16 17:55:46 NOVT 2013 root at eg.sd.rdtc.ru:/usr/local/obj/usr/local/src/sys/EG amd64

>Description:

	The problem described here is exactly identical to
	https://bugs.freedesktop.org/show_bug.cgi?id=865

	In short, xkb switches keyboard layouts on press of switching key
	combination. This breaks application hotkeys like Ctrl-Shift-A
	when your layout switching key combo is Ctrl-Shift. xkb should
	switch layouts on key release, not press, like Windows GUI does.

>How-To-Repeat:

	The section in xorg.conf:

Section "InputDevice"
	Identifier  "Keyboard0"
	Driver      "kbd"
	Option      "XkbRules" "xorg"
	Option      "XkbModel" "pc105"
	Option      "XkbLayout" "us,ru"
	Option      "XkbVariant" "winkeys"
	Option      "XkbOptions" "grp:ctrl_shift_toggle"
EndSection

	For example, you cannot use Ctrl-Shift-A in Firefox with such config.

>Fix:

	The patch taken from mentioned freedesktop.org bug solves the problem
	by changing xkb behaviour to switch layouts on key release.

	https://bugs.freedesktop.org/attachment.cgi?id=33142

	The patch should be added to ports tree as
	ports/x11-servers/xorg-server/files/patch-xkbActions.c

--- xkb/xkbActions.c
+++ xkb/xkbActions.c
@@ -325,24 +325,83 @@ _XkbFilterLatchState(	XkbSrvInfoPtr	xkbi,
     return 1;
 }
 
+static int xkbSwitchGroupOnRelease(void)
+{
+    /* TODO: user configuring */
+    return TRUE;
+}
+
+static void xkbUpdateLockedGroup(XkbSrvInfoPtr xkbi, XkbAction* pAction)
+{
+    XkbGroupAction ga = pAction->group;
+    if (ga.flags&XkbSA_GroupAbsolute)
+	xkbi->state.locked_group= XkbSAGroup(&ga);
+    else xkbi->state.locked_group+= XkbSAGroup(&ga);
+}
+
+static XkbFilterPtr _XkbNextFreeFilter(XkbSrvInfoPtr xkbi);
+
 static int
-_XkbFilterLockState(	XkbSrvInfoPtr	xkbi,
+_XkbFilterLockGroup(	XkbSrvInfoPtr	xkbi,
 			XkbFilterPtr	filter,
 			unsigned	keycode,
 			XkbAction *	pAction)
 {
-    if (pAction&&(pAction->type==XkbSA_LockGroup)) {
-	if (pAction->group.flags&XkbSA_GroupAbsolute)
-	     xkbi->state.locked_group= XkbSAGroup(&pAction->group);
-	else xkbi->state.locked_group+= XkbSAGroup(&pAction->group);
-	return 1;
+    int sendEvent = 1;
+
+    if (!xkbSwitchGroupOnRelease()) {
+	xkbUpdateLockedGroup(xkbi, pAction);
+	return sendEvent;
+    }
+    
+    /* Delay switch till button release */
+    if (filter->keycode==0) {		/* initial press */
+	filter->keycode = keycode;
+	filter->active = 1;
+	filter->filterOthers = 0; /* for what? */
+	filter->filter = _XkbFilterLockGroup;
+
+	/* filter->priv = 0; */
+	filter->upAction = *pAction;
+
+	/* Ok, now we need to simulate the action which would go if this action didn't block it.
+	   XkbSA_SetMods is the one: it is to set modifier' flag up. */
+	{
+	    XkbStateRec	fake_state = xkbi->state;
+	    XkbAction act;
+
+	    fake_state.mods = 0;
+	    act = XkbGetKeyAction(xkbi, &fake_state, keycode);
+
+	    /* KLUDGE: XkbSA_SetMods only? */
+	    if (act.type == XkbSA_SetMods) { 
+		XkbFilterPtr filter = _XkbNextFreeFilter(xkbi);
+		sendEvent = _XkbFilterSetState(xkbi,filter,keycode,&act);
+	    }
+	}
     }
+    else {
+  	/* do nothing if some button else is pressed */
+	if (!pAction)
+	    xkbUpdateLockedGroup(xkbi, &filter->upAction);
+	filter->active = 0;
+    }
+
+    return sendEvent;
+}
+
+static int
+_XkbFilterLockMods(	XkbSrvInfoPtr	xkbi,
+			XkbFilterPtr	filter,
+			unsigned	keycode,
+			XkbAction *	pAction)
+{
     if (filter->keycode==0) {		/* initial press */
 	filter->keycode = keycode;
 	filter->active = 1;
 	filter->filterOthers = 0;
 	filter->priv = 0;
-	filter->filter = _XkbFilterLockState;
+	filter->filter = _XkbFilterLockMods;
 	filter->upAction = *pAction;
 	xkbi->state.locked_mods^= pAction->mods.mask;
 	xkbi->setMods = pAction->mods.mask;
@@ -1104,9 +1163,12 @@ xkbDeviceInfoPtr xkbPrivPtr = XKBDEVICEINFO(dev);
 		    sendEvent=_XkbFilterLatchState(xkbi,filter,key,&act);
 		    break;
 		case XkbSA_LockMods:
+		    filter = _XkbNextFreeFilter(xkbi);
+		    sendEvent=_XkbFilterLockMods(xkbi,filter,key,&act);
+		    break;
 		case XkbSA_LockGroup:
 		    filter = _XkbNextFreeFilter(xkbi);
-		    sendEvent=_XkbFilterLockState(xkbi,filter,key,&act);
+		    sendEvent=_XkbFilterLockGroup(xkbi,filter,key,&act);
 		    break;
 		case XkbSA_ISOLock:
 		    filter = _XkbNextFreeFilter(xkbi);
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-ports-bugs mailing list