inputMethod: Handle IBusInputContext::forward-key-press
The input method may hint that certain keycodes should be pressed/released besides the textual information in ::commit. An example is hitting space in some IMs to commit text, where both ::commit happens, and an space is visibly inserted. In order to handle this properly, we must honor ::forward-key-press. In order to cater for the case that a keypress is forwarded while handling that same keypress in a physical keyboard, check the current event being handled and just forward it as-is if it matches. This is necessary to prevent state from being doubly set, and the second event silenced away. https://gitlab.gnome.org/GNOME/gnome-shell/issues/275 Closes: #275
This commit is contained in:
parent
a5937d1d6d
commit
374caade47
@ -15,6 +15,8 @@ var InputMethod = new Lang.Class({
|
|||||||
this._purpose = 0;
|
this._purpose = 0;
|
||||||
this._enabled = true;
|
this._enabled = true;
|
||||||
this._currentFocus = null;
|
this._currentFocus = null;
|
||||||
|
this._currentEvent = null;
|
||||||
|
this._doForwardEvent = false;
|
||||||
this._ibus = IBus.Bus.new_async();
|
this._ibus = IBus.Bus.new_async();
|
||||||
this._ibus.connect('connected', this._onConnected.bind(this));
|
this._ibus.connect('connected', this._onConnected.bind(this));
|
||||||
this._ibus.connect('disconnected', this._clear.bind(this));
|
this._ibus.connect('disconnected', this._clear.bind(this));
|
||||||
@ -25,6 +27,9 @@ var InputMethod = new Lang.Class({
|
|||||||
this._onSourceChanged.bind(this));
|
this._onSourceChanged.bind(this));
|
||||||
this._currentSource = this._inputSourceManager.currentSource;
|
this._currentSource = this._inputSourceManager.currentSource;
|
||||||
|
|
||||||
|
let deviceManager = Clutter.DeviceManager.get_default();
|
||||||
|
this._virtualDevice = deviceManager.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
|
||||||
|
|
||||||
if (this._ibus.is_connected())
|
if (this._ibus.is_connected())
|
||||||
this._onConnected();
|
this._onConnected();
|
||||||
},
|
},
|
||||||
@ -64,6 +69,7 @@ var InputMethod = new Lang.Class({
|
|||||||
this._context.connect('commit-text', this._onCommitText.bind(this));
|
this._context.connect('commit-text', this._onCommitText.bind(this));
|
||||||
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
|
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
|
||||||
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
|
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
|
||||||
|
this._context.connect('forward-key-event', this._onForwardKeyEvent.bind(this));
|
||||||
|
|
||||||
this._updateCapabilities();
|
this._updateCapabilities();
|
||||||
},
|
},
|
||||||
@ -96,6 +102,24 @@ var InputMethod = new Lang.Class({
|
|||||||
this.set_preedit_text(str, pos);
|
this.set_preedit_text(str, pos);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onForwardKeyEvent(context, keyval, keycode, state) {
|
||||||
|
let press = (state & IBus.ModifierType.RELEASE_MASK) == 0;
|
||||||
|
|
||||||
|
if (this._currentEvent) {
|
||||||
|
// If we are handling this same event in filter_key_press(),
|
||||||
|
// just let it go through, sending the same event again will
|
||||||
|
// be silenced away because the key counts as pressed.
|
||||||
|
if (this._currentEvent.get_key_symbol() == keyval &&
|
||||||
|
(this._currentEvent.type() == Clutter.EventType.KEY_PRESS) == press) {
|
||||||
|
this._doForwardEvent = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._virtualDevice.notify_key(Clutter.get_current_event_time(), keycode,
|
||||||
|
press ? Clutter.KeyState.PRESSED : Clutter.KeyState.RELEASED);
|
||||||
|
},
|
||||||
|
|
||||||
vfunc_focus_in(focus) {
|
vfunc_focus_in(focus) {
|
||||||
this._currentFocus = focus;
|
this._currentFocus = focus;
|
||||||
if (this._context) {
|
if (this._context) {
|
||||||
@ -197,13 +221,23 @@ var InputMethod = new Lang.Class({
|
|||||||
|
|
||||||
if (event.type() == Clutter.EventType.KEY_RELEASE)
|
if (event.type() == Clutter.EventType.KEY_RELEASE)
|
||||||
state |= IBus.ModifierType.RELEASE_MASK;
|
state |= IBus.ModifierType.RELEASE_MASK;
|
||||||
|
|
||||||
|
this._currentEvent = event;
|
||||||
|
this._doForwardEvent = false;
|
||||||
|
|
||||||
this._context.process_key_event_async(event.get_key_symbol(),
|
this._context.process_key_event_async(event.get_key_symbol(),
|
||||||
event.get_key_code() - 8, // Convert XKB keycodes to evcodes
|
event.get_key_code() - 8, // Convert XKB keycodes to evcodes
|
||||||
state, -1, null,
|
state, -1, null,
|
||||||
(context, res) => {
|
(context, res) => {
|
||||||
try {
|
try {
|
||||||
let retval = context.process_key_event_async_finish(res);
|
let retval = context.process_key_event_async_finish(res);
|
||||||
|
|
||||||
|
if (this._doForwardEvent)
|
||||||
|
retval = false;
|
||||||
|
|
||||||
this.notify_key_event(event, retval);
|
this.notify_key_event(event, retval);
|
||||||
|
this._doForwardEvent = false;
|
||||||
|
this._currentEvent = null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Error processing key on IM: ' + e.message);
|
log('Error processing key on IM: ' + e.message);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user