Python keyboard.add_hotkey(): как правильно сохранить значения горячих клавиш?
В одном из приложений на библиотеке keyboard, пытаюсь реализовать установку и последующее сохранение горячей(-их) клавиш(-и), для того чтобы после перезапуска приложения, кнопки подгружались, устанавливались и их не надо было заново биндить.
Документация: ссылка на документацию по библиотеке keyboard
Храню кнопки в БД, использую SQLite
Алгоритм такой:
- Если в базе пусто, создаем значение
buttonи вызываем функцию для прослушивания клавиш. - С помощью вызванной функции биндим клавишу или сочетание клавиш
- Алгоритм определяет одна ли это клавиша, или несколько и добавляет в
keyboard.add_hotkey(), после чего сохраняет. - Если при входе в базе не пусто - достает значение и также устанавливает
keyboard.add_hotkey().
Проблема:
Все работает, но есть одно НО. Значение нажатой клавиши определяется текущей раскладкой. Если сохранить клавишу/сочетание клавиш на русском языке, то потом, когда я снова запущу приложение с включенной английской раскладкой, keyboard выдаст ошибку о том, что не знает, например, клавиши "Ч". Точно также при переходе с английской раскладки на русскую.
- Если сохранять кнопки через
keyboard.hook(), то из переданного события можно получить как название кнопки - "K"/"Л", так и ее код - 37. И если биндить уже код, тогда проблемы не возникает, ведь код кнопки общий для обеих раскладок. Но мне нужна возможность биндить 2 клавиши, аkeyboard.hook()сразу отправляетeventпри нажатии одной. - Я пробовал получать коды кнопок через
keyboard.key_to_scan_codes(), но в таком случае их нельзя забиндить через методkeyboard.add_hotkey(), так как он принимает значениеkeyлибо в виде строки:'ALT+F', либо в виде числа. И если я захочу записать комбинацию клавиш в видеint- я получу сумму этих чисел, то есть совсем другую ОДНУ клавишу.
Примеры:
keyboard.add_hotkey('ctrl+shift', callback) ⬅⬅⬅⬅⬅ True
keyboard.add_hotkey(29, callback) ⬅⬅⬅⬅⬅ True (29 - код кнопки CTRL)
keyboard.add_hotkey(16+17, callback) ⬅⬅⬅⬅⬅ True (16 - Q, 17 - W, но в результате получаем 33 - кнопка F)
keyboard.add_hotkey('16+17', callback) ⬅⬅⬅⬅⬅ False (16 - Q, 17 - W, но keyboard говорит что это неизвестные клавиши)
Код: (не уверен, что он нужен)
import keyboard, sqlite3
def callback():
print('Функция вызвана')
def bind_keys():
print('Нажмите клавишу / Сочетание двух клавиш')
key = keyboard.read_hotkey(suppress=False)
key = str(key).split('+')
if len(key) == 2:
print(f'Нажато две кнопки: {key[0].upper()}, {key[1].upper()}')
key = f'{key[0]}+{key[1]}'
elif len(key) == 1:
print(f'Нажата одна кнопка: {key[0].upper()}')
key = key[0]
keyboard.add_hotkey(key, callback, suppress = False)
sql.execute(f"SELECT button FROM test WHERE button = '{key}'")
if sql.fetchone() is None:
sql.execute(f"INSERT INTO test VALUES('{key}')")
db.commit()
print('Клавиши сохранены')
keyboard.wait()
db = sqlite3.connect('db.db')
sql = db.cursor()
sql.execute("CREATE TABLE IF NOT EXISTS test(button TEXT)")
db.commit()
sql.execute("SELECT * FROM test")
key = sql.fetchone()
if key != None:
keyboard.add_hotkey(key[0], callback, suppress = False)
keyboard.wait()
else:
bind_keys()
Ответы (2 шт):
Самое логичное - сохранить названия клавиш в словарь типа
keys = {
'w' : 'ц',
'a' : 'ф',
's' : 'ы',
'd' : 'в'
}
И затем, проверяя текущую раскладку, например так
import ctypes
def get_layout():
u = ctypes.windll.LoadLibrary("user32.dll")
pf = getattr(u, "GetKeyboardLayout")
if hex(pf(0)) == '0x4190419':
return 'ru'
if hex(pf(0)) == '0x4090409':
return 'en'
Устанавливать сочетания клавиш уже по значениям словаря:
keyboard.add_hotkey(f"{keys['ctrl']}+{keys['shift']}", callback)
В документации это не отражено, но в исходниках add_hotkey видно, что метод принимает список, то есть можно просто передать ему список сканкодов.
Любопытно то, что при передаче строки вида 'ALT+F' она всё равно превращается в сканкоды. Учитывать разные раскладки при создании горячих клавиш не нужно.