It can be done using ctypes:

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

# msdn.microsoft.com/en-us/library/dd375731
VK_TAB  = 0x09
VK_MENU = 0x12

# 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))

def AltTab():
    """Press Alt+Tab and hold Alt key for 2 seconds
    in order to see the overlay.
    """
    PressKey(VK_MENU)   # Alt
    PressKey(VK_TAB)    # Tab
    ReleaseKey(VK_TAB)  # Tab~
    time.sleep(2)
    ReleaseKey(VK_MENU) # Alt~

if __name__ == "__main__":
    AltTab()

hexKeyCode is the virtual keyboard mapping as defined by the Windows API. The list of codes is available on MSDN: Virtual-Key Codes (Windows)

Answer from lucasg on Stack Overflow
🌐
PyPI
pypi.org › project › keyboard
keyboard · PyPI
Listen and send keyboard events. Works with Windows and Linux (requires sudo), with experimental OS X support (thanks @glitchassassin!). Pure Python, no C modules to be compiled.
      » pip install keyboard
    
Published   Mar 23, 2020
Version   0.13.5
🌐
The Python Code
thepythoncode.com › article › control-keyboard-python
Keyboard module: Controlling your Keyboard in Python - The Python Code
We will be using the keyboard module, let's install it: ... Alright, open up a Python interactive shell or a Jupyter notebook/lab and follow along. ... This module provides us with the function add_abbreviation() that enables us to register a hotkey that replaces one typed text with another. For instance, let's replace the text "@email" to the email address "test@example.com":
🌐
GeeksforGeeks
geeksforgeeks.org › keyboard-module-in-python
Keyboard module in Python - GeeksforGeeks
April 12, 2025 - This code demonstrates how to record and replay key presses using the keyboard module. ... Python Tutorial – Python is one of the most popular programming languages. It’s simple to use, packed with features and supported by a wide range of libraries and frameworks.
🌐
Stack Abuse
stackabuse.com › guide-to-pythons-keyboard-module
Guide to Python's keyboard Module
October 24, 2023 - >>> import keyboard >>> keyboard.write("Hello") >>> Hello · The Hello message appears on the screen, in the terminal, as if you've written it. You can automate a command very easily, and create a hotkey alias for it. Here's a (crude) example of exiting the Python REPL, writing a curl command ...
Top answer
1 of 12
150

It can be done using ctypes:

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

# msdn.microsoft.com/en-us/library/dd375731
VK_TAB  = 0x09
VK_MENU = 0x12

# 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))

def AltTab():
    """Press Alt+Tab and hold Alt key for 2 seconds
    in order to see the overlay.
    """
    PressKey(VK_MENU)   # Alt
    PressKey(VK_TAB)    # Tab
    ReleaseKey(VK_TAB)  # Tab~
    time.sleep(2)
    ReleaseKey(VK_MENU) # Alt~

if __name__ == "__main__":
    AltTab()

hexKeyCode is the virtual keyboard mapping as defined by the Windows API. The list of codes is available on MSDN: Virtual-Key Codes (Windows)

2 of 12
111

For both python3 and python2 you can use pyautogui (pip install pyautogui)

from pyautogui import press, typewrite, hotkey

press('a')
typewrite('quick brown fox')
hotkey('ctrl', 'w')

It's also crossplatform with Windows, OSX, and Ubuntu LTS.

🌐
GitHub
github.com › boppreh › keyboard
GitHub - boppreh/keyboard: Hook and simulate global keyboard events on Windows and Linux. · GitHub
February 13, 2026 - # Replay events python -m keyboard < events.txt
Starred by 4K users
Forked by 455 users
Languages   Python 99.7% | Makefile 0.3%
🌐
pytz
pythonhosted.org › pynput › keyboard.html
Handling the keyboard — pynput 1.1.2 documentation
class pynput.keyboard.KeyCode(vk=0, char=None, is_dead=False)[source]¶ ... Creates a key from a character. ... Creates a dead key. ... Creates a key from a virtual key code. ... Applies this dead key to another key and returns the result. Joining a dead key with space (' ') or itself yields ...
Find elsewhere
🌐
Read the Docs
pynput.readthedocs.io › en › latest › keyboard.html
Handling the keyboard — pynput 1.7.6 documentation
from pynput.keyboard import Key, Controller keyboard = Controller() # Press and release space keyboard.press(Key.space) keyboard.release(Key.space) # Type a lower case A; this will work even if no key on the # physical keyboard is labelled 'A' keyboard.press('a') keyboard.release('a') # Type ...
🌐
Nitratine
nitratine.net › blog › post › simulate-keypresses-in-python
Simulate Keypresses In Python - Nitratine
December 16, 2017 - keyboard.type('This is one line.\nAnd this is the next line.\n\tThis line has been tabbed in.') To put a random delay between each keypress, you can use time.sleep with a random number passed to it. Here is a small example function I made:
🌐
Real Python
realpython.com › python-keyboard-input
How to Read User Input From the Keyboard in Python – Real Python
February 20, 2024 - Taking user input is an essential skill that unlocks more dynamic Python coding and allows you to elevate simple scripts into personalized applications. Get Your Code: Click here to download the free sample code that shows you how to get user input from the keyboard with Python.
🌐
Javatpoint
javatpoint.com › keyboard-module-in-python
Keyboard Module in Python - Javatpoint
Keyboard Module in Python with python, tutorial, tkinter, button, overview, entry, checkbutton, canvas, frame, environment set-up, first python program, operators, etc.
🌐
GitHub
github.com › makerdiary › python-keyboard
GitHub - makerdiary/python-keyboard: A hand-wired USB & Bluetooth keyboard powered by Python and more · GitHub
Follow the guide - hand-wiring-a-keyboard.md to rapidly make a keyboard with 100 lines of Python code.
Starred by 500 users
Forked by 59 users
Languages   Python
🌐
Playwright
playwright.dev › keyboard
Keyboard | Playwright Python
Keyboard provides an api for managing a virtual keyboard. The high level api is keyboard.type(), which takes raw characters and generates proper keydown, keypress/input, and keyup events on your page.
🌐
TechGeekBuzz
techgeekbuzz.com › blog › keyboard-module-controlling-your-keyboard-in-python
Keyboard module: Controlling your Keyboard in Python
Let's say you want to create your own hotkey that performs a particular operation when a specific combination of keys is pressed. Hotkeys are also known as shortcut keys, for example, Ctrl+C is a hotkey for copy and Ctrl+V is the hotkey for paste. ...
🌐
GitHub
github.com › gauthsvenkat › pyKey
GitHub - gauthsvenkat/pyKey: A python library to simulate keyboard presses · GitHub
December 27, 2023 - This library makes use of SendInput function (on windows) and xdotool (on linux) to simulate keystrokes (as opposed to other python keyboard simulator libraries, which use virtual keyboard codes).
Starred by 56 users
Forked by 6 users
Languages   Python
🌐
GitHub
github.com › boppreh › keyboard › blob › master › keyboard › __init__.py
keyboard/keyboard/__init__.py at master · boppreh/keyboard
February 13, 2026 - Hook and simulate global keyboard events on Windows and Linux. - keyboard/keyboard/__init__.py at master · boppreh/keyboard
Author   boppreh
🌐
Oreate AI
oreateai.com › blog › using-the-python-keyboard-library › 14775cff500b82fb8644bc971b2d6f0a
Using the Python Keyboard Library - Oreate AI Blog
December 22, 2025 - For example: import keyboard def on_key_press(event): print(event.name, event.scan_code) kboard.on_press(on_key_press) Running this code will print out both name and scan code of any pressed key.
🌐
Python Course
python-course.eu › python-tutorial › input.php
15. Keyboard Input | Python Tutorial | python-course.eu
June 29, 2022 - There are hardly any programs without any input. Input can come in various ways, for example, from a database, another computer, mouse clicks and movements or from the internet. Yet, in most cases the input stems from the keyboard. For this purpose, Python provides the function input().