from pynput import keyboard import datetime # datetime functions import time # time functions # Init the keyboard listener def Init(inGSettings): pass def lang(inKLID = None): # https://stackoverflow.com/questions/42047253/how-to-detect-current-keyboard-language-in-python # My keyboard is set to the English - United States keyboard import ctypes # For debugging Windows error codes in the current thread user32 = ctypes.WinDLL('user32', use_last_error=True) # I switched my keyboard to the Russian keyboard curr_window = user32.GetForegroundWindow() thread_id = user32.GetWindowThreadProcessId(curr_window, 0) # Made up of 0xAAABBBB, AAA = HKL (handle object) & BBBB = language ID klid = inKLID if klid is None: klid = user32.GetKeyboardLayout(thread_id) # English = 67699721, Russian = 68748313 #print("LANG:", klid) # Extract language ID from KLID lid = klid & (2**16 - 1) # Convert language ID from decimal to hexadecimal lid_hex = hex(lid) #print("LANG:",lid) return klid # https://stackoverflow.com/questions/38224277/tounicodeex-always-returns-0-in-python from ctypes import * _ToUnicodeEx = WinDLL('user32').ToUnicodeEx _ToUnicodeEx.argtypes = [c_uint,c_uint,POINTER(c_char),POINTER(c_wchar),c_int,c_uint,c_void_p] _ToUnicodeEx.restype = c_int def ToUn(vk,sc,wfl,hkid): kst = create_string_buffer(256) b = create_unicode_buffer(5) windll.User32.GetKeyboardState(kst) y= _ToUnicodeEx(vk,sc,kst,b,5,wfl,hkid) VK_SHIFT = 0x10 VK_CAPITAL = 0x14 shifted = False # TODO UPPER CASE https://stackoverflow.com/questions/42037204/why-getkeystate-changed-the-behavior-of-tounicodeex if windll.User32.GetKeyboardState(VK_SHIFT) < 0: shifted = True if windll.User32.GetKeyboardState(VK_CAPITAL) < 0: shifted = True if shifted: return b.value.upper() return b.value #print(ToUn(65,0,0,windll.User32.GetKeyboardLayout(1))) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Technical defs import pdb SpecialKeyList = [] inList = [ # { # "EventDatetime": datetime.datetime.now(), # "EventTypeStr": "HOTKEY" # HOTKEY | CHARACTER | DELETE # "ValueStr": "" # HOTKEY: alt_l+shift or ctrl_l+c # } ] def on_press(key): lResult = { "EventDatetime": datetime.datetime.now(), "EventTypeStr": "HOTKEY", "ValueStr": ""} try: #print('alphanumeric key {0} pressed'.format( # key.char)) #print("__",dir(key)) import win32api MAPVK_VK_TO_CHAR = 0 #scancode = win32api.MapVirtualKey(key.vk, MAPVK_VK_TO_CHAR) from ctypes import windll #result = windll.User32.MapVirtualKeyExA(key.vk,MAPVK_VK_TO_CHAR,windll.User32.GetKeyboardLayout(1)) lDestKey = ToUn(key.vk, key._scan, 0, lang()) if str(key).isupper(): lDestKey = lDestKey.upper() #print("WINDOWS:",lDestKey) # Add result in list if len(SpecialKeyList) > 0 and not (len(SpecialKeyList)==1 and "shift" in SpecialKeyList): lDestKey = ToUn(key.vk, key._scan, 0, 67699721) # English = 67699721 lResult["EventTypeStr"] = "HOTKEY" lResult["ValueStr"] = '+'.join(SpecialKeyList)+f"+{lDestKey}" else: lResult["EventTypeStr"] = "CHARACTER" lResult["ValueStr"] = lDestKey print(lResult) inList.append(lResult) except AttributeError: #print('special key {0} pressed'.format( # key)) lKeyStr = str(key)[4:] # Check if not the delete or backspace if lKeyStr != "backspace" and lKeyStr != "delete": SpecialKeyList.append(lKeyStr) # Add result in list if len(SpecialKeyList) >= 2 or (lKeyStr != "shift" and lKeyStr != "ctrl_l" and lKeyStr != "ctrl_r" and lKeyStr != "alt_l" and lKeyStr != "alt_r" and lKeyStr != "shift_r"): lResult["EventTypeStr"] = "HOTKEY" lResult["ValueStr"] = '+'.join(SpecialKeyList) inList.append(lResult) print(lResult) else: lResult["EventTypeStr"] = "DELETE" lResult["ValueStr"] = ('+'.join(SpecialKeyList)+f"+{lKeyStr}" if len(SpecialKeyList)>0 else f"{lKeyStr}") inList.append(lResult) print(lResult) #return True def on_release(key): if len(SpecialKeyList)>0: try: SpecialKeyList.remove(str(key)[4:]) except Exception as e: pass if key == keyboard.Key.esc: # Stop listener return True # Collect events until released #while True: # with keyboard.Listener( # on_press=on_press, # on_release=on_release) as listener: # listener.join() # ...or, in a non-blocking fashion: listener = keyboard.Listener( on_press=on_press, on_release=on_release) listener.start() import pprint while True: time.sleep(5) #print(inList) #pprint.pprint(inList)