From 9790aa7e7fa6115145e5bba44923039e9832e53a Mon Sep 17 00:00:00 2001 From: Mike FABIAN Date: Mon, 23 Dec 2024 21:47:43 +0100 Subject: [PATCH] Add option to force the use of the US keyboard layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ibus-typing-booster >= 2.27.0 also offers simple engines emulating the behaviour of the ibus-m17n engines, see: https://github.com/mike-fabian/ibus-typing-booster/issues/570 ibus-m17n has an option `☑️ Use US keyboard layout` which some users of ibus-m17n might miss if they try to use the Typing Booster engines emulating ibus-m17n. To make the switch to Typing Booster easier for such users, I am adding the same option to Typing Booster here. --- engine/hunspell_table.py | 47 +++++++++++++++++ ...top.ibus.engine.typing-booster.gschema.xml | 3 ++ setup/main.py | 50 +++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/engine/hunspell_table.py b/engine/hunspell_table.py index 152364ad..02c053d6 100644 --- a/engine/hunspell_table.py +++ b/engine/hunspell_table.py @@ -219,6 +219,9 @@ def __init__( 'ibuseventsleepseconds']['user'] LOGGER.info('self._ibus_event_sleep_seconds=%s', self._ibus_event_sleep_seconds) + self._ibus_us_keymap = IBus.Keymap('us') + self._use_us_layout: bool = self._settings_dict['useuslayout']['user'] + self._emoji_predictions: bool = self._settings_dict[ 'emojipredictions']['user'] @@ -748,6 +751,9 @@ def _init_settings_dict(self) -> Dict[str, Any]: 'ibuseventsleepseconds': { 'set': self.set_ibus_event_sleep_seconds, 'get': self.get_ibus_event_sleep_seconds}, + 'useuslayout': { + 'set': self.set_use_us_layout, + 'get': self.get_use_us_layout}, 'errorsound': { 'set': self.set_error_sound, 'get': self.get_error_sound}, @@ -5251,6 +5257,32 @@ def get_ibus_event_sleep_seconds(self) -> float: '''Returns the current value ibus event sleep seconds ''' return self._ibus_event_sleep_seconds + def set_use_us_layout( + self, mode: bool, update_gsettings: bool = True) -> None: + '''Sets whether the use of the US keyboard is forced + + :param mode: True if the use of the US keyboard is forced, False if not + :param update_gsettings: Whether to write the change to Gsettings. + Set this to False if this method is + called because the Gsettings key changed + to avoid endless loops when the Gsettings + key is changed twice in a short time. + ''' + if self._debug_level > 1: + LOGGER.debug( + '(%s, update_gsettings = %s)', mode, update_gsettings) + if mode == self._use_us_layout: + return + self._use_us_layout = mode + if update_gsettings: + self._gsettings.set_value( + 'useuslayout', + GLib.Variant.new_boolean(mode)) + + def get_use_us_layout(self) -> bool: + '''Returns whether the use of the US keyboard layout is forced''' + return self._use_us_layout + def set_error_sound( self, error_sound: bool, update_gsettings: bool = True) -> None: '''Sets whether a sound is played on error or not @@ -6968,6 +7000,21 @@ def do_process_key_event( # pylint: disable=arguments-differ key = itb_util.KeyEvent(keyval, keycode, state) if self._debug_level > 1: LOGGER.debug('KeyEvent object: %s', key) + if self._use_us_layout and key.name != 'Multi_key': + # Do not translate the Multi_key: If the non-US layout as + # a Multi_key, trying to translate it to US layout just + # takes it away. Skipping the translation keeps the + # Multi_key around which is more useful, it can still be + # used for Compose then. + key = itb_util.KeyEvent( + IBus.Keymap.lookup_keysym( + self._ibus_us_keymap, + keycode, + state), + keycode, state) + if self._debug_level > 1: + LOGGER.debug('Forcing US layout...') + LOGGER.debug('KeyEvent object: %s', key) disabled = False if not self._input_mode: diff --git a/org.freedesktop.ibus.engine.typing-booster.gschema.xml b/org.freedesktop.ibus.engine.typing-booster.gschema.xml index dd6fd308..a9c30b13 100644 --- a/org.freedesktop.ibus.engine.typing-booster.gschema.xml +++ b/org.freedesktop.ibus.engine.typing-booster.gschema.xml @@ -399,6 +399,9 @@ have been typed. + + false + false diff --git a/setup/main.py b/setup/main.py index efa66718..5f7510fb 100644 --- a/setup/main.py +++ b/setup/main.py @@ -789,6 +789,22 @@ def __init__( # pylint: disable=too-many-statements self._ascii_digits_checkbutton, 0, _options_grid_row, 2, 1) + self._use_us_layout_checkbutton = Gtk.CheckButton( + # Translators: Whether the use of the US keyboard layout is + # forced while Typing Booster is active + label=_('Use US keyboard layout')) + self._use_us_layout_checkbutton.set_tooltip_text( + _('Whether the use of the US keyboard layout is forced ' + 'while Typing Booster is active.')) + self._use_us_layout_checkbutton.connect( + 'clicked', self._on_use_us_layout_checkbutton) + self._use_us_layout_checkbutton.set_active( + self._settings_dict['useuslayout']['user']) + _options_grid_row += 1 + self._options_grid.attach( + self._use_us_layout_checkbutton, + 0, _options_grid_row, 2, 1) + self._emoji_trigger_characters_label = Gtk.Label() self._emoji_trigger_characters_label.set_text( # Translators: The characters in this list trigger an @@ -2304,6 +2320,7 @@ def _init_settings_dict(self) -> Dict[str, Any]: 'preeditstyleonlywhenlookup': self.set_preedit_style_only_when_lookup, 'mincharcomplete': self.set_min_char_complete, + 'useuslayout': self.set_use_us_layout, 'errorsound': self.set_error_sound, 'errorsoundfile': self.set_error_sound_file, 'soundbackend': self.set_sound_backend, @@ -3187,6 +3204,15 @@ def _on_ascii_digits_checkbutton( self.set_ascii_digits( widget.get_active(), update_gsettings=True) + def _on_use_us_layout_checkbutton( + self, widget: Gtk.CheckButton) -> None: + ''' + The checkbutton whether to force the use of the US + keyboard layout has been clicked. + ''' + self.set_use_us_layout( + widget.get_active(), update_gsettings=True) + def _on_emoji_trigger_characters_entry( self, widget: Gtk.Entry, _property_spec: Any) -> None: ''' @@ -6099,6 +6125,30 @@ def set_min_char_complete( self._min_char_complete_adjustment.set_value( int(min_char_complete)) + def set_use_us_layout( + self, + mode: bool, + update_gsettings: bool = True) -> None: + '''Sets whether the use of the US keyboard is forced + + :param mode: True if the use of the US keyboard is forced, False if not + :param update_gsettings: Whether to write the change to Gsettings. + Set this to False if this method is + called because the Gsettings key changed + to avoid endless loops when the Gsettings + key is changed twice in a short time. + ''' + LOGGER.info( + '(%s, update_gsettings = %s)', mode, update_gsettings) + mode = bool(mode) + self._settings_dict['useuslayout']['user'] = mode + if update_gsettings: + self._gsettings.set_value( + 'useuslayout', + GLib.Variant.new_boolean(mode)) + else: + self._use_us_layout_checkbutton.set_active(mode) + def set_error_sound( self, error_sound: bool,