-
-
Save Aniruddha-Tapas/1627257344780e5429b10bc92eb2f52a to your computer and use it in GitHub Desktop.
# 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") |
holy shit...this is god code
Some elaboration would be useful here
Thank you for your script that I'm using in a game.
But I have one big issue, I have a latency/delay of 4 frames, around 50ms.
Is there a way to fix it ?
This is awesome. That in combination with win32gui = perfection
Thanks! Used it in my project https://github.com/freecodecampster/DirectInputServer.
hey, my pc language is turkish and we got "ı" word in our language. My problem is even though I send ascii codes of "i" or "I" for example 0x49
it types "ı". how can i solve that?
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))
def __init__(self, *args, **kwds):
super(KEYBDINPUT, self).__init__(*args, **kwds)
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))
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)
sir, this code is just amazing.
Did you code this? because this needs more recognition.
I would love to see some detailed explanation of how the code works since I find it quite confusing since you are dealing with low level problem which is a rare case in python.