[gnome-shell/wip/carlosg/im-forward-key: 35/35] inputMethod: Handle IBusInputContext::forward-key-press



commit 374caade4742405a402952a894f11ced77fe1b9b
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Jun 29 17:35:39 2018 +0200

    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);
                                                   }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]