From 99c77e85b3514e885641ebdc3dee3d4508e08fbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Mon, 16 Jul 2018 23:36:38 +0000 Subject: [PATCH 1/6] keyboard: Handle no-window case in FocusTracker For windows, the cursor location needs to be adjusted by the frame offsets. However we cannot assume that there is a window, as the shell itself can have the key focus. https://gitlab.gnome.org/GNOME/gnome-shell/issues/414 (cherry picked from commit 0dee82fb9fa974ebdb4dd77fd85535a6edf207fd) --- js/ui/keyboard.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js index 5fcdf988a..66653d602 100644 --- a/js/ui/keyboard.js +++ b/js/ui/keyboard.js @@ -533,17 +533,25 @@ var FocusTracker = new Lang.Class({ }, _setCurrentRect(rect) { - let frameRect = this._currentWindow.get_frame_rect(); - rect.x -= frameRect.x; - rect.y -= frameRect.y; + if (this._currentWindow) { + let frameRect = this._currentWindow.get_frame_rect(); + rect.x -= frameRect.x; + rect.y -= frameRect.y; + } this._rect = rect; this.emit('position-changed'); }, getCurrentRect() { - let frameRect = this._currentWindow.get_frame_rect(); - let rect = { x: this._rect.x + frameRect.x, y: this._rect.y + frameRect.y, width: this._rect.width, height: this._rect.height }; + let rect = { x: this._rect.x, y: this._rect.y, + width: this._rect.width, height: this._rect.height }; + + if (this._currentWindow) { + let frameRect = this._currentWindow.get_frame_rect(); + rect.x += frameRect.x; + rect.y += frameRect.y; + } return rect; } -- 2.20.1 From b89224c37afc9cbedbd776bfdd27c57849669fba Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 29 Jun 2018 17:35:39 +0200 Subject: [PATCH 2/6] 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 --- js/misc/inputMethod.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/js/misc/inputMethod.js b/js/misc/inputMethod.js index 621483243..59b3d78d6 100644 --- a/js/misc/inputMethod.js +++ b/js/misc/inputMethod.js @@ -15,6 +15,8 @@ var InputMethod = new Lang.Class({ this._purpose = 0; this._enabled = true; this._currentFocus = null; + this._currentEvent = null; + this._doForwardEvent = false; this._ibus = IBus.Bus.new_async(); this._ibus.connect('connected', this._onConnected.bind(this)); this._ibus.connect('disconnected', this._clear.bind(this)); @@ -25,6 +27,9 @@ var InputMethod = new Lang.Class({ this._onSourceChanged.bind(this)); 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()) this._onConnected(); }, @@ -64,6 +69,7 @@ var InputMethod = new Lang.Class({ this._context.connect('commit-text', this._onCommitText.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('forward-key-event', this._onForwardKeyEvent.bind(this)); this._updateCapabilities(); }, @@ -96,6 +102,24 @@ var InputMethod = new Lang.Class({ 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) { this._currentFocus = focus; if (this._context) { @@ -197,13 +221,23 @@ var InputMethod = new Lang.Class({ if (event.type() == Clutter.EventType.KEY_RELEASE) state |= IBus.ModifierType.RELEASE_MASK; + + this._currentEvent = event; + this._doForwardEvent = false; + this._context.process_key_event_async(event.get_key_symbol(), event.get_key_code() - 8, // Convert XKB keycodes to evcodes state, -1, null, (context, res) => { try { let retval = context.process_key_event_async_finish(res); + + if (this._doForwardEvent) + retval = false; + this.notify_key_event(event, retval); + this._doForwardEvent = false; + this._currentEvent = null; } catch (e) { log('Error processing key on IM: ' + e.message); } -- 2.20.1 From f8040e59811cd28d9c55d766d6f4c80cf45a226d Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Tue, 21 Aug 2018 20:21:53 +0900 Subject: [PATCH 3/6] inputMethod: Fix to hide preedit text ibus_engine_update_preedit_text() should hide the pre-edit text when visible == false. https://gitlab.gnome.org/GNOME/gnome-shell/issues/431 --- js/misc/inputMethod.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/js/misc/inputMethod.js b/js/misc/inputMethod.js index 59b3d78d6..320a6cc33 100644 --- a/js/misc/inputMethod.js +++ b/js/misc/inputMethod.js @@ -17,6 +17,8 @@ var InputMethod = new Lang.Class({ this._currentFocus = null; this._currentEvent = null; this._doForwardEvent = false; + this._preeditStr = ''; + this._preeditPos = 0; this._ibus = IBus.Bus.new_async(); this._ibus.connect('connected', this._onConnected.bind(this)); this._ibus.connect('disconnected', this._clear.bind(this)); @@ -69,6 +71,8 @@ var InputMethod = new Lang.Class({ this._context.connect('commit-text', this._onCommitText.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('show-preedit-text', this._onShowPreeditText.bind(this)); + this._context.connect('hide-preedit-text', this._onHidePreeditText.bind(this)); this._context.connect('forward-key-event', this._onForwardKeyEvent.bind(this)); this._updateCapabilities(); @@ -79,6 +83,8 @@ var InputMethod = new Lang.Class({ this._hints = 0; this._purpose = 0; this._enabled = false; + this._preeditStr = '' + this._preeditPos = 0; }, _emitRequestSurrounding() { @@ -95,11 +101,22 @@ var InputMethod = new Lang.Class({ }, _onUpdatePreeditText(context, text, pos, visible) { - let str = null; - if (visible && text != null) - str = text.get_text(); + if (text == null) + return; + this._preeditStr = text.get_text(); + this._preeditPos = pos; + if (visible) + this.set_preedit_text(this._preeditStr, pos); + else + this.set_preedit_text(null, pos); + }, + + _onShowPreeditText(context) { + this.set_preedit_text(this._preeditStr, this._preeditPos); + }, - this.set_preedit_text(str, pos); + _onHidePreeditText(context) { + this.set_preedit_text(null, this._preeditPos); }, _onForwardKeyEvent(context, keyval, keycode, state) { -- 2.20.1 From 43c841a6b9f79b136f8bfe34a28b5c9681006ae7 Mon Sep 17 00:00:00 2001 From: Andrea Azzarone Date: Mon, 17 Sep 2018 18:00:04 +0200 Subject: [PATCH 4/6] inputMethod: Add a null-check for text in vfunc_set_surrounding. Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/579 --- js/misc/inputMethod.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/misc/inputMethod.js b/js/misc/inputMethod.js index 320a6cc33..ec84f7277 100644 --- a/js/misc/inputMethod.js +++ b/js/misc/inputMethod.js @@ -176,7 +176,7 @@ var InputMethod = new Lang.Class({ }, vfunc_set_surrounding(text, cursor, anchor) { - if (this._context) + if (this._context && text) this._context.set_surrounding_text(text, cursor, anchor); }, -- 2.20.1 From 5f03edcadcada801100bab027188660fb2a4c3f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 11 Sep 2018 15:36:35 +0200 Subject: [PATCH 5/6] inputMethod: Fix setting surrounding text The underlying ibus method expects an object of type IBusText rather than a plain string. https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/228 --- js/misc/inputMethod.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/js/misc/inputMethod.js b/js/misc/inputMethod.js index ec84f7277..7fb78178a 100644 --- a/js/misc/inputMethod.js +++ b/js/misc/inputMethod.js @@ -176,8 +176,11 @@ var InputMethod = new Lang.Class({ }, vfunc_set_surrounding(text, cursor, anchor) { - if (this._context && text) - this._context.set_surrounding_text(text, cursor, anchor); + if (!this._context || !text) + return; + + let ibusText = IBus.Text.new_from_string(text); + this._context.set_surrounding_text(ibusText, cursor, anchor); }, vfunc_update_content_hints(hints) { -- 2.20.1 From 4ed4039ae031f1ed16bac2e7729c84e300f90534 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 27 Sep 2018 21:09:02 +0200 Subject: [PATCH 6/6] inputMethod: Use forward_key() method to forward key events ClutterVirtualInputDevice has the limitation that event flags won't be made to contain CLUTTER_EVENT_FLAG_INPUT_METHOD, possibly causing feedback loops. As the event gets injected up the platform dependent bits, we can avoid care on not pressing the same key twice, we still expect coherence between key presses and releases from the IM though. https://gitlab.gnome.org/GNOME/gnome-shell/issues/531 --- js/misc/inputMethod.js | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/js/misc/inputMethod.js b/js/misc/inputMethod.js index 7fb78178a..4a92dc49b 100644 --- a/js/misc/inputMethod.js +++ b/js/misc/inputMethod.js @@ -15,8 +15,6 @@ var InputMethod = new Lang.Class({ this._purpose = 0; this._enabled = true; this._currentFocus = null; - this._currentEvent = null; - this._doForwardEvent = false; this._preeditStr = ''; this._preeditPos = 0; this._ibus = IBus.Bus.new_async(); @@ -29,9 +27,6 @@ var InputMethod = new Lang.Class({ this._onSourceChanged.bind(this)); 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()) this._onConnected(); }, @@ -121,20 +116,16 @@ var InputMethod = new Lang.Class({ _onForwardKeyEvent(context, keyval, keycode, state) { let press = (state & IBus.ModifierType.RELEASE_MASK) == 0; + state &= ~(IBus.ModifierType.RELEASE_MASK); - 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; - } - } + let curEvent = Clutter.get_current_event(); + let time; + if (curEvent) + time = curEvent.get_time(); + else + time = global.display.get_current_time_roundtrip(); - this._virtualDevice.notify_key(Clutter.get_current_event_time(), keycode, - press ? Clutter.KeyState.PRESSED : Clutter.KeyState.RELEASED); + this.forward_key(keyval, keycode + 8, state & Clutter.ModifierType.MODIFIER_MASK, time, press); }, vfunc_focus_in(focus) { @@ -242,22 +233,13 @@ var InputMethod = new Lang.Class({ if (event.type() == Clutter.EventType.KEY_RELEASE) state |= IBus.ModifierType.RELEASE_MASK; - this._currentEvent = event; - this._doForwardEvent = false; - this._context.process_key_event_async(event.get_key_symbol(), event.get_key_code() - 8, // Convert XKB keycodes to evcodes state, -1, null, (context, res) => { try { let retval = context.process_key_event_async_finish(res); - - if (this._doForwardEvent) - retval = false; - this.notify_key_event(event, retval); - this._doForwardEvent = false; - this._currentEvent = null; } catch (e) { log('Error processing key on IM: ' + e.message); } -- 2.20.1