1. 程式人生 > >python 在windows下監聽鍵盤按鍵

python 在windows下監聽鍵盤按鍵

else name setw 程序 是我 user api put use

python 在windows下監聽鍵盤按鍵

使用到的庫

  • ctypes(通過ctypes來調用Win32API, 主要就是調用鉤子函數)

使用的Win32API

  • SetWindowsHookEx(), 將用戶定義的鉤子函數添加到鉤子鏈中, 也就是我們的註冊鉤子函數
  • UnhookWindowsHookEx(), 卸載鉤子函數
  • CallNextHookEx()在我們的鉤子函數中必須調用, 這樣才能讓程序的傳遞消息

在沒有鉤子函數的情況下windows程序運行機制

  • 鍵盤輸入 --> 系統消息隊列 --> 對應應用程序的消息隊列 --> 將消息發送到對應的窗口中

在有了鉤子函數的情況下windows程序運行機制

  • 鍵盤輸入 --> 系統消息隊列 --> 對應應用程序消息隊列 --> 將消息發送到鉤子鏈中 --> 消息一一調用完畢所有的鉤子函數(需要調用CallNextHookEx函數才能將消息傳遞下去) --> 將消息發送到對應的窗口中

示例程序

  • 註意:
    • 在程序中, 我們通過CFUNCTYPE返回一個類對象, 通過該類對象可以實例化出我們需要的c類型的函數, 但是如果不將他放在全局的話則會失去效果, 因為在C語言中函數是全局的
# -*- coding: utf-8 -*-
import os
import sys
from ctypes import *
from ctypes.wintypes import *


"""
define constants
"""
WH_KEYBOARD = 13
WM_KEYDOWN = 0x0100
CTRL_CODE = 162


class JHKeyLogger(object):

    def __init__(self, user32, kernel32):
        """
        Description:
            Init the keylogger object, the property ‘hook_‘ is the handle to control our hook function
        
        Args:
            @(dll)user32: just put windll.user32 here
            @(dll)kernel32: just put windll.kernel32 here

        Returns:
            None
        """
        self.user32_ = user32
        self.kernel32_ = kernel32
        self.hook_ = None
        
    def install_hookproc(self, hookproc):
        """
        Description:
            install hookproc function into message chain

        Args:
            @(c type function)hookproc: hookproc is the hook function to call

        Returns:
            @(bool):
                if SetWindowHookExA() function works successfully, return True
                else return False
        """
        self.hook_ = self.user32_.SetWindowsHookExA(
                                      WH_KEYBOARD,
                                      hookproc,
                                      self.kernel32_.GetModuleHandleW(None),
                                      0)
        if not self.hook_:
            return False
        return True

    def uninstall_hookproc(self):
        """
        Description:
            uninstall the hookproc function which means pick the hookproc pointer off the message chain
        Args:
            None
        Returns:
            None
        """
        if not self.hook_:
            return
        self.user32_.UnhookWindowsHookEx(self.hook_)
        self.hook_ = None

    def start(self):
        """
        Description:
            start logging, just get the message, the current thread will blocked by the GetMessageA() function
        
        Args:
            None
        Returns:
            None
        """
        msg = MSG()
        self.user32_.GetMessageA(msg, 0, 0, 0)

    def stop(self):
        self.uninstall_hookproc()


def hookproc(nCode, wParam, lParam):
    """
    Description:
        An user-defined hook function

    Attention:
        here we use the global variable named ‘g_keylogger‘
    """
    if wParam != WM_KEYDOWN:
        return g_keylogger.user32_.CallNextHookEx(g_keylogger.hook_, nCode, wParam, lParam)

    pressed_key = chr(lParam[0])
    print pressed_key,
    # hit ctrl key to stop logging
    if CTRL_CODE == lParam[0]:
        g_keylogger.stop()
        sys.exit(-1)
    return g_keylogger.user32_.CallNextHookEx(g_keylogger.hook_, nCode, wParam, lParam)


# Attention: pointer must be defined as a global variable
cfunctype = CFUNCTYPE(c_int, c_int, c_int, POINTER(c_void_p))
pointer = cfunctype(hookproc)

g_keylogger = JHKeyLogger(windll.user32, windll.kernel32)

def main():
    if g_keylogger.install_hookproc(pointer):
        print ‘install keylogger successfully!‘
    g_keylogger.start()
    print ‘hit ctrl to stop‘
    
if __name__ == ‘__main__‘:
    main()

python 在windows下監聽鍵盤按鍵