Sublime Forum

Block default keypess event programatically

#1

Hi, I am creating a plugin where I want to stop the keypress action. For example, I want to prevent the editor from writing “a” when the key “a” is pressed programatically. Can anyone help?

0 Likes

#2

The way you would do this would be to define a key binding in your package that is bound to the key you want to block (in these examples, the unmodified A key), along with a context that constrains when the key binding is actually active.

For example, you can create a key binding like this:

{
    "keys": ["a"],
    "command": "noop",
},

Now pressing A by itself will try to execute the noop command, which doesn’t exist; now it’s impossible to type a lowercase letter a (although upper case ‘A’ is still possible because that includes a Shift modifier; duplicate the binding with "A" in place of "a" to also block upper-case A).

On the whole this is not a good idea because being able to type is fairly important, so if you do something like this you need a way to still allow an 'a' to be typed. One way to do that would be to use a context in the key binding and create an on_query_context event handler, so that the binding is only active in specific situations where you want to block the key.

{
    "keys": ["a"],
    "command": "noop",
    "context": [
        { "key": "block_a_key", "operator": "equal", "operand": true },
    ],
},
import sublime
import sublime_plugin


class SampleEventListener(sublime_plugin.EventListener):
    def on_query_context(self, view, key, operator, operand, match_all):
        if key == "block_a_key":
            lhs = view.settings().get("block_a")
            rhs = bool(operand)
        else:
            return None

        if operator == sublime.OP_EQUAL:
            return lhs == rhs
        elif operator == sublime.OP_NOT_EQUAL:
            return lhs != rhs

        return None

In this example, the key binding is only active when the current view has a setting that specifically says to block the A key from being pressed; otherwise it operates as per normal. You can put whatever detection logic you need in the context code so that your binding is only active when you want it to be (i.e. when you want to block the key).

Another option would be to make your key binding unconditional as in the first example, but instead of invoking a command that doesn’t exist you invoke your own command that either does nothing or replicates the default logic.

{
    "keys": ["a"],
    "command": "example",
},
import sublime
import sublime_plugin


class ExampleCommand(sublime_plugin.TextCommand):
    def run(self, edit):
        if self.view.settings().get("block_a", False) == False:
            self.view.run_command("insert", {"characters": "a"})

In this case, pressing an unmodified A key will always execute the command example, which can determine if it should be inserting the character or doing nothing (or taking some other action instead, which is generally why you want to do something like this in the first place).

Generally speaking you probably want to use a context for something like this to stop the binding from being considered except where it should be. For example, if you are writing something for distribution through package control, your package will likely be rejected if it has bindings that override defaults without providing a context.

5 Likes

#3

Thank you! This really helped

0 Likes

#4

also potentially relevant:

3 Likes