윈도우 환경에서 Python을 사용하여 키보드 후킹을 하는 방법 관련하여 좀더 쓰기 편하게 코드 정리를 하였다. 특수키를 확인하는 방법도 추가되었다.
소스
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | # -*- coding: utf-8 -*- #!/usr/bin/python import sys from ctypes import * from ctypes.wintypes import MSG from ctypes.wintypes import DWORD class KeyRogue: user32 = windll.user32 kernel32 = windll.kernel32 WH_KEYBOARD_LL = 13 WM_KEYDOWN = 0x0100 WM_SYSKEYDOWN = 0x0104 VK_CONTROL = 0x11 VK_MENU = 0x12 VK_SHIFT = 0x10 hooked = None hookProc = None pointer = None @staticmethod def installHookProc(hookProc): if KeyRogue.hooked is not None : print ( "already installed. uninstalling.." ) KeyRogue.uninstallHookProc() KeyRogue.hookProc = hookProc KeyRogue.pointer = KeyRogue.getFPTR(KeyRogue.hookProcInternal) KeyRogue.hooked = KeyRogue.user32.SetWindowsHookExA( KeyRogue.WH_KEYBOARD_LL, KeyRogue.pointer, KeyRogue.kernel32.GetModuleHandleW( None ), 0 ) if not KeyRogue.hooked: return False return True @staticmethod def uninstallHookProc(): if KeyRogue.hooked is None : return KeyRogue.user32.UnhookWindowsHookEx(KeyRogue.hooked) KeyRogue.hooked = None @staticmethod def bytes(integer): return divmod (integer, 0x10000 ) @staticmethod def getFPTR(fn): CMPFUNC = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p)) return CMPFUNC(fn) @staticmethod def startKeyLog(): msg = MSG() KeyRogue.user32.GetMessageA(byref(msg), 0 , 0 , 0 ) @staticmethod def getKeyCode(lParam): high, low = KeyRogue.bytes(lParam[ 0 ]) return low @staticmethod def getKeyInfo(lParam): keyCode = KeyRogue.getKeyCode(lParam) return (keyCode, chr (keyCode)) @staticmethod def checkModifier(lParam, vKey): if KeyRogue.user32.GetAsyncKeyState(vKey) & 0x8000 : return True return False @staticmethod def hookProcInternal(nCode, wParam, lParam): if wParam ! = KeyRogue.WM_KEYDOWN and wParam ! = KeyRogue.WM_SYSKEYDOWN: return KeyRogue.user32.CallNextHookEx(KeyRogue.hooked, nCode, wParam, lParam) if KeyRogue.hookProc: KeyRogue.hookProc(nCode, wParam, lParam) return KeyRogue.user32.CallNextHookEx(KeyRogue.hooked, nCode, wParam, lParam) @staticmethod def start(hookProc): if KeyRogue.installHookProc(hookProc): KeyRogue.startKeyLog() else : print ( "install failed" ) @staticmethod def stop(): KeyRogue.uninstallHookProc() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from KeyRogue import * def hookProc(nCode, wParam, lParam): key = KeyRogue.getKeyInfo(lParam) print ( "key code = %d" % key[ 0 ]) print ( "key char = %c" % key[ 1 ]) if KeyRogue.checkModifier(lParam, KeyRogue.VK_CONTROL): print ( "CTRL pressed" ) if (key[ 1 ] = = 'Q' ): print ( "exit key pressed, call stop()" ) KeyRogue.stop() sys.exit( - 1 ) if KeyRogue.checkModifier(lParam, KeyRogue.VK_MENU): print ( "ALT pressed" ) if KeyRogue.checkModifier(lParam, KeyRogue.VK_SHIFT): print ( "SHIFT pressed" ) KeyRogue.start(hookProc) |
- Hook 설치 성공시 .start() 함수는 리턴되지 않는다.(심지어 stop() 함수를 사용하여 언인스톨되었을 경우에도) 따라서 GUI가 있는 프로그램에 키보드 후킹 기능을 추가하려면 별도의 쓰레드에서 실행되도록 처리가 필요하다.
참고사항
<테스트 환경> - OS : Windows 10 - Python 버전 : 3.6.5(32/64bit), 3.7.5(32bit)
'1. 연구 모듈 > Python' 카테고리의 다른 글
[Python] wxPython에서 어플리케이션 아이콘 변경 방법 (1) | 2021.03.29 |
---|---|
[Python] 키보드 후킹 - 간편화 코드 시행 착오 (0) | 2020.12.23 |
[Python] 키보드 후킹 - 1. 예제 코드 (0) | 2020.12.21 |
[Python] .INI 파일에 설정 읽고 쓰기 - 2. 간편화 코드 (0) | 2020.12.18 |
[Python] .INI 파일에 설정 읽고 쓰기 - 1. 예제 코드 (0) | 2020.10.16 |