Skip to content

Instantly share code, notes, and snippets.

@Aniruddha-Tapas
Created April 26, 2017 15:09
Script to emulate key-presses on Windows via Python.
# 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")
@PegasusClassSupplyShip
Copy link

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.

@chihiro888
Copy link

holy shit...this is god code

@PiepsC
Copy link

PiepsC commented Jun 12, 2019

Some elaboration would be useful here

@FimoX
Copy link

FimoX commented Mar 29, 2020

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 ?

@Rikka-404
Copy link

This is awesome. That in combination with win32gui = perfection

@freecodecampster
Copy link

@drdoof2019
Copy link

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?

@ali-epitech
Copy link

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 ?

It's normal. The inputs are sent one after an other. Although the delay shouldn't be that notisablebe for a few inputs, the more you have the bigger the delay betwen the first and last one. If you want to have no delay the only way is using multi threading. But the code will need to be modified.

@ali-epitech
Copy link

ali-epitech commented Feb 7, 2025

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?

Your problem could come from the code using virtual keys not scan keys. This is an easy fix but the code needs to be tweaked. In the lower part of the code

ki=KEYBDINPUT(wVk=hexKeyCode))

change
wvk
to
wScan

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment