Активация кода путем нажатия клавиши мыши (Python)
код на питоне, пример: мне нужно чтобы, когда я нажимал в реальной жизни, на левую кнопку мыши - выводилось "Hello World", а при отпускании этой кнопки писалось "Goodbye world". Не могу решить прошу помогите!
Ответы (2 шт):
Автор решения: Amgarak
→ Ссылка
Решил вам немного помочь, пример довольно простой (немного избыточный наверное), устанавливаем Hook -> обрабатываем event от мышки -> через генератор обрабатываем строку -> посылаем нажатия клавиши через winAPI. Если сами не разберётесь, спрашивайте ?:
import ctypes
import time
import string
import win32con
import win32api
import win32gui
import atexit
from collections import namedtuple
import threading
import queue
class InputSimulator:
def __init__(self):
# Константы для ввода мыши
self.WHEEL_DELTA = 120
self.XBUTTON1 = 0x0001
self.XBUTTON2 = 0x0002
self.MOUSEEVENTF_ABSOLUTE = 0x8000
self.MOUSEEVENTF_HWHEEL = 0x01000
self.MOUSEEVENTF_MOVE = 0x0001
self.MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000
self.MOUSEEVENTF_LEFTDOWN = 0x0002
self.MOUSEEVENTF_LEFTUP = 0x0004
self.MOUSEEVENTF_RIGHTDOWN = 0x0008
self.MOUSEEVENTF_RIGHTUP = 0x0010
self.MOUSEEVENTF_MIDDLEDOWN = 0x0020
self.MOUSEEVENTF_MIDDLEUP = 0x0040
self.MOUSEEVENTF_VIRTUALDESK = 0x4000
self.MOUSEEVENTF_WHEEL = 0x0800
self.MOUSEEVENTF_XDOWN = 0x0080
self.MOUSEEVENTF_XUP = 0x0100
# Константы для ввода клавиатуры
self.KEYEVENTF_EXTENDEDKEY = 0x0001
self.KEYEVENTF_KEYUP = 0x0002
self.KEYEVENTF_SCANCODE = 0x0008
self.KEYEVENTF_UNICODE = 0x0004
# Константы для типов ввода
self.INPUT_MOUSE = 0
self.INPUT_KEYBOARD = 1
self.INPUT_HARDWARE = 2
# Коды клавиш
self.VK_LBUTTON = 0x01
self.VK_RBUTTON = 0x02
self.VK_CANCEL = 0x03
self.VK_MBUTTON = 0x04
self.VK_XBUTTON1 = 0x05
self.VK_XBUTTON2 = 0x06
self.VK_BACK = 0x08
self.VK_TAB = 0x09
self.VK_CLEAR = 0x0C
self.VK_RETURN = 0x0D
self.VK_SHIFT = 0x10
self.VK_CONTROL = 0x11
self.VK_MENU = 0x12
self.VK_PAUSE = 0x13
self.VK_CAPITAL = 0x14
self.VK_KANA = 0x15
self.VK_HANGUL = 0x15
self.VK_JUNJA = 0x17
self.VK_FINAL = 0x18
self.VK_HANJA = 0x19
self.VK_KANJI = 0x19
self.VK_ESCAPE = 0x1B
self.VK_CONVERT = 0x1C
self.VK_NONCONVERT = 0x1D
self.VK_ACCEPT = 0x1E
self.VK_MODECHANGE = 0x1F
self.VK_SPACE = 0x20
self.VK_PRIOR = 0x21
self.VK_NEXT = 0x22
self.VK_END = 0x23
self.VK_HOME = 0x24
self.VK_LEFT = 0x25
self.VK_UP = 0x26
self.VK_RIGHT = 0x27
self.VK_DOWN = 0x28
self.VK_SELECT = 0x29
self.VK_PRINT = 0x2A
self.VK_EXECUTE = 0x2B
self.VK_SNAPSHOT = 0x2C
self.VK_INSERT = 0x2D
self.VK_DELETE = 0x2E
self.VK_HELP = 0x2F
self.VK_LWIN = 0x5B
self.VK_RWIN = 0x5C
self.VK_APPS = 0x5D
self.VK_SLEEP = 0x5F
self.VK_NUMPAD0 = 0x60
self.VK_NUMPAD1 = 0x61
self.VK_NUMPAD2 = 0x62
self.VK_NUMPAD3 = 0x63
self.VK_NUMPAD4 = 0x64
self.VK_NUMPAD5 = 0x65
self.VK_NUMPAD6 = 0x66
self.VK_NUMPAD7 = 0x67
self.VK_NUMPAD8 = 0x68
self.VK_NUMPAD9 = 0x69
self.VK_MULTIPLY = 0x6A
self.VK_ADD = 0x6B
self.VK_SEPARATOR = 0x6C
self.VK_SUBTRACT = 0x6D
self.VK_DECIMAL = 0x6E
self.VK_DIVIDE = 0x6F
self.VK_F1 = 0x70
self.VK_F2 = 0x71
self.VK_F3 = 0x72
self.VK_F4 = 0x73
self.VK_F5 = 0x74
self.VK_F6 = 0x75
self.VK_F7 = 0x76
self.VK_F8 = 0x77
self.VK_F9 = 0x78
self.VK_F10 = 0x79
self.VK_F11 = 0x7A
self.VK_F12 = 0x7B
self.VK_F13 = 0x7C
self.VK_F14 = 0x7D
self.VK_F15 = 0x7E
self.VK_F16 = 0x7F
self.VK_F17 = 0x80
self.VK_F18 = 0x81
self.VK_F19 = 0x82
self.VK_F20 = 0x83
self.VK_F21 = 0x84
self.VK_F22 = 0x85
self.VK_F23 = 0x86
self.VK_F24 = 0x87
self.VK_NUMLOCK = 0x90
self.VK_SCROLL = 0x91
self.VK_LSHIFT = 0xA0
self.VK_RSHIFT = 0xA1
self.VK_LCONTROL = 0xA2
self.VK_RCONTROL = 0xA3
self.VK_LMENU = 0xA4
self.VK_RMENU = 0xA5
self.VK_BROWSER_BACK = 0xA6
self.VK_BROWSER_FORWARD = 0xA7
self.VK_BROWSER_REFRESH = 0xA8
self.VK_BROWSER_STOP = 0xA9
self.VK_BROWSER_SEARCH = 0xAA
self.VK_BROWSER_FAVORITES = 0xAB
self.VK_BROWSER_HOME = 0xAC
self.VK_VOLUME_MUTE = 0xAD
self.VK_VOLUME_DOWN = 0xAE
self.VK_VOLUME_UP = 0xAF
self.VK_MEDIA_NEXT_TRACK = 0xB0
self.VK_MEDIA_PREV_TRACK = 0xB1
self.VK_MEDIA_STOP = 0xB2
self.VK_MEDIA_PLAY_PAUSE = 0xB3
self.VK_LAUNCH_MAIL = 0xB4
self.VK_LAUNCH_MEDIA_SELECT = 0xB5
self.VK_LAUNCH_APP1 = 0xB6
self.VK_LAUNCH_APP2 = 0xB7
self.VK_OEM_1 = 0xBA
self.VK_OEM_PLUS = 0xBB
self.VK_OEM_COMMA = 0xBC
self.VK_OEM_MINUS = 0xBD
self.VK_OEM_PERIOD = 0xBE
self.VK_OEM_2 = 0xBF
self.VK_OEM_3 = 0xC0
self.VK_OEM_4 = 0xDB
self.VK_OEM_5 = 0xDC
self.VK_OEM_6 = 0xDD
self.VK_OEM_7 = 0xDE
self.VK_OEM_8 = 0xDF
self.VK_OEM_102 = 0xE2
self.VK_PROCESSKEY = 0xE5
self.VK_PACKET = 0xE7
self.VK_ATTN = 0xF6
self.VK_CRSEL = 0xF7
self.VK_EXSEL = 0xF8
self.VK_EREOF = 0xF9
self.VK_PLAY = 0xFA
self.VK_ZOOM = 0xFB
self.VK_PA1 = 0xFD
self.VK_OEM_CLEAR = 0xFE
self.KEYEVENTF_EXTENDEDKEY = 0x0001
self.KEYEVENTF_KEYUP = 0x0002
self.KEYEVENTF_SCANCODE = 0x0008
self.KEYEVENTF_UNICODE = 0x0004
self.KEY_0 = 0x30
self.KEY_1 = 0x31
self.KEY_2 = 0x32
self.KEY_3 = 0x33
self.KEY_4 = 0x34
self.KEY_5 = 0x35
self.KEY_6 = 0x36
self.KEY_7 = 0x37
self.KEY_8 = 0x38
self.KEY_9 = 0x39
self.KEY_A = 0x41
self.KEY_B = 0x42
self.KEY_C = 0x43
self.KEY_D = 0x44
self.KEY_E = 0x45
self.KEY_F = 0x46
self.KEY_G = 0x47
self.KEY_H = 0x48
self.KEY_I = 0x49
self.KEY_J = 0x4A
self.KEY_K = 0x4B
self.KEY_L = 0x4C
self.KEY_M = 0x4D
self.KEY_N = 0x4E
self.KEY_O = 0x4F
self.KEY_P = 0x50
self.KEY_Q = 0x51
self.KEY_R = 0x52
self.KEY_S = 0x53
self.KEY_T = 0x54
self.KEY_U = 0x55
self.KEY_V = 0x56
self.KEY_W = 0x57
self.KEY_X = 0x58
self.KEY_Y = 0x59
self.KEY_Z = 0x5A
# Объявление структур
class MOUSEINPUT(ctypes.Structure):
_fields_ = [
('dx', ctypes.c_long),
('dy', ctypes.c_long),
('mouseData', ctypes.c_ulong),
('dwFlags', ctypes.c_ulong),
('time', ctypes.c_ulong),
('dwExtraInfo', ctypes.POINTER(ctypes.c_ulong))
]
class KEYBDINPUT(ctypes.Structure):
_fields_ = [
('wVk', ctypes.c_ushort),
('wScan', ctypes.c_ushort),
('dwFlags', ctypes.c_ulong),
('time', ctypes.c_ulong),
('dwExtraInfo', ctypes.POINTER(ctypes.c_ulong))
]
class HARDWAREINPUT(ctypes.Structure):
_fields_ = [
('uMsg', ctypes.c_ulong),
('wParamL', ctypes.c_ushort),
('wParamH', ctypes.c_ushort)
]
class _INPUTunion(ctypes.Union):
_fields_ = [
('mi', MOUSEINPUT),
('ki', KEYBDINPUT),
('hi', HARDWAREINPUT)
]
class INPUT(ctypes.Structure):
_fields_ = [
('type', ctypes.c_ulong),
('union', _INPUTunion)
]
self.MOUSEINPUT = MOUSEINPUT
self.KEYBDINPUT = KEYBDINPUT
self.HARDWAREINPUT = HARDWAREINPUT
self._INPUTunion = _INPUTunion
self.INPUT = INPUT
def SendInput(self, *inputs):
nInputs = len(inputs)
LPINPUT = self.INPUT * nInputs
pInputs = LPINPUT(*inputs)
cbSize = ctypes.c_int(ctypes.sizeof(inputs[0]))
return ctypes.windll.user32.SendInput(nInputs, pInputs, cbSize)
def MouseInput(self, flags, x, y, data):
return self.MOUSEINPUT(x, y, data, flags, 0, None)
def KeybdInput(self, code, flags):
return self.KEYBDINPUT(code, code, flags, 0, None)
def HardwareInput(self, message, parameter):
return self.HARDWAREINPUT(message & 0xFFFFFFFF, parameter & 0xFFFF, parameter >> 16 & 0xFFFF)
def Mouse(self, flags, x=0, y=0, data=0):
return self.INPUT(self.INPUT_MOUSE, self._INPUTunion(mi=self.MouseInput(flags, x, y, data)))
def Keyboard(self, code, flags=0):
return self.INPUT(self.INPUT_KEYBOARD, self._INPUTunion(ki=self.KeybdInput(code, flags)))
def Hardware(self, message, parameter=0):
return self.INPUT(self.INPUT_HARDWARE, self._INPUTunion(hi=self.HardwareInput(message, parameter)))
class InputListener:
"""
https://gist.github.com/Amgarak/5df8477bad67dabbc491322e74ce1c2c
This class is designed for listening to keyboard and mouse events in a Windows environment.
It utilizes low-level hooks to capture events such as key presses,
key releases, mouse movements, and mouse button clicks.
The class provides functionalities to register event handlers and filters,
allowing custom processing of events.
It also supports the control of threads for concurrent event handling.
"""
def __init__(self):
self.flagRun=False
self.signal = queue.Queue()
self._key_down = set()
self.if_handlers = set()
self.handlers = set()
self.listener_queues = {}
self.listeners =[]
self.variable_key_down = {}
self.event_types = {
win32con.WM_KEYDOWN: 'key_down',
win32con.WM_KEYUP: 'key_up',
0x104: 'key_down',
0x105: 'key_up'}
self.mouse_types={
0x200: 'move',
0x20A: 'wheel',
0x20E: 'H_wheel',
0x204: 'key_down',
0x205: 'key_up',
0x201: 'key_down',
0x202: 'key_up',
0x207: 'key_down',
0x208: 'key_up',
0x20B: 'key_down',
0x20C: 'key_up'}
self.mouse_key={
0x200: 'move',
0x20A: 'wheel',
7864320: 'wheel_top',
4287102976: 'wheel_bot',
0x20E: 'H_wheel',
0x204: 'right',
0x205: 'right',
0x201: 'left',
0x202: 'left',
0x207: 'middle',
0x208: 'middle',
131072: 'X_Button_1',
65536: 'X_Button_2'}
self.DeviceEvent = namedtuple('DeviceEvent', ['inputDevice', 'event_type', 'key_code', 'x', 'y', 'scan_code', 'key_down'])
self.DeviceEvent.__new__.__defaults__ = (None, None, None, None, None, None, None)
self.default_key = "Value not defined"
def key_event(self, event):
while not self.signal.empty():
self.signal_handler(self.signal.get())
for listener_queue in self.listener_queues.values():
listener_queue.put(event)
def key_down(self, event_type, key_code):
key = str(key_code)
if key not in self._key_down and event_type == 'key_down':
self._key_down.add(key)
return True
elif key in self._key_down and event_type == 'key_up':
self._key_down.remove(key)
return True
def if_block(self, event):
for if_handler in self.if_handlers:
result = if_handler(event)
if result is not None and not result:
return False
return True
def keyboard_low_level_handler(self, nCode, wParam, lParam):
lParam = ctypes.cast(lParam, ctypes.POINTER(ctypes.c_ulong)).contents.value
rezult = self.key_down(self.event_types[wParam], lParam)
event = self.DeviceEvent('Keyboard', self.event_types[wParam], lParam, key_down=self._key_down)
if rezult: # !!! - Отсекаем повторяющийся ивент key_down
self.key_event(event)
if self.if_block(event):
return ctypes.windll.user32.CallNextHookEx(self.keyboard_hook_id, nCode, wParam, lParam)
else:
return -1
def mouse_low_level_handler(self, nCode, wParam, lParam):
point = ctypes.cast(lParam, ctypes.POINTER(ctypes.c_long * 2)).contents
x = point[0]
y = point[1]
castomParam = self.mouse_key.get(lParam[1], self.default_key) if lParam[1] is not None else self.mouse_key[wParam]
self.key_down(self.mouse_types[wParam], castomParam)
event = self.DeviceEvent('Mouse', self.mouse_types[wParam], castomParam, x, y, lParam[1], self._key_down)
self.key_event(event)
if self.if_block(event):
return ctypes.windll.user32.CallNextHookEx(self.mouse_hook_id, nCode, wParam, lParam)
else:
return -1
def listen(self):
CMPFUNC = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_void_p))
ctypes.windll.user32.SetWindowsHookExW.argtypes = (
ctypes.c_int,
CMPFUNC,
ctypes.c_void_p,
ctypes.c_uint
)
keyboard_pointer = CMPFUNC(self.keyboard_low_level_handler)
self.keyboard_hook_id = ctypes.windll.user32.SetWindowsHookExW(win32con.WH_KEYBOARD_LL, keyboard_pointer,
win32api.GetModuleHandle(None), 0)
mouse_pointer = CMPFUNC(self.mouse_low_level_handler)
self.mouse_hook_id = ctypes.windll.user32.SetWindowsHookExW(win32con.WH_MOUSE_LL, mouse_pointer,
win32api.GetModuleHandle(None), 0)
atexit.register(ctypes.windll.user32.UnhookWindowsHookEx, self.keyboard_hook_id)
atexit.register(ctypes.windll.user32.UnhookWindowsHookEx, self.mouse_hook_id)
win32gui.GetMessage(None, 0, 0)
print(f"Hooks завершил свою работу..")
def add_if_handler(self, func):
self.if_handlers.add(func)
def add_handler(self, func):
self.handlers.add(func)
def remove_if_handler(self, func):
self.if_handlers.discard(func)
def remove_handler(self, func):
self.handlers.discard(func)
self.variable_key_down.pop(func.__name__, None)
def create_listener_queues(self):
self.listener_queues = {func.__name__: queue.Queue() for func in self.handlers}
def create_listener(self):
self.listeners = [
threading.Thread(target=self.wrapper, args=(self.listener_queues[func.__name__], func), name=func.__name__)
for func in self.handlers
]
def start_listener(self):
for listener_thread in self.listeners:
listener_thread.daemon = True
listener_thread.start()
def wrapper(self, listener_queue, func):
self.variable_key_down[func.__name__] = set()
while True:
event = listener_queue.get()
if event is None:
break
self.variable_key_down[func.__name__].clear()
self.variable_key_down[func.__name__].update(event.key_down)
event = event._replace(key_down=self.variable_key_down.get(func.__name__, None))
func(event)
print(f"Демон {func.__name__} завершил свою работу..")
def start(self, use_daemon = False):
self.create_listener_queues()
self.create_listener()
self.start_listener()
self.flagRun=True
thread = threading.Thread(target=self.listen, name="Hooks")
thread.daemon = use_daemon
thread.start()
self.thread_id = thread.native_id
def stop(self):
user32 = ctypes.windll.user32
WM_QUIT = 0x0012
user32.PostThreadMessageW(self.thread_id, WM_QUIT, 0, 0)
ctypes.windll.user32.UnhookWindowsHookEx(self.keyboard_hook_id)
ctypes.windll.user32.UnhookWindowsHookEx(self.mouse_hook_id)
for listener_queue in self.listener_queues.values():
listener_queue.put(None)
self.listener_queues.clear()
self.listeners.clear()
self._key_down.clear()
self.variable_key_down.clear()
self.flagRun=False
def hot_removal_handler(self, func):
signal = {"hot_removal_handler": func}
self.signal.put(signal)
def hot_plugging_handler(self, func):
signal = {"hot_plugging_handler": func}
self.signal.put(signal)
def hot_removal_if_handler(self, func):
signal = {"hot_removal_if_handler": func}
self.signal.put(signal)
def hot_plugging_if_handler(self, func):
signal = {"hot_plugging_if_handler": func}
self.signal.put(signal)
def signal_handler(self, handler_dict):
match handler_dict:
case {"hot_removal_handler": func}:
self.handlers.discard(func)
stop_signal_queue = self.listener_queues.get(func.__name__)
stop_signal_queue.put(None)
self.variable_key_down.pop(func.__name__, None)
self.listener_queues.pop(func.__name__, None)
print(f"Handling hot removal for function {func.__name__}")
case {"hot_plugging_handler": func}:
self.handlers.add(func)
self.listener_queues.update({func.__name__: queue.Queue()})
listener_thread=threading.Thread(target=self.wrapper, args=(self.listener_queues[func.__name__], func), name=func.__name__)
self.listeners.append(listener_thread)
listener_thread.daemon = True
listener_thread.start()
print(f"Handling hot plugging for function {func.__name__}")
case {"hot_removal_if_handler": func}:
self.if_handlers.discard(func)
print(f"Handling conditional hot removal for function {func.__name__}")
case {"hot_plugging_if_handler": func}:
self.if_handlers.add(func)
print(f"Handling conditional hot plugging for function {func.__name__}")
case _:
print("Unknown case")
def get_if_handlers(self, objekt=None):
if objekt == "__name__":
return set(if_handler.__name__ for if_handler in self.if_handlers)
else:
return self.if_handlers
def get_handlers(self, objekt=None):
if objekt == "__name__":
return set(handler.__name__ for handler in self.handlers)
else:
return self.handlers
def get_status_hooks(self):
return self.flagRun
input_simulator = InputSimulator()
UPPER = frozenset('~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:"ZXCVBNM<>?')
LOWER = frozenset("`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./")
ORDER = string.ascii_letters + string.digits + ' \b\r\t'
ALTER = dict(zip('!@#$%^&*()', '1234567890'))
OTHER = {'`': input_simulator.VK_OEM_3,
'~': input_simulator.VK_OEM_3,
'-': input_simulator.VK_OEM_MINUS,
'_': input_simulator.VK_OEM_MINUS,
'=': input_simulator.VK_OEM_PLUS,
'+': input_simulator.VK_OEM_PLUS,
'[': input_simulator.VK_OEM_4,
'{': input_simulator.VK_OEM_4,
']': input_simulator.VK_OEM_6,
'}': input_simulator.VK_OEM_6,
'\\': input_simulator.VK_OEM_5,
'|': input_simulator.VK_OEM_5,
';': input_simulator.VK_OEM_1,
':': input_simulator.VK_OEM_1,
"'": input_simulator.VK_OEM_7,
'"': input_simulator.VK_OEM_7,
',': input_simulator.VK_OEM_COMMA,
'<': input_simulator.VK_OEM_COMMA,
'.': input_simulator.VK_OEM_PERIOD,
'>': input_simulator.VK_OEM_PERIOD,
'/': input_simulator.VK_OEM_2,
'?': input_simulator.VK_OEM_2}
def keyboard_stream(string):
mode = False
for character in string.replace('\r\n', '\r').replace('\n', '\r'):
if mode and character in LOWER or not mode and character in UPPER:
yield input_simulator.Keyboard(input_simulator.VK_SHIFT, mode and input_simulator.KEYEVENTF_KEYUP)
mode = not mode
character = ALTER.get(character, character)
if character in ORDER:
code = ord(character.upper())
elif character in OTHER:
code = OTHER[character]
else:
continue
yield input_simulator.Keyboard(code)
yield input_simulator.Keyboard(code, input_simulator.KEYEVENTF_KEYUP)
if mode:
yield input_simulator.Keyboard(input_simulator.VK_SHIFT, input_simulator.KEYEVENTF_KEYUP)
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'
if __name__ == '__main__':
if get_layout() == 'ru':
input_simulator.SendInput(input_simulator.Keyboard(input_simulator.VK_MENU))
input_simulator.SendInput(input_simulator.Keyboard(input_simulator.VK_SHIFT, input_simulator.KEYEVENTF_EXTENDEDKEY))
input_simulator.SendInput(input_simulator.Keyboard(input_simulator.VK_SHIFT, input_simulator.KEYEVENTF_KEYUP | input_simulator.KEYEVENTF_EXTENDEDKEY))
input_simulator.SendInput(input_simulator.Keyboard(input_simulator.VK_MENU, input_simulator.KEYEVENTF_KEYUP))
def left_mouse_down(event):
if event.key_code == "left" and event.event_type == 'key_down':
for event in keyboard_stream('Hello World'):
input_simulator.SendInput(event)
time.sleep(0.01)
def left_mouse_up(event):
if event.key_code == "left" and event.event_type == 'key_up':
for event in keyboard_stream('Goodbye world'):
input_simulator.SendInput(event)
time.sleep(0.01)
input_listener = InputListener()
input_listener.add_handler(left_mouse_down)
input_listener.add_handler(left_mouse_up)
input_listener.start()
Автор решения: ArseniyRybasov
→ Ссылка
Могу предложить способ только с использованием библиотеки Tkinter:
from tkinter import *
def printhello(event):
print("Hello World")
def printgoodbye(event):
print("Goodbye World")
if __name__ == '__main__':
window = Tk()
window.bind("<Button-1>", printhello)
window.bind("<Button-3>", printgoodbye)
window.mainloop()