Blob Blame History Raw
From 99c77e85b3514e885641ebdc3dee3d4508e08fbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
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 <carlosg@gnome.org>
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 <tfujiwar@redhat.com>
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 <andrea.azzarone@canonical.com>
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?= <fmuellner@gnome.org>
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 <carlosg@gnome.org>
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