Skip to content

How to (persistently) change the Cmd Space remap

RedBearAK edited this page Aug 8, 2024 · 8 revisions

In the default Toshy config, the Cmd+Space shortcut (standard Spotlight shortcut in macOS for several years) remaps onto different default shortcuts depending on the desktop environment, DE version, or even the distro. Sometimes it remaps to Alt+F1, or Ctrl+Esc, or just the Meta key. The Toshy config tries to have some sane defaults for this shortcut for a number of the more common Linux desktop environments.

But this doesn't always work out, or you may want to change what the shortcut does, to use an alternate search bar or app launcher. In modern KDE Plasma there are at least three different built-in options for searching or launching apps, all powered by krunner search settings. I'm having a hard time deciding which of those should be activated by Cmd+Space in Plasma. The simple krunner pop-down (which can be changed to pop up in the middle of the screen) would actually be the closest analogue to the Spotlight dialog in macOS. So that might become the default. But right now it's the "Kicker" main application launcher menu. Another option is the new "Overview" that Plasma copied from GNOME (which GNOME may have copied from macOS, but would probably claim they didn't 🤣).

So how do we change this particular shortcut remap to make a custom remap when the Toshy default choice isn't quite right? Hopefully, this Wiki page will explain in a sensible way. The instructions here would actually apply to any other specific shortcut that you want to override from the default behavior, but I'm focusing on Cmd+Space in the examples.

The Steps to Enlightenment

Step 0: Why all the steps?

Be aware that if you reinstall or upgrade Toshy at some point, any customizations you make to the config file will be saved in a backup file by the Toshy installer script, but won't be automatically inserted into the new config file that the Toshy installer creates unless you keep your edits inside the marked "slices". So follow the instructions to have a permanent solution that will survive this process.

Step 1: It's just a keymapper

Understand that this is just a keymapper config. In most cases Toshy doesn't actually change any of the native shortcuts, the config just "remaps" some shortcuts onto some native shortcut that already exists. (But the Toshy installer will in a couple of cases disable a Meta-only shortcut.) So basically all you need to do is find a way to "override" the existing behavior of the Cmd+Space shortcut.

Step 2: Identify the keymap

Realize that when you see the following sort of pattern in the config file, the C("RC-Space"): represents the keys at the physical location where Cmd+Space would be on an Apple keyboard, regardless of the actual keyboard type (Windows, Apple, IBM, Chromebook):

keymap("Some unique keymap name", {
…
    C("RC-Space"):  [some key/combo/macro on this side of the colon], # A comment about the remap
…
}, when = [some match condition will appear here] )

For clarity, the curly braces here represent a Python "dictionary" being given as the second argument to the keymap() function, with the first argument being the keymap name string, and the last argument being the when condition that controls when the keymap becomes active in memory. In Python, dictionaries are sets of key:value pairs, with each pair separated by a comma from additional key:value pairs. In this case, in the keymap() function, the "keys" represent an input combo, and then the "values" on the other side of the colon represent whatever you want the output key, combo or macro to be. Python allows for line breaks and comments inside the curly braces, so we can lay out the key:value pairs in a nice readable way. Regardless of the line breaks, it's still just a function call: keymap(arg1, arg2, arg3).

Step 3: Find the keymap

Figure out which existing keymap is being used to remap Cmd+Space to something native. Not all possible shortcuts are remapped to something else in the config file. But this one will basically always be remapped regardless of your desktop environment, because one of the remaps for it is in the "General" keymap, which is always active unless you are in some kind of "remote" or virtual machine app.

Here is how to check which keymap is being used when you use Cmd+Space. Run the command below in a terminal, wait a few seconds for it to start up, and then use the Cmd+Space shortcut to see the debugging output that occurs.

toshy-debug

Or you can use this older, longer alias to do the same thing:

toshy-config-verbose-start

(You can usually get the whole command quickly via Tab-completion by just typing "tosh[Tab]co[Tab]ve[Tab]" and then hitting Enter.)

There will be a lot of debugging output, but what you want to see right after using Cmd+Space is a larger block like this, between the press and release events for the Space key:

(II) in SPACE (press)
(DD) SHELL_EXT: Using UUID '[email protected]' for window context
(DD) on_key SPACE press
(DD) KBTYPE: 'Windows' | (CACHED) Rgx matched on dev: 'AT Translated Set 2 keyboard'

(DD) WM_CLASS: 'gnome-terminal-server' | WM_NAME: 'Terminal'
(DD) DEVICE: 'AT Translated Set 2 keyboard' | CAPS_LOCK: 'False' | NUM_LOCK: 'False'
(DD) ACTIVE KEYMAPS:
     'User hardware keys', 'Currency character overlay', 'Wordwise - not
      … vscode', 'GenTerms overrides: Fedora GNOME', 'GenTerms overrides:
      … Ubuntu/Fedora', 'GenTerms overrides: GNOME', 'General Terminals', 'GenGUI
      … overrides: not Chromebook', 'GenGUI overrides: Fedora GNOME', 'GenGUI
      … overrides: GNOME', 'General GUI', 'Diagnostics'
(DD) COMBO: RCtrl-SPACE => [<function iEF2.<locals>._is_Enter_F2 at 0x7f945822ab60>, <Key.LEFT_META: 125>] in KMAP: 'GenGUI overrides: GNOME'
(DD) spent modifiers [<Key.RIGHT_CTRL: 97>]
(DD) resuspending keys
(DD) suspending keys: [RCtrl<Key.RIGHT_CTRL>]
(DD) _is_Enter_F2:  combo_list      = [None]
(DD) _is_Enter_F2:  _enter_is_F2    = True
(DD) resuspending keys
(DD) suspending keys: [RCtrl<Key.RIGHT_CTRL>]
(OO) press LEFT_META 1709934239.0447977
(OO) release LEFT_META 1709934239.0450451

(II) in SPACE (release)
(DD) SHELL_EXT: Using UUID '[email protected]' for window context
(DD) on_key SPACE release

Your desktop environment will determine exactly how much it looks like the example above, but the important part is just this:

(DD) COMBO: RCtrl-SPACE => [<function iEF2.<locals>._is_Enter_F2 at 0x7f945822ab60>, <Key.LEFT_META: 125>] in KMAP: 'GenGUI overrides: GNOME'

And maybe these, if they appear (could be important in situations other than a general shortcut like Cmd+Space, where it's not that relevant):

(DD) _is_Enter_F2:  combo_list      = [None]
(DD) _is_Enter_F2:  _enter_is_F2    = True

The COMBO line helpfully also contains the specific keymap name where this combo was found:

KMAP: 'GenGUI overrides: GNOME'

Now we can move on...

Step 4: Copy the keymap

Find the keymap with that name in the config file. The config file is toshy_config.py in the folder ~/.config/toshy/. There is an easy way to open the config folder in the tray icon menu. It's helpful to have an editor like Visual Studio Code or GNOME Text Editor, or KWrite or Kate in KDE Plasma. Something that supports syntax highlighting. But modifications can be made to the config file with any simple "text editor" (don't use a "word processor" type of application for code editing). It's just a plain UTF-8 text file, and needs to stay that way.

The keymap from the example currently looks like this (it's the second one, but the first one might be relevant for an older GNOME install):

if DESKTOP_ENV == 'gnome':
    if is_pre_GNOME_45(DE_MAJ_VER):
        # This keymap, if invoked, must come before the other GNOME overrides in the next keymap, not after.
        keymap("GenGUI overrides: pre-GNOME 45 fix", {
            C("RC-Space"):             [C("Super-s"),iEF2NT()],         # Override GNOME 45+ Shift+Ctrl+Space remap
        }, when = lambda ctx:
            cnfg.screen_has_focus and
            matchProps(not_clas=remoteStr)(ctx)
        )
    keymap("GenGUI overrides: GNOME", {
        C("RC-Space"):             [C("Shift-C-Space"),iEF2NT()],   # Show GNOME overview/app launcher
        C("RC-F3"):                 C("Super-d"),                   # Default SL - Show Desktop (gnome/kde,elementary)
        C("RC-Super-f"):            C("Alt-F10"),                   # Default SL - Maximize app (gnome/kde)
        C("RC-H"):                  C("Super-h"),                   # Default SL - Minimize app (gnome/budgie/popos/fedora) not-deepin
        # Screenshot shortcuts for GNOME 42+
        C("RC-Shift-Key_3"):        C("Shift-Print"),               # Take a screenshot immediately (gnome)
        C("RC-Shift-Key_4"):        C("Alt-Print"),                 # Take a screenshot of a window (gnome)
        C("RC-Shift-Key_5"):        C("Print"),                     # Take a screenshot interactively (gnome)
    }, when = lambda ctx:
        cnfg.screen_has_focus and
        matchProps(not_clas=remoteStr)(ctx)
    )

Now copy the whole keymap into the clipboard or even copy/paste it into a separate editor window/tab, and proceed to the next step...

Step 5: Paste new keymap

Search for the string "user_apps" in your config file, and paste the copy of the keymap inside the marked "slice". It should end up looking something like this:

####################################  USER APPS  #####################################
###                                                                                ###
###                                                                                ###
###      ██    ██ ███████ ███████ ██████       █████  ██████  ██████  ███████      ###
###      ██    ██ ██      ██      ██   ██     ██   ██ ██   ██ ██   ██ ██           ###
###      ██    ██ ███████ █████   ██████      ███████ ██████  ██████  ███████      ###
###      ██    ██      ██ ██      ██   ██     ██   ██ ██      ██           ██      ###
###       ██████  ███████ ███████ ██   ██     ██   ██ ██      ██      ███████      ###
###                                                                                ###
###                                                                                ###
######################################################################################
### This is a good location in the config file for adding new custom keymaps for 
### user applications and custom function keys. Watch out that you don't override 
### any "general" shortcuts like Cmd+Z/X/C/V that may be defined below this section. 
### Changes made between the "slice" marks will be retained by the Toshy installer 
### if you reinstall and it finds matching start/end markers for each section. 

###################################################################################################
###  SLICE_MARK_START: user_apps  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE


if DESKTOP_ENV == 'gnome':
    keymap("GenGUI overrides: GNOME", {
        C("RC-Space"):             [C("Shift-C-Space"),iEF2NT()],   # Show GNOME overview/app launcher
        C("RC-F3"):                 C("Super-d"),                   # Default SL - Show Desktop (gnome/kde,elementary)
        C("RC-Super-f"):            C("Alt-F10"),                   # Default SL - Maximize app (gnome/kde)
        C("RC-H"):                  C("Super-h"),                   # Default SL - Minimize app (gnome/budgie/popos/fedora) not-deepin
        # Screenshot shortcuts for GNOME 42+
        C("RC-Shift-Key_3"):        C("Shift-Print"),               # Take a screenshot immediately (gnome)
        C("RC-Shift-Key_4"):        C("Alt-Print"),                 # Take a screenshot of a window (gnome)
        C("RC-Shift-Key_5"):        C("Print"),                     # Take a screenshot interactively (gnome)
    }, when = lambda ctx:
        cnfg.screen_has_focus and
        matchProps(not_clas=remoteStr)(ctx)
    )


###  SLICE_MARK_END: user_apps  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE
###################################################################################################

Being inside those "slice marks" is VERY important.

But we don't actually want to override the entire keymap, and if we keep the same name it probably won't work as expected, so change the name and trim it down a bit:

###################################################################################################
###  SLICE_MARK_START: user_apps  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE


if DESKTOP_ENV == 'gnome':
    keymap("GenGUI overrides: GNOME - user overrides", {
        C("RC-Space"):             [C("Shift-C-Space"),iEF2NT()],   # Show GNOME overview/app launcher
    }, when = lambda ctx:
        cnfg.screen_has_focus and
        matchProps(not_clas=remoteStr)(ctx)
    )


###  SLICE_MARK_END: user_apps  ###  EDITS OUTSIDE THESE MARKS WILL BE LOST ON UPGRADE
###################################################################################################

Here I've just changed the keymap name to 'GenGUI overrides: GNOME - user override' and removed the irrelevant shortcuts, but I haven't actually changed the shortcut yet. It's still remapping to Shift-C-Space by default (for GNOME 45 or later), as part of a macro (as indicated by the brackets). This is a shortcut set up by the Toshy installer, because there's no longer a default shortcut to map onto, other than Meta, which is problematic.

The iEF2NT() function helps control the behavior of the Enter key in file manager apps. It's not crucial to retain, but recommended. What it tries to do is make sure the Enter key will immediately be the Enter key instead of F2, if you launched the app launcher while in a file manager app. If it's not there or doesn't work, you may have to hit Enter twice in such situations.

Now let's say you set up a native shortcut in GNOME's keyboard settings, to activate something like Ulauncher (with the ulauncher-toggle command) using Alt+F3. (Remember, this is completely outside the Toshy config.) Then you might modify that remap line to something like this:

    C("RC-Space"):             [C("Alt-F3"),iEF2NT()],        # Show GNOME overview/app launcher

Or maybe you were able to bind some search extension to activating with Alt+F1 (this broke in a recent GNOME update for some reason, nothing to do with Toshy). Then you would use this:

    C("RC-Space"):             [C("Alt-F1"),iEF2NT()],        # Show GNOME overview/app launcher

Another example, what if you literally wanted Cmd+Space to issue Ctrl+Space (a simple thing, since the "Command" modifier key under Toshy becomes RIGHT_CTRL). Then you'd do:

    C("RC-Space"):             [C("C-Space"),iEF2NT()],        # Show GNOME overview/app launcher

Or what if you are on a PC keyboard where the physical Alt key is acting as the "Command" key, but when you turn Toshy off you want that same physical shortcut to activate the same launcher? This is possible if you have a situation where you can set up two different native shortcuts that trigger the launcher somehow, like with my GNOME setup that has two native shortcuts to activate the ulauncher-toggle command with either Alt+F3 or Alt+Space. The one that needs to be remapped in the Toshy config is "RC-Space" to "Alt+F3", like the example a little earlier. Then when Toshy is disabled, I still have the Ulauncher dialog when I press the same physical keys, but the shortcut in that case is the native "Alt+Space" shortcut.

In other words, there are a lot of different things you can do, but it depends on your desktop environment and how you can set up either native shortcuts or some keybinding directly inside the app preferences for the launcher app itself. In Wayland usually this needs to be taken care of by the shell, they are still working on the global shortcut protocol in most compositors.

Followups - How to restart Toshy

Any time the config file is changed, you must save the file and then restart Toshy to restart the keymapper process and load the new state of the config. How do you restart Toshy? From the tray icon menu ("Re/Start Toshy Services") or using the terminal command:

toshy-services-restart

After making modifications like this, you should see the new keymap name in the debugging output (from the verbose command) when using Cmd+Space. If you successfully followed the instructions and kept your custom edit inside those special "slice marks" (and didn't damage the slice markers) then you should be able to safely reinstall or upgrade Toshy in the future, and retain your custom remap.

Many other customizations such as fixes for some hardware keys on PC laptops can go in that editable slice, and there are several other editable slice locations for different purposes. Like adding your own custom lists, modmaps or functions that don't make sense to add to the Toshy default config file.

NB: Modifying or removing the original keymap is not necessary, and that sort of change would get reset when reinstalling Toshy anyway. What we are doing here is putting a keymap in place that is (A) active under the same circumstances and (B) sits in memory to be seen before the original keymap, thus preventing the original keymap from ever being used for that particular shortcut. Basically we are "shadowing" the original keymap, but only for that specific remap/combo.