Make Escape key don't close the current window

This question doesn’t require you to know about Linux. It’s a general question on Anki Desktop.

The context

I’m using Anki on Linux. On Linux, I’ve customized my Caps Lock key so that it works

  • as Escape when Caps Lock is pressed on its own.
  • as Ctrl + {key} when other key is pressed at the same time.

Because of this, when sometimes pressing Caps Lock, my system detects Esc and, therefore, Anki windows are closed.

The question

How can I disable the functionality of the Esc key, so that it doesn’t close Anki windows (e.g. Add, Browse, Stats, etc.)?

In other words, is it possible to remap Esc so that it does nothing?

Additional context

  1. On my system, I can close windows by pressing Windows + Shift + c, that’s the reason why I don’t need Anki map a key for closing windows.
  2. This happens with the Add, Browse and Stats windows. The main window is not closed when pressing Esc.
3 Likes

I am too scared to use Anki’s add dialog for this reason; I often accidentally tap CapsLock or hit escape key due to muscle memory from vim, and if I do, all my effort editing a card is lost. I have a hacky unenjoyable workflow for adding cards like this:

  1. Open add dialog
  2. Enter something minimal like a title (just so that I can find it later)
  3. Add card
  4. Find card in browser
  5. Continue to edit the contents of my card

The add window won’t close with non-empty fields unless those fields have been marked as sticky.

Please add the ability to deactivate the escape key. I keep losing my place in the browser window. :+1:

Never mind, I managed to make Customize Keyboard Shortcuts do this by remapping "window_browser goto sidebar": "Esc", which is how it should work, in my opinion. Hope this helps somebody.

Glad you figured it out.

I used autohotkey to remap the Escape key to switch between the browse and the add window, so check it out if you wish to.

https://www.autohotkey.com/

Please… PLEASE change the ESC key from exiting out without warning so I don’t lose 45 minutes of work and hundreds of flashcards being made all at once… I’m begging you.

Which window are you talking about here, where Escape would do this kind of damage?

Generally I also agree that Esc might not be the best key to close a window. I’ve noticed, that in the Browser, you can also use Ctrl-W for closing the window. Maybe we could use that instead as it’s harder to hit by accident, and it’s also used across other apps with the semantic of “closing”.

1 Like

When adding cards to a deck, so the Add window I suppose? And since I utilize image occlusion cards, often times 100+ cards occlude parts of a diagram within 1 window. Pressing ESC by accident wipes out all of that effort.

1 Like

Esc is a standard shortcut to close dialogs - even on macOS things like the Preferences screen of Terminal.app will close when it is pressed.

Anki’s Add screen asks you to confirm if the fields are non-empty, so you don’t lose data accidentally. It sounds like the image occlusion add-on needs to add a similar feature.

1 Like

I do think there’s some truth to that however.

Qt says about dialogs:

A dialog window is a top-level window mostly used for short-term tasks and brief communications with the user.

I would not consider the AddCards or the EditCurrent window to be a window for “short-term tasks”.

The Browser in fact is a QMainWindow, but we add the Esc shortcut outselves.

However when looking into it, I also noticed that it’s not trivial to change the behavior of the Escape key in QDialogs.

2 Likes

I think you could argue the case either way - sometimes users will quickly open the add or edit screens to jot something down, or make a minor edit. When using your persistent editor add-on, not so much. :slight_smile:

@hengiesel Since you have already looked into it and know the Anki source better than nearly everyone; I am trying to make the “close window” shortcut configurable (like some others I find it highly annoying to close the window because you press escape once too many). For the browser and add note dialogs themselves it is easy enough, however I can’t figure out from where the QDialog.close() is called when focus is in an AnkiWebView. At first I though that AnkiWebView.onEsc() would be called and that monkey patching would allow overriding the keypress (I also submitted a PR for storing a reference to the QShortcut that maps escape to onEsc) however it doesn’t seem to fire? Is there maybe some other mechanism in the svelte parts?

In the meantime it can be solved by installing an event filter that discards the Escape key press:

from aqt import mw, gui_hooks, QObject, QEvent, QShortcut, QKeySequence, QKeyCombination, qconnect, Qt

SHORTCUT = "Shortcut"

def close_sc(win, sc: str):
    win.keyPressEvent = lambda evt: super(win.__class__, win).keyPressEvent(evt)
    win.configure_window_close_shortcut = QShortcut(QKeySequence(sc), win)
    qconnect(win.configure_window_close_shortcut.activated, win.close)

class eat_escape(QObject):
    def eventFilter(self: object, obj: QObject, evt: QEvent):
        if evt.type() == QEvent.Type.ShortcutOverride and evt.keyCombination() == QKeyCombination(Qt.Key.Key_Escape):
            evt.accept()
            return True
        return False

CFG = mw.addonManager.getConfig(__name__)
gui_hooks.browser_menus_did_init.append(lambda win: close_sc(win, CFG[SHORTCUT]))
gui_hooks.add_cards_did_init.append(lambda win: close_sc(win, CFG[SHORTCUT]))
gui_hooks.editor_did_init.append(lambda ed: ed.parentWindow.installEventFilter(eat_escape(ed.parentWindow)))

Thanks

That’s because these are QDialogs, which have this behavior built-in, see here.

Yes, I have read as much but it doesn’t seem to match the de factor behavour of Anki as the following:

def close_sc(win, sc: str):
    win.keyPressEvent = lambda evt: super(win.__class__, win).keyPressEvent(evt)
    win.configure_window_close_shortcut = QShortcut(QKeySequence(sc), win)
    qconnect(win.configure_window_close_shortcut.activated, win.close)
CFG = mw.addonManager.getConfig(__name__)
gui_hooks.browser_menus_did_init.append(lambda win: close_sc(win, CFG[SHORTCUT]))
gui_hooks.add_cards_did_init.append(lambda win: close_sc(win, CFG[SHORTCUT])

works just fine as long as the input focus is not on a WebEngineView (for instance choose deck from the add note dialog but don’t focus the input field).

“Unstoppable escapes” only occur when input focus is inside a WebEngineView. The problem is solved for the moment with the event filter but I am curious either where close() is called from WebEngineView (which doesn’t seem to be onEsc()) or where it is discarded in the other widgets in the browser and add note dialog.