What to bind a global shortcut to?

Thanks to help here, I finished a simple (but useful!) add-on. The last step is to try and make the shortcut global.

Looking at the anki codebase, I basically want this: anki/main.py at c21e6e2b97c6df76aebe4d61890b055a8de1dd7e · ankitects/anki · GitHub

but I’m not quite sure how to get at the same object from where I’m calling.

Here’s what I have:

def create_shortcut():
  QShortcut(QKeySequence('u'), aqt.mw, next_deck)

aqt.gui_hooks.main_window_did_init.append(create_shortcut)

I think it’s just a matter of replacing aqt.mw with the right object, I’m just not sure what that object should be. I want this shortcut to work like ‘d’ or ‘s’ work, so if I’m on a deck screen I can still use it.

Thank you very much!

Edit: if it’s simpler, I’d also be fine with just making it so that this shortcut is also available in the current deck screen, eg the screen you see when you click a deck (or finish studying it). I don’t need it everywhere…that might make it simpler

That should work already. If you add a print statement to your next_deck function and run Anki with a console active, you should see output.

3 Likes

Wrote a reply here, but yeah, looking at this again now, I think the main issue really just is that u is already bound in some mw states. Switching to a different assignment should make the QShortcut solution work!

4 Likes

thank you for taking the time! the shortcut indeed works in the main deck view. it’s not working in the current deck review screen, though…sounds like I need to get a better debug setup :slight_smile: (I’ve been meaning to ask if there is a good way to trace everything going on in the background with anki as that would be very helpful for developing add-ons, perhaps deserves its own thread through) I’m going to paste the code just in case it’s a very easy solution…I will of course keep digging in

def next_deck():
  due_tree = aqt.mw.col.sched.deck_due_tree().children
  def has_reviews(x):
    return x.learn_count > 0 or x.new_count > 0 or x.review_count > 0
  has_due = sorted([(x.name, x.deck_id) for x in due_tree if has_reviews(x)])
  has_due = filter(lambda x: x[0] not in FORBIDDEN, has_due)
  to_select = next(has_due, None)
  if to_select is None:
    return
  aqt.mw.col.decks.select(to_select[1])
  aqt.mw.moveToState('review')

So I just confirmed (with a showInfo that I inserted at the beginning of this function) that if I am in the screen that comes up when you finish reviewing, that the shortcut does not fire.

So basically, from the main deck screen, I press u. It correctly takes me to the first deck with reviews. I review them all, I am taken to the “you’ve reviewed everything in this deck” screen. I press u again–nothing happens.

1 Like

ack, I was writing my response when you sent this, so I didn’t see it. Thank you for your very informative response on reddit, and this makes sense, I will try out different bindings.

1 Like

per @glutanimate’s post on reddit, I tried the binding “Ctrl+Alt+Shift+U” and what I posted did indeed work…odd. So I guess it is that there is a binding collision. Which is weird, because when I press “u” in the deck overview screen, nothing happens. It’d be very convenient if there were a way to spit out all of the shortcuts currently active on a view…

For avoiding conflicts with native Anki shortcuts I usually look at the source code. Otherwise, and especially when troubleshooting conflicts with other add-ons, I sometimes do a variation of this (run via the debug console):

from aqt import mw
from aqt.qt import QShortcut

sc = mw.findChildren(QShortcut)
print([i.key().toString() for i in sc])

Though this doesn’t reflect all bindings as add-ons or native code might intercept key presses through other means as well.

For what it’s worth, u is bound to unbury (and thus only really does something when there are cards to unbury, which is why it’s a bit easy to miss).

3 Likes