Created
April 26, 2017 15:09
-
-
Save Aniruddha-Tapas/1627257344780e5429b10bc92eb2f52a to your computer and use it in GitHub Desktop.
Script to emulate key-presses on Windows via Python.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# directkeys.py | |
# http://stackoverflow.com/questions/13564851/generate-keyboard-events | |
# msdn.microsoft.com/en-us/library/dd375731 | |
import ctypes | |
from ctypes import wintypes | |
import time | |
user32 = ctypes.WinDLL('user32', use_last_error=True) | |
INPUT_MOUSE = 0 | |
INPUT_KEYBOARD = 1 | |
INPUT_HARDWARE = 2 | |
KEYEVENTF_EXTENDEDKEY = 0x0001 | |
KEYEVENTF_KEYUP = 0x0002 | |
KEYEVENTF_UNICODE = 0x0004 | |
KEYEVENTF_SCANCODE = 0x0008 | |
MAPVK_VK_TO_VSC = 0 | |
# List of all codes for keys: | |
# # msdn.microsoft.com/en-us/library/dd375731 | |
UP = 0x26 | |
DOWN = 0x28 | |
A = 0x41 | |
# C struct definitions | |
wintypes.ULONG_PTR = wintypes.WPARAM | |
class MOUSEINPUT(ctypes.Structure): | |
_fields_ = (("dx", wintypes.LONG), | |
("dy", wintypes.LONG), | |
("mouseData", wintypes.DWORD), | |
("dwFlags", wintypes.DWORD), | |
("time", wintypes.DWORD), | |
("dwExtraInfo", wintypes.ULONG_PTR)) | |
class KEYBDINPUT(ctypes.Structure): | |
_fields_ = (("wVk", wintypes.WORD), | |
("wScan", wintypes.WORD), | |
("dwFlags", wintypes.DWORD), | |
("time", wintypes.DWORD), | |
("dwExtraInfo", wintypes.ULONG_PTR)) | |
def __init__(self, *args, **kwds): | |
super(KEYBDINPUT, self).__init__(*args, **kwds) | |
# some programs use the scan code even if KEYEVENTF_SCANCODE | |
# isn't set in dwFflags, so attempt to map the correct code. | |
if not self.dwFlags & KEYEVENTF_UNICODE: | |
self.wScan = user32.MapVirtualKeyExW(self.wVk, | |
MAPVK_VK_TO_VSC, 0) | |
class HARDWAREINPUT(ctypes.Structure): | |
_fields_ = (("uMsg", wintypes.DWORD), | |
("wParamL", wintypes.WORD), | |
("wParamH", wintypes.WORD)) | |
class INPUT(ctypes.Structure): | |
class _INPUT(ctypes.Union): | |
_fields_ = (("ki", KEYBDINPUT), | |
("mi", MOUSEINPUT), | |
("hi", HARDWAREINPUT)) | |
_anonymous_ = ("_input",) | |
_fields_ = (("type", wintypes.DWORD), | |
("_input", _INPUT)) | |
LPINPUT = ctypes.POINTER(INPUT) | |
def _check_count(result, func, args): | |
if result == 0: | |
raise ctypes.WinError(ctypes.get_last_error()) | |
return args | |
user32.SendInput.errcheck = _check_count | |
user32.SendInput.argtypes = (wintypes.UINT, # nInputs | |
LPINPUT, # pInputs | |
ctypes.c_int) # cbSize | |
# Functions | |
def PressKey(hexKeyCode): | |
x = INPUT(type=INPUT_KEYBOARD, | |
ki=KEYBDINPUT(wVk=hexKeyCode)) | |
user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x)) | |
def ReleaseKey(hexKeyCode): | |
x = INPUT(type=INPUT_KEYBOARD, | |
ki=KEYBDINPUT(wVk=hexKeyCode, | |
dwFlags=KEYEVENTF_KEYUP)) | |
user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x)) | |
if __name__ == "__main__": | |
PressKey(A) | |
time.sleep(0.5) | |
ReleaseKey(A) | |
print("Pressed") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I edited your code a bit for my needs.
I want create a simple keyboard macro with ctypes. When I press "spacebar", I need the keys "b" and "spacebar" be pressed (with a small delay between them). The thing is that when I run the code, it just presses continuously "f" and "space". I only need "b" and "space" to be pressed and only when I hit the spacebar.
import ctypes
from ctypes import wintypes
import time
import win32con
user32 = ctypes.WinDLL('user32', use_last_error=True)
INPUT_MOUSE = 0
INPUT_KEYBOARD = 1
INPUT_HARDWARE = 2
KEYEVENTF_EXTENDEDKEY = 0x0001
KEYEVENTF_KEYUP = 0x0002
KEYEVENTF_UNICODE = 0x0004
KEYEVENTF_SCANCODE = 0x0008
MAPVK_VK_TO_VSC = 0
List of all codes for keys:
# msdn.microsoft.com/en-us/library/dd375731
B = 0x46
SPACE = 0x20
C struct definitions
wintypes.ULONG_PTR = wintypes.WPARAM
class MOUSEINPUT(ctypes.Structure):
fields = (("dx", wintypes.LONG),
("dy", wintypes.LONG),
("mouseData", wintypes.DWORD),
("dwFlags", wintypes.DWORD),
("time", wintypes.DWORD),
("dwExtraInfo", wintypes.ULONG_PTR))
class KEYBDINPUT(ctypes.Structure):
fields = (("wVk", wintypes.WORD),
("wScan", wintypes.WORD),
("dwFlags", wintypes.DWORD),
("time", wintypes.DWORD),
("dwExtraInfo", wintypes.ULONG_PTR))
class HARDWAREINPUT(ctypes.Structure):
fields = (("uMsg", wintypes.DWORD),
("wParamL", wintypes.WORD),
("wParamH", wintypes.WORD))
class INPUT(ctypes.Structure):
class _INPUT(ctypes.Union):
fields = (("ki", KEYBDINPUT),
("mi", MOUSEINPUT),
("hi", HARDWAREINPUT))
anonymous = ("_input",)
fields = (("type", wintypes.DWORD),
("_input", _INPUT))
LPINPUT = ctypes.POINTER(INPUT)
def _check_count(result, func, args):
if result == 0:
raise ctypes.WinError(ctypes.get_last_error())
return args
user32.SendInput.errcheck = _check_count
user32.SendInput.argtypes = (wintypes.UINT, # nInputs
LPINPUT, # pInputs
ctypes.c_int) # cbSize
Functions
def PressKey(hexKeyCode):
x = INPUT(type=INPUT_KEYBOARD,
ki=KEYBDINPUT(wVk=hexKeyCode))
user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
def ReleaseKey(hexKeyCode):
x = INPUT(type=INPUT_KEYBOARD,
ki=KEYBDINPUT(wVk=hexKeyCode,
dwFlags=KEYEVENTF_KEYUP))
user32.SendInput(1, ctypes.byref(x), ctypes.sizeof(x))
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
Register hotkeys
ctypes.windll.user32.RegisterHotKey(None, 1, 0, win32con.VK_SPACE)
Macro when the hotkey is pressed
try:
msg = ctypes.wintypes.MSG()
while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
PressKey(0x46)
time.sleep(1)
ReleaseKey(0x46)
PressKey(0x20)
time.sleep(1)
ReleaseKey(0x20)
Cleanup
finally:
ctypes.windll.user32.UnregisterHotKey(None, 1)