summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Wettstein <wettstein509@solnet.ch>2011-11-08 20:18:09 +0000
committerJames Cloos <cloos@jhcloos.com>2011-12-11 16:56:06 -0500
commitd3b3570592e9b9e57f270a0bd86762fd205a2833 (patch)
tree3d2badbf9c7452d9ff54af0737a04f6f3ee7897f
parent56448a626fc90bcf75a1fa2f4c294b0eb1f23bd6 (diff)
XIM: Allow modifier releases in compose sequences (#26705)
Currently, only non-modifier keys (actually, keysyms) can be part of a compose sequence, and they are matched against the defined compose sequences at the time the key is pressed. The patch allows to use modifier keys an well, but matches them on key release, and only if no other key has been pressed after the modifier. Releasing a non-matched modifier during an ongoing compose sequence only aborts the sequence if any modifier release would have matched. In particular, if no compose sequences with modifiers are specified, the compose mechanism works exactly as without this patch. Even if modifiers are part of a compose sequence, they are not filtered. This is because modifiers affect the keyboard state no matter what we do here and, therefore, filtering them only could confuse clients. The purpose is this extension to the compose mechanism is to allow to make better use of keys in convenient reach for touch typing. Signed-off-by: Andreas Wettstein <wettstein509@solnet.ch> Signed-off-by: James Cloos <cloos@jhcloos.com>
-rw-r--r--modules/im/ximcp/imLcFlt.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/modules/im/ximcp/imLcFlt.c b/modules/im/ximcp/imLcFlt.c
index 06aa9980..a7060903 100644
--- a/modules/im/ximcp/imLcFlt.c
+++ b/modules/im/ximcp/imLcFlt.c
@@ -43,18 +43,17 @@ _XimLocalFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
Xic ic = (Xic)client_data;
KeySym keysym;
static char buf[256];
+ static unsigned prevcode = 0, prevstate = 0;
+ unsigned currstate;
DefTree *b = ic->private.local.base.tree;
DTIndex t;
- Bool braille = False;
+ Bool braille = False, anymodifier = False;
if(ev->xkey.keycode == 0)
return (False);
XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &keysym, NULL);
- if(IsModifierKey(keysym))
- return (False);
-
if(keysym >= XK_braille_dot_1 && keysym <= XK_braille_dot_8) {
if(ev->type == KeyPress) {
ic->private.local.brl_pressed |=
@@ -78,38 +77,71 @@ _XimLocalFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
}
}
- if( (ev->type != KeyPress)
- || (((Xim)ic->core.im)->private.local.top == 0 ) )
+ if(((Xim)ic->core.im)->private.local.top == 0 )
goto emit_braille;
+ currstate = ev->xkey.state;
+ if(ev->type == KeyPress) {
+ prevcode = ev->xkey.keycode;
+ prevstate = currstate;
+
+ if(IsModifierKey(keysym))
+ return(False);
+ prevcode = 0;
+ } else {
+ if(prevcode != ev->xkey.keycode)
+ return False;
+
+ /* For lookup, we use the state at the time when the key was pressed, */
+ /* because this state was not affected by the modifier that is mapped */
+ /* to the key. */
+ ev->xkey.state = prevstate;
+ XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &keysym, NULL);
+ }
+
for(t = ic->private.local.context; t; t = b[t].next) {
+ if(IsModifierKey(b[t].keysym))
+ anymodifier = True;
if(((ev->xkey.state & b[t].modifier_mask) == b[t].modifier) &&
(keysym == b[t].keysym))
break;
}
+ /* Restore the state */
+ ev->xkey.state = currstate;
+
if(t) { /* Matched */
if(b[t].succession) { /* Intermediate */
ic->private.local.context = b[t].succession;
- return(True);
+ return (ev->type == KeyPress);
} else { /* Terminate (reached to leaf) */
ic->private.local.composed = t;
ic->private.local.brl_committed = 0;
/* return back to client KeyPressEvent keycode == 0 */
ev->xkey.keycode = 0;
+ ev->xkey.type = KeyPress;
XPutBackEvent(d, ev);
+ if(prevcode){
+ /* For modifier key releases, restore the event, as we do not */
+ /* filter it. */
+ ev->xkey.type = KeyRelease;
+ ev->xkey.keycode = prevcode;
+ }
/* initialize internal state for next key sequence */
ic->private.local.context = ((Xim)ic->core.im)->private.local.top;
- return(True);
+ return (ev->type == KeyPress);
}
} else { /* Unmatched */
- if(ic->private.local.context == ((Xim)ic->core.im)->private.local.top) {
+ /* Unmatched modifier key releases abort matching only in the case that */
+ /* there was any modifier that would have matched */
+ if((ic->private.local.context == ((Xim)ic->core.im)->private.local.top) ||
+ (ev->type == KeyRelease && !anymodifier)) {
goto emit_braille;
}
/* Error (Sequence Unmatch occured) */
/* initialize internal state for next key sequence */
ic->private.local.context = ((Xim)ic->core.im)->private.local.top;
- return(True);
+ return (ev->type == KeyPress);
}
emit_braille: