Sublime Forum

Several questions related to keybinds and input

#1

I have several issues/questions regarding keybinds and input handling. I chose to collect them here since several questions are closely related.

(Context: I’m working on a plugin to do modal editing/navigation on the syntactical level of code using tree-sitter. I have some basic proof-of-concept functionality but I’m starting to encounter more and more frustrations, especially regarding keybind/input.)

1.a) I’ve seen several references to {"keys":["<character>"], ...} as a catch-all for triggering on regular self-inserted keys. But I cannot find its documentation. Are there other such special keys? (Specifically more expressive/powerful triggers like this <character>, not simple names like “f12” or “keypad_period”.)

1.b) How do I combine the above behavior but with modifiers? "ctrl+<character>", "super+<character>", etc. gives me syntax errors.

2.a) More generally, (and ideally,) I would like to run code on all input and choose to react/suppress/ignore/modify it. Is this possible? Basically, I’d like a function to be called with everything that log.input_events(True) normally prints. Ideally a function which has the option of reporting “I handled it, don’t worry about it” or “I don’t care about this input, you can forward it to other handlers.”

2.b) on_query_context gets close but it does not seem to receive information about the actual input event that triggered it? Did I miss or misunderstand something there?

(I imagine there exists the option of creating keymaps of several megabytes for thousands of Unicode characters together with all modifier combinations, but that just seems insanely painful and rather silly? My keyboard has several languages and lots of special characters like ∞∅⋆∈∧×⋅∘… etc…)

3. In my plugin code I would also ideally like to show overlays / certain information when a key is held down. For example like holding down "x" would show syntactic node type information. Is there a way to trigger on KeyDown/KeyUp events? Currently the only option I see is to either have an on/off toggle, or a “turn on & set a short timeout to turn off,” neither of which is ideal to me.

4. (Linux) Is there a way (e.g. hidden command-line flag) to make Sublime trigger shortcuts by symbol instead of by scancode? For some reason Sublime ignores the symbol (keyval in GTK) whenever a modifier is involved (if it’s not some basic US QWERTY ASCII), and instead uses the scancode (hardware_keycode in GTK). This makes zero sense to me (on Linux), and is pretty annoying/confusing. It seems like a Win32-like attempt at “localizing” keys? It matches neither my language nor my keyboard. If I hold down the Control key and type “¿”, it’s because I want to trigger “ctrl+¿”, not whatever this would blindly correspond to on some historic IBM keyboard (Sublime reports “ctrl+q” in this case).)

This also means duplicated ways to input shortcuts that cannot be disambiguated (e.g. both "ctrl+æ" and "ctrl+altgr+s" maps redundantly to "ctrl+[" in Sublime) and it means there are several reasonable keybinds I simply cannot input in Sublime even though I can ordinarily type the characters just fine (e.g. "shift+," produces ";" but Sublime interprets "ctrl+shift+," literally as itself – and the scancode for the US QWERTY key for semicolon happens to be taken by “o” in my case, thus I seem to have no way of actually triggering a shortcut like "ctrl+;").

1 Like

#2

No; just that. In use it binds to every character that can be typed (or rather, which would be inserted) and the command that’s invoked gets an extra parameter named character that indicates which character triggered the binding. When you use bindings in this manner, it’s up to you to insert the character into the buffer if it’s supposed to go there.

Example:

{ "keys": ["<character>"], "command": "echo", }

You can’t; that particular sequence only works unmodified. If you want to capture every possible combination of ctrl+ some character, you need to create that many key bindings and simulate the extra parameter yourself.

Note however that <character> captures (or should) everything that is an inserted character; so it implicitly handles shift+<character> internally by giving you the shifted character. Keys like ctrl+k don’t type anything and thus are not capturable like this.

Generically speaking, no. However since plugins are just Python code it may be possible to use something like pynput to read input (sort of example in the SublimePiano repository, although that package does not currently actually do this; I think @kingkeith did a PoC on that, though I may be misremembering).

If you had something like that, then the world is your oyster to make the view read only, capture input, and basically replicate the entire core of the editor yourself,

on_query_context is for implementing your own keybinding context keys; they’re used to allow you to have multiple bindings on the same key and have one enabled at a time based on circumstance.

You can’t test for the circumstance “ctrl+c” was pressed (for example) because that is implicit in the fact that the key binding specific field already knows that. Commands generally do not and should not make assumptions about what key is invoking them, since they’re user customizable (and commands can be invoked from menus and the command palette, as well as programatically by plugins, in which case there could be no input at all).

No, other than what you already specified or the pynput item mentioned above.

Not that I’m aware of, no. It’s a known thing that some keys may not report as you expect given particular layouts.

0 Likes

#3

4. (Linux) Is there a way (e.g. hidden command-line flag) to make Sublime trigger shortcuts by symbol instead of by scancode ? For some reason Sublime ignores the symbol ( keyval in GTK) whenever a modifier is involved (if it’s not some basic US QWERTY ASCII), and instead uses the scancode ( hardware_keycode in GTK). This makes zero sense to me (on Linux), and is pretty annoying/confusing. It seems like a Win32-like attempt at “localizing” keys? It matches neither my language nor my keyboard. If I hold down the Control key and type “¿”, it’s because I want to trigger “ctrl+¿”, not whatever this would blindly correspond to on some historic IBM keyboard (Sublime reports “ctrl+q” in this case).)

This behavior is done to match GTK, as keybindings inherently don’t use the same localization as keyboard input. Take for instance Cyrillic: the keybindings must match that of a ANSI keyboard. This can be turned off using the undocumented "gtk_enable_key_translation" setting, though that does generally break most keybindings.

1 Like

#4

Yes, tho this seems like desired behavior, as shift is usually used to compose symbols? As a user I think of “T” and “÷” as those symbols, and not as shortcuts “shift+t” and “shift+7”. Luckily, binding to “t”, “T”, “7” and “÷” seems to work out of the box (it’s just when Ctrl or Alt is involved Sublime breaks this and unhelpfully “reverts” “÷” into “shift+7”).

That is clever, I hadn’t thought of that! I remember trying pynput once when I wanted to make a terminal version of modern Tetris (w/ adjustable DAS), but finding it basically worked like a system-wide keysniffer. So it does seem a bit of an intrusive solution, having to suppress & resend based on whether the Sublime view has focus or not, but it might actually work.

I’d never want to distribute a plugin like that tho…

I understand and was afraid of that. I have looked at some other plugins doing modal modes (or generally any VI-style mappings), and they basically seem to list hundreds or thousands of shortcuts going to the same command that then does handling on the Python side, which does make the static JSON approach to shortcuts seem a bit under-powered. (I figured early on I had to write code to output/rewrite sublime-keymap files as they’re very verbose and cumbersome to edit by hand.)

0 Likes

#5

!!! This is FANTASTIC news! That… wow. That makes me so happy. I was searching for so long for this, going through dozens of forum threads and issues on GitHub, just finding various people who had the same issue (e.g. inability to bind Ctrl+è, etc etc). You really should put this somewhere in big bold letters for any Linux users or technical people. I had long given up hope that this would be built-in.

I even found & built the sort of hack-workaround that someone made for ST3, https://github.com/Phaiax/gtkneofix – tho of course that only seemed to allow me to shuffle around the scancodes that Sublime sees, I was unable to “trick” Sublime into allowing me to bind “Ctrl+∑” etc… (By the way, I had to use the hidden/undocumented flag --multiinstance to have GTK actually load external modules; does it normally clear environment or something?) I was at my wit’s end, considering having my reverse engineer friend look at the GTK event handler to see if a binary patch would be viable…

Finally some range in shortcuts that comes close to the likes of other editors like Emacs, etc. (Where “Ctrl+&” and the like is just this, which in my mind is the saner approach.) Thank you!!

Must they? You might be able to convince me that they should, by default, but must? Indeed, take the Cyrillic keyboard. Historically shortcuts came from mnemonics, o for open, q for quit, and so forth? Of course all the mnemonics flies out the window once you move on to other languages (that is fine, we’re used to it, we didn’t establish IBM and Microsoft, and for that we must suffer). However, forcefully “untranslating” keys back to US QWERTY seems rather destructive, as now you also block users from actually implementing mnemonics in their language:

e.g. Ctrl+å for “åpne” (Norwegian for open), or indeed, “Ctrl+о” for Russian (that is Unicode symbol CYRILLIC SMALL LETTER O, not ASCII “o”!!), regardless of how those symbols are composed, mapping to God only knows on a US QWERTY keyboard. The composition might also be highly dependent on keymap, e.g. whether it’s a secondary language, in a different ISO level/group, etc. Punctuation also tend to have diverse composition, e.g. Shift+7 is “&” (US), “/” (Scandinavian), “=” (Hungarian), etc., but my point is that there’s no intuitive connection between the symbols “7” and “&” like there is between “t” and “T”, so it makes little sense to most people to think of “&” as Shift-7.

I was just thinking, by what logic would I explain to my parents or nephew (who share the trait that neither have probably ever used a US keyboard) why the menu item that says “Ctrl+]” activates when they press Ctrl-ø (or some other weird key, I can’t recall) or why attempting to bind the latter overwrites the former, etc etc. I grew up using a gloriously heavy IBM PC101 keyboard, so I realize what’s happening, but most didn’t and don’t.

(… Thank you for coming to my TED talk.)

Anyway, but seriously, thank you for the GTK setting thing.

0 Likes

#6

Must they? You might be able to convince me that they should , by default, but must ? Indeed, take the Cyrillic keyboard. Historically shortcuts came from mnemonics, o for open, q for quit, and so forth? Of course all the mnemonics flies out the window once you move on to other languages (that is fine, we’re used to it, we didn’t establish IBM and Microsoft, and for that we must suffer). However, forcefully “untranslating” keys back to US QWERTY seems rather destructive, as now you also block users from actually implementing mnemonics in their language:

If you want keybindings to work across languages, then yes they must. Before this was fixed ST was unusable if you didn’t have an ANSI(-like) layout, for Cyrillic keyboards this meant having to build and maintain a localized set of keyboard shortcuts. This isn’t done by any GUI toolkit, GTK, QT, Cocoa and Win32 all translate keys to ANSI to match keybindings.

1 Like

#7

Hmm, doesn’t Qt recommends the opposite? As far as I know they recommend using human-readable strings for shortcuts namely so they can be included in localization. (E.g. “Accelerator values such as Ctrl+Q or Alt+F need to be translated too. If you hardcode Qt::CTRL + Qt::Key_Q for “quit” in your application, translators won’t be able to override it.”) Tho they acknowledge this is most effective when the majority of users are expected to use the dominant layout for that language.

There’s also some discussion at https://doc.qt.io/qt-5/qkeysequence.html concerning this problem – but I don’t think they would ever recommend forcing US/QWERTY (which would be odd given their non-US origin).

I also believe I read in the GTK documentation about shortcuts/accelerators that the hardware_keycode is only there for use when there is no symbol (keyval) available, which would be contrary to how Sublime behaves when modifiers are present. (I could be wrong, it was when I was trying to figure out how to undo/work around the translation Sublime does, for which you gave the hidden option.)

That said, my main problem was the sort of destructive/irreversible way in which the symbol was totally disregarded if it wasn’t US. While I appreciate not having the resources to translate keys, there must be a better way than discarding any symbol that’s not a key on US/QWERTY; for example by allowing scancode->US/QWERTY to be used as a fallback if no binding for the symbol exists.

I don’t use any other program in my day to day that won’t accept Ctrl+å as a shortcut, for example (Emacs, Gnome Terminal, Atom, etc). Also shortcuts like Ctrl++ (Ctrl and plus-symbol; which would be Ctrl+AltGr+r if my keyboard is to be translated to US/QWERTY) and Ctrl+& (ditto Ctrl+AltGr+t) works fine for me in Atom and Emacs, but were frustratingly impossible in Sublime. Again, until this wonderful hidden option.

(Problems still remain, such as Ctrl+; being impossible to type when the layout has N.European-style ,; .: punctuation if the US/QWERTY key of “;” happens to be taken up by a regular ASCII letter, as Sublime insists Shift is a shortcut key here even when simply used to make the “;” symbol, so you get Ctrl+Shift+, instead. But still, that’s more small fry stuff, it’s miles more functional than it was.)

0 Likes