Commit 4ef27790 authored by Andreas Wettstein's avatar Andreas Wettstein Committed by Ulrich Sibiller

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: 's avatarAndreas Wettstein <wettstein509@solnet.ch> Signed-off-by: 's avatarJames Cloos <cloos@jhcloos.com> Backported-to-NX-by: 's avatarUlrich Sibiller <uli42@gmx.de>
parent b8b885da
...@@ -43,18 +43,17 @@ _XimLocalFilter(Display *d, Window w, XEvent *ev, XPointer client_data) ...@@ -43,18 +43,17 @@ _XimLocalFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
Xic ic = (Xic)client_data; Xic ic = (Xic)client_data;
KeySym keysym; KeySym keysym;
static char buf[256]; static char buf[256];
static unsigned prevcode = 0, prevstate = 0;
unsigned currstate;
DefTree *b = ic->private.local.base.tree; DefTree *b = ic->private.local.base.tree;
DTIndex t; DTIndex t;
Bool braille = False; Bool braille = False, anymodifier = False;
if(ev->xkey.keycode == 0) if(ev->xkey.keycode == 0)
return (False); return (False);
XLookupString((XKeyEvent *)ev, buf, sizeof(buf), &keysym, NULL); 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(keysym >= XK_braille_dot_1 && keysym <= XK_braille_dot_8) {
if(ev->type == KeyPress) { if(ev->type == KeyPress) {
ic->private.local.brl_pressed |= ic->private.local.brl_pressed |=
...@@ -78,38 +77,71 @@ _XimLocalFilter(Display *d, Window w, XEvent *ev, XPointer client_data) ...@@ -78,38 +77,71 @@ _XimLocalFilter(Display *d, Window w, XEvent *ev, XPointer client_data)
} }
} }
if( (ev->type != KeyPress) if(((Xim)ic->core.im)->private.local.top == 0 )
|| (((Xim)ic->core.im)->private.local.top == 0 ) )
goto emit_braille; 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) { 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) && if(((ev->xkey.state & b[t].modifier_mask) == b[t].modifier) &&
(keysym == b[t].keysym)) (keysym == b[t].keysym))
break; break;
} }
/* Restore the state */
ev->xkey.state = currstate;
if(t) { /* Matched */ if(t) { /* Matched */
if(b[t].succession) { /* Intermediate */ if(b[t].succession) { /* Intermediate */
ic->private.local.context = b[t].succession; ic->private.local.context = b[t].succession;
return(True); return (ev->type == KeyPress);
} else { /* Terminate (reached to leaf) */ } else { /* Terminate (reached to leaf) */
ic->private.local.composed = t; ic->private.local.composed = t;
ic->private.local.brl_committed = 0; ic->private.local.brl_committed = 0;
/* return back to client KeyPressEvent keycode == 0 */ /* return back to client KeyPressEvent keycode == 0 */
ev->xkey.keycode = 0; ev->xkey.keycode = 0;
ev->xkey.type = KeyPress;
XPutBackEvent(d, ev); 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 */ /* initialize internal state for next key sequence */
ic->private.local.context = ((Xim)ic->core.im)->private.local.top; ic->private.local.context = ((Xim)ic->core.im)->private.local.top;
return(True); return (ev->type == KeyPress);
} }
} else { /* Unmatched */ } 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; goto emit_braille;
} }
/* Error (Sequence Unmatch occured) */ /* Error (Sequence Unmatch occured) */
/* initialize internal state for next key sequence */ /* initialize internal state for next key sequence */
ic->private.local.context = ((Xim)ic->core.im)->private.local.top; ic->private.local.context = ((Xim)ic->core.im)->private.local.top;
return(True); return (ev->type == KeyPress);
} }
emit_braille: emit_braille:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment