Which hook should i use to paste automatically my clip board over here?

Hello,

I’m verry new in coding add ons. I know a bit about python.
Which hook should i use to paste my clipboad into this front field ? and then into this back field ?

My final pupose is to be on any other program, select a sentence, make a shortcut and send it to my front field or my back field (depends on the shortcut i used).

Hope it’s clear. If someone can tell me how i could use the hook, wich are verry vague for me. I already read the manual to create add on
image

But it doesn’t tell well theire action. For example, which hook to use after to click on the button add a card ?

Thanks for your help.

Gilles

I don’t think Anki hooks will work for this purpose. Instead, here is a snippet that invokes the Add screen and pastes some text in the Front field:

import aqt

addcards = aqt.dialogs.open("AddCards", mw=aqt.mw)
addcards.editor.note["Front"] = "Hello"
addcards.editor.loadNoteKeepingFocus()

To hook global shortcuts that can be triggered from any program, you’ll probably need to use an external library. I recommend trying pyqtkeybind. I’ve used it in an external script that I wrote to help me quickly create cards from selected text. It doesn’t paste the text in the editor, instead, it uses the AnkiConnect add-on to create the cards, but you can check out the relevant pyqtkeybind part here: hoarder/main.py at 5ccbd3204c9e9a6fe55152b076d92737b6767585 · abdnh/hoarder · GitHub

2 Likes

hello abdo,

Thanks for your kind respons,

I’m not sure to understand what’s in aqt class. How could i get this ?
My purpose is to activate the hotkey board (and add my text on the front card) only when the create card window is open. Why should i open the dialogs aqt ? I tried your code and have an error.
image
for this code
image

I’m not sure what i have to do just to access to the textbox. Normaly i should have Hello on my front card, but i get nothing.

Thanks for your help,

Kind regards,

Gilles

aqt.dialogs.open("AddCards", mw=aqt.mw) opens the Add window or focuses it (if already open) and gives you a reference to it. If you only want to add cards when the window is already open instead, you can try this (not tested):

import aqt

(_, addcards) = aqt.dialogs._dialogs["AddCards"]
if addcards:
    addcards.editor.note["Front"] = "Hello"
    addcards.editor.loadNoteKeepingFocus()

Before running any code that accesses the mw.col object (the previous snippet results in that eventually), you will need to make sure it’s fully initialized. One way to do that is to use the collection_did_load hook:

from anki.collection import Collection
import aqt

def on_col_did_load(col: Collection) -> None:

    addcards = aqt.dialogs.open("AddCards", mw=aqt.mw)
    addcards.editor.note["Front"] = "Hello"
    addcards.editor.loadNoteKeepingFocus()

aqt.gui_hooks.collection_did_load.append(on_col_did_load)

If you can sure your add-on’s code so far, that will be helpful to get a clearer picture of what you’re trying to do.

2 Likes

Hello Abdo,

I’m still having some trouble, and i’am verry grateful for you help.
On the same way that the on_col_did_load method has to be append to the hook collection_did_load,
this part should also be linked to a hook from the adding card window
image
But… i don’t know which hook i should use, and the documentation is not so clear.
On github , it gives only name and args.

Could you help me ?
I should have something like this in my code
image
But instead, i have an error like this,
image
What i expected here, was to have hello on my front card, when i pressed on the button to open the add card.
And the last question, how the shortcut can be activated the time the window add card is open ? Is there also a special hook ? or is it the same hook than above here ? that’s the big deal.
thank you for lighting my way

This part is just a modified version of my very first snippet that only pastes the text if the AddCards screen is already open. It can also be used with collection_did_load.

In this case, the editor_did_load_note is more suitable as you have guessed. Just change the first line of the function to def addTextInFrontOnLoadAddCard(editor): and try it. The arguments expected by each hook are the ones in the args list. Your function should have a matching number of arguments.

You want to also have a shortcut that pastes content to the editor when the Add screen is open? Try this:

import aqt
from aqt.editor import Editor

def addTextInFrontOnLoadAddCard(editor: Editor) -> None:
    (_, addcards) = aqt.dialogs._dialogs["AddCards"]
    if addcards:
        addcards.editor.note["Front"] = "Hello"
        addcards.editor.loadNoteKeepingFocus()

def add_button(buttons: list[str], editor: Editor):
    buttons.append(
        editor.addButton(
            icon=None,
            cmd="myaddon",
            func=addTextInFrontOnLoadAddCard,
            label="test",
            # Your shortcut
            keys="Ctrl+S"
        )
    )

aqt.gui_hooks.editor_did_init_buttons.append(add_button)
aqt.gui_hooks.editor_did_load_note.append(addTextInFrontOnLoadAddCard)

This adds a button to the editor that can also be activated via the specified shortcut.
See editor.py for details about addButton.

2 Likes

Hello Abdo,

Thanks for your response. It’s working well, and i reach almost my purpose thanks to you.

I just don’t know how to put the focus on the field like this ? To make that my cursor could be on the field that i desire.


When i do this, the intellisens gives no more function to control the front card text which surprises me. How should i do ? I’d was thinking at something like
addcard.editor.note[“Front”].setfocus().

How could i get a function to set the focus on a specific field ?
Sorry to ask lot of questions, but the aqt library has still a lot of secrets for me.
I think if i have the ability to set the focus on the right field, i’ll be able to send automatically key stroke with pyautogui library and simulate an ctrl v. It will be more easy for me than using the clipboard mime data. (which is complicated to paste images).
Once i finish it, let me know if i can maybe publish it as add on to help the others from the anki community, and maybe can i contribute to one of your personnal project ?

Thanks for your help,

Have a nice weekend :wink:

Try something like this:

field_index = addcards.editor.note.keys().index("Front")
addcards.editor.web.eval(f"focusField({field_index})")

Of course.

That will be appreciated!

1 Like

Hello abdo,

If you can eventually just help me to finish this, it would be verry nice,

I can’t adapt this code of pyqtkeybind lib, maybe you know why it’s not working ?
So my purpose is to call a function addTextInFrontOnClickButton() with a shortcut, and execute it.

this is the tricky part at the end of my code:

window = QtWidgets.QMainWindow()

keybinder.init()
keybinder.register_hotkey(window.winId(), 'ctrl+l', addTextInFrontOnClickButton)

win_event_filter = WinEventFilter(keybinder)
event_dispatcher = QAbstractEventDispatcher.instance()
event_dispatcher.installNativeEventFilter(win_event_filter)

My total code is just below :

import sys
import time



# appending a path
sys.path.append("C:/Users/Admin/AppData/Roaming/Anki2/addons21/BtnCopyPaste")

import keyboard
import aqt
from aqt.editor import Editor
from ahk import AHK, Hotkey
from pyqtkeybind import keybinder
from PyQt5.QtWidgets import *
import DemoShortcut
VK_PACKET = False
from PyQt5.QtCore import QAbstractNativeEventFilter, QAbstractEventDispatcher
from PyQt5 import QtWidgets



class WinEventFilter(QAbstractNativeEventFilter):
    def __init__(self, keybinder):
        self.keybinder = keybinder
        super().__init__()

    def nativeEventFilter(self, eventType, message):
        ret = self.keybinder.handler(eventType, message)
        return ret, 0



def addTextInFrontOnClickButton(editor: Editor) -> None:
    # action du bouton - pose le focus sur le logiciel word/ envoie les commandes ctrl+c / retourne dans anki sur le focus
    # correspondant/ envoie les commandes ctrl+v avec pygui / retourne sur word.
    (_, addcards) = aqt.dialogs._dialogs["AddCards"]
    if addcards:
        keyboard.send('ctrl+c')
        field_index = addcards.editor.note.keys().index("Front")
        addcards.editor.web.eval(f"focusField({field_index})")
        keyboard.send('ctrl+v')


def addTextInBackOnClickButton(editor: Editor) -> None:
    (_, addcards) = aqt.dialogs._dialogs["AddCards"]
    if addcards:
        keyboard.send('ctrl+c')
        field_index = addcards.editor.note.keys().index("Back")
        addcards.editor.web.eval(f"focusField({field_index})")
        keyboard.send('ctrl+v')


def add_buttonInFront(buttons: list[str], editor: Editor):
    buttons.append(
        editor.addButton(
            icon=None,
            cmd="myaddon",
            func=addTextInFrontOnClickButton,
            label="FRT",
            # Your shortcut
            keys="Ctrl+S"

        )
    )


def add_buttonInBack(buttons: list[str], editor: Editor):
    buttons.append(
        editor.addButton(
            icon=None,
            cmd="myaddonn",
            func=addTextInBackOnClickButton,
            label="BCK",
            # Your shortcut
            keys="Ctrl+S"

        )
    )


aqt.gui_hooks.editor_did_init_buttons.append(add_buttonInBack)
aqt.gui_hooks.editor_did_init_buttons.append(add_buttonInFront)

window = QtWidgets.QMainWindow()

keybinder.init()
keybinder.register_hotkey(window.winId(), 'ctrl+l', addTextInFrontOnClickButton)

win_event_filter = WinEventFilter(keybinder)
event_dispatcher = QAbstractEventDispatcher.instance()
event_dispatcher.installNativeEventFilter(win_event_filter)


And i try to adapt it from the example from the sample of the library that you suggest to me.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Sample PyQt5 app to demonstrate keybinder capabilities."""

import sys

from PyQt5 import QtWidgets
from PyQt5.QtCore import QAbstractNativeEventFilter, QAbstractEventDispatcher

from pyqtkeybind import keybinder


class WinEventFilter(QAbstractNativeEventFilter):
    def __init__(self, keybinder):
        self.keybinder = keybinder
        super().__init__()

    def nativeEventFilter(self, eventType, message):
        ret = self.keybinder.handler(eventType, message)
        return ret, 0


def main():
    app = QtWidgets.QApplication(sys.argv)
    window = QtWidgets.QMainWindow()

    print("Sample app for pyqtkeybind:")
    print("\tPress Ctrl+Shift+A or Print Screen any where to trigger a callback.")
    print("\tCtrl+Shift+F unregisters and re-registers previous callback.")
    print("\tCtrl+Shift+E exits the app.")

    # Setup a global keyboard shortcut to print "Hello World" on pressing
    # the shortcut
    keybinder.init()
    unregistered = False

    def callback():
        print("hello world")
    def exit_app():
        window.close()
    def unregister():
        keybinder.unregister_hotkey(window.winId(), "Shift+Ctrl+A")
        print("unregister and register previous binding")
        keybinder.register_hotkey(window.winId(), "Shift+Ctrl+A", callback)

    keybinder.register_hotkey(window.winId(), "Shift+Ctrl+A", callback)
    keybinder.register_hotkey(window.winId(), "Print Screen", callback)
    keybinder.register_hotkey(window.winId(), "Shift+Ctrl+E", exit_app)
    keybinder.register_hotkey(window.winId(), "Shift+Ctrl+F", unregister)

    # Install a native event filter to receive events from the OS
    win_event_filter = WinEventFilter(keybinder)
    event_dispatcher = QAbstractEventDispatcher.instance()
    event_dispatcher.installNativeEventFilter(win_event_filter)

    app.exec_()
    keybinder.unregister_hotkey(window.winId(), "Shift+Ctrl+A")
    keybinder.unregister_hotkey(window.winId(), "Shift+Ctrl+F" )
    keybinder.unregister_hotkey(window.winId(), "Shift+Ctrl+E")
    keybinder.unregister_hotkey(window.winId(), "Print Screen")


if __name__ == '__main__':
    main()

My problem is that i don’t know the anki architecture, and i’m not sure on how to proceed when i have to call the addwindow card.

Thanks for your help,