Ubuntu虚拟机下用Python向其他程序发送游戏手柄输入的实现方案
Hey there, let's break down how to send gamepad inputs with Python on your Ubuntu VM—this aligns with the DirectInput approach you mentioned for keyboard/mouse, but tailored specifically for controllers. Linux uses the evdev subsystem instead of DirectInput, so we'll leverage that with the evdev Python library.
Prerequisites
First, get the tools and permissions sorted:
- Install the
evdevlibrary:pip install evdev - Grant permission to access input devices: You'll need to add your user to the
inputgroup to avoid running scripts withsudoevery time:
Log out and back in for this change to take effect.sudo usermod -aG input $USER - VM Note: Make sure your physical gamepad (if using one) is passed through to the Ubuntu VM. For VirtualBox/VMware, go to the USB devices menu and select your controller to redirect it from the host to the guest.
Understand Gamepad Event Codes
Linux maps every gamepad button/axis to a specific event code. To find the codes for your controller (or reference standard ones), use the evtest tool:
- Install it:
sudo apt install evtest - Run it and select your gamepad from the list to see real-time event codes when you press buttons or move sticks. For example:
- Left stick X-axis =
ABS_X - X button (PS-style) =
BTN_SOUTH - D-pad left/right =
ABS_HAT0X
- Left stick X-axis =
Python Script to Send Gamepad Inputs
We'll create a virtual gamepad using UInput (part of evdev) and send events to it. This works because most games/programs will recognize the virtual device as a real controller.
Here's a sample script that simulates stick movement and button presses:
from evdev import UInput, ecodes as e import time # Define the capabilities of our virtual gamepad (matches standard controllers) gamepad_capabilities = { # Buttons: PS-style (X, Circle, Square, Triangle) + triggers, start/select e.EV_KEY: [ e.BTN_SOUTH, e.BTN_EAST, e.BTN_WEST, e.BTN_NORTH, e.BTN_START, e.BTN_SELECT, e.BTN_MODE, e.BTN_TL, e.BTN_TR, e.BTN_TL2, e.BTN_TR2, e.BTN_THUMBL, e.BTN_THUMBR ], # Axes: Left/right sticks, triggers, D-pad e.EV_ABS: [ (e.ABS_X, (0, 255, 0, 0)), # Left stick X (0=left, 255=right) (e.ABS_Y, (0, 255, 0, 0)), # Left stick Y (0=up, 255=down) (e.ABS_Z, (0, 255, 0, 0)), # Right stick X (e.ABS_RZ, (0, 255, 0, 0)), # Right stick Y (e.ABS_HAT0X, (-1, 1, 0, 0)), # D-pad X (-1=left, 1=right) (e.ABS_HAT0Y, (-1, 1, 0, 0)) # D-pad Y (-1=up, 1=down) ] } # Create the virtual gamepad device with UInput(gamepad_capabilities, name="Python Virtual Gamepad") as virtual_gamepad: print("Virtual gamepad created. Sending test inputs...") # Simulate left stick moving fully right virtual_gamepad.write(e.EV_ABS, e.ABS_X, 255) virtual_gamepad.syn() # Sync events to notify the system time.sleep(1) # Simulate pressing the X button (BTN_SOUTH) virtual_gamepad.write(e.EV_KEY, e.BTN_SOUTH, 1) # 1 = press virtual_gamepad.syn() time.sleep(0.5) # Release the X button virtual_gamepad.write(e.EV_KEY, e.BTN_SOUTH, 0) # 0 = release virtual_gamepad.syn() time.sleep(0.5) # Reset left stick to center position virtual_gamepad.write(e.EV_ABS, e.ABS_X, 127) virtual_gamepad.syn() time.sleep(1) print("Test completed. Virtual gamepad closed.")
How It Works
UInputcreates a virtual input device that the OS treats like a physical gamepad.write()sends individual events (axis movement, button presses/releases).syn()is critical: it tells the system that a full set of events is ready to be processed—without this, your inputs won't register.
Testing the Inputs
To verify the virtual gamepad is working:
- Run the script.
- Open a terminal and run:
Replacejstest /dev/input/jsXXwith the number of your virtual gamepad (you can find it withls /dev/input/js*). You'll see the inputs update as the script runs.
Customizing for Your Use Case
- Adjust the
gamepad_capabilitiesto match the buttons/axes your target program expects. - Modify the
write()calls to send specific inputs (e.g., hold a trigger, move the right stick) based on your needs.
内容的提问来源于stack exchange,提问作者Shaked Sibony

