Welcome to Game Handle repository
Python Driver Tutorial
Python Test Handle
I. Experimental Environment
Jupyter Lab
Python Environment
Ii. Test Method
Note
This tutorial uses a 2.4G test environment as an example!
The controller supports rapid-fire functionality. If you experience jitter when pressing a button, please disable the rapid-fire function for the corresponding button according to the instruction manual.
Before testing, ensure the controller receiver is connected to the motherboard or PC, and switch the controller to DINPUT. ( Press and hold FN+SELECT for 3 seconds ) A solid blue indicator light indicates successful pairing of the controller.
Environment Setup
The provided virtual machine has already set up the test environment; no further setup is required. Please skip directly to starting Jupyter Lab.
sudo apt updateInstall required dependencies
xxxxxxxxxxsudo apt install -y python3-pip python3-dev python3-setuptools libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev libportmidi-dev libswscale-dev libavformat-dev libavcodec-dev zlib1g-dev gcc build-essential libffi-dev jupyter-corexxxxxxxxxxpip install cffi pygame jupyter notebook jupyterlab ipywidgetsStart Jupyter Lab
Open the terminal and enter Jupyter lab.
xxxxxxxxxxjupyter lab
It can be opened by using the IP address or port number
Before testing, make sure the handle receiver is connected to the motherboard or PC and successfully paired. Enter the following command to check if the handle device can be detected.

As shown in the image above, this indicates that the gamepad receiver has been successfully recognized. Note that if a mouse or keyboard is connected, it may also be recognized as a js device, but the program only recognizes js0. Therefore, if multiple js devices are connected, connect the gamepad receiver first, then connect the other devices. When the gamepad is connected, the indicator light will be solid blue; flashing indicates a disconnection.
ipywidgets Test

pygame Test
After pressing a key, it will print which key was pressed
ximport pygameimport timeimport platform
# Initialize Pygamepygame.init()pygame.joystick.init()
# Get number of connected gamepadsjoystick_count = pygame.joystick.get_count()print(f"Detected {joystick_count} gamepad(s)")
if joystick_count == 0: print("No gamepads detected. Please connect a gamepad and try again.") exit()
# Initialize all detected gamepadsjoysticks = []for i in range(joystick_count): joystick = pygame.joystick.Joystick(i) joystick.init() joysticks.append(joystick) print(f"\nGamepad {i}: {joystick.get_name()}") print(f" Number of axes: {joystick.get_numaxes()}") print(f" Number of D-pads (hats): {joystick.get_numhats()}")
# Detect operating system for platform-specific mappingssystem = platform.system()print(f"Platform: {system}")
if system == "Windows": # Button/axis mappings for Windows button_names = { 0: "A", 1: "B", 3: "X", 4: "Y", 6: "LB", 7: "RB", 8: "LT", 9: "RT", 10: "SELECT", 11: "START", 12: "Left Stick Click", 13: "Right Stick Click" } axis_names = [ "Left Stick X", "", # Unused axis 1 "Left Stick Y", "Right Stick X", "", "Right Stick Y" # Unused axis 4 ]elif system == "Linux": # Button/axis mappings for Linux button_names = { 0: "A", 1: "B", 3: "X", 4: "Y", 6: "LB", 7: "RB", 8: "LT", 9: "RT", 10: "SELECT", 11: "START", 12: "Left Stick Click", 13: "Right Stick Click" } axis_names = [ "Left Stick X", "Left Stick Y", "Right Stick X", "Right Stick Y", "RT", "LT" ]else: # Default mappings for other systems (compatibility fallback) button_names = {} axis_names = []
# Only print axis data with absolute value above this threshold (dead zone)AXIS_THRESHOLD = 0.1
try: while True: # Process all Pygame events for event in pygame.event.get(): # Button press event if event.type == pygame.JOYBUTTONDOWN: btn_name = button_names.get(event.button, f"Unknown Button({event.button})") print(f"Gamepad {event.joy}: Button {btn_name} pressed") # Button release event elif event.type == pygame.JOYBUTTONUP: btn_name = button_names.get(event.button, f"Unknown Button({event.button})") print(f"Gamepad {event.joy}: Button {btn_name} released") # Joystick axis movement event elif event.type == pygame.JOYAXISMOTION: if abs(event.value) > AXIS_THRESHOLD: axis_name = axis_names[event.axis] if event.axis < len(axis_names) else f"Axis {event.axis}" # Suppress unused axes (1/4) only on Windows; show all axes on Linux if system == "Windows": if event.axis != 1 and event.axis != 4: print(f"Gamepad {event.joy}: {axis_name} = {event.value:.2f}") else: # Linux systems print(f"Gamepad {event.joy}: {axis_name} = {event.value:.2f}") # D-pad (hat) movement event elif event.type == pygame.JOYHATMOTION: if event.value != (0, 0): # Only show non-neutral positions hat_dir = { (1, 0): "Right", (-1, 0): "Left", (0, 1): "Up", (0, -1): "Down", }.get(event.value, event.value) print(f"Gamepad {event.joy}: D-pad = {hat_dir}") time.sleep(0.01) # Reduce CPU usage
except KeyboardInterrupt: print("\n\nProgram terminated") pygame.quit()Iii. Gamepad Key Value Definition
【Buttons】Represent physical buttons
| Buttons Index | Gamepad Button |
|---|---|
| buttons[0] | A |
| buttons[1] | B |
| buttons[2] | - |
| buttons[3] | X |
| buttons[4] | Y |
| buttons[5] | - |
| buttons[6] | L1|LB |
| buttons[7] | R1|RB |
| buttons[8] | L2|LT |
| buttons[9] | R2|RT |
| buttons[10] | SELECT |
| buttons[11] | START |
| buttons[12] | Left Stick Press |
| buttons[13] | Right Stick Press |
【Axes】Represent joysticks and linear triggers
| Axes Index | Gamepad Control | Description |
|---|---|---|
| axes[0] | Left Joystick (Horizontal) | Positive = Left, Negative = Right |
| axes[1] | Left Joystick (Vertical) | Positive = Up, Negative = Down |
| axes[2] | Right Joystick (Horizontal) | Positive = Left, Negative = Right |
| axes[3] | Right Joystick (Vertical) | Positive = Up, Negative = Down |
| axes[4] | Linear Trigger R2|RT | Released: -1, Pressed: 1 |
| axes[5] | Linear Trigger L2|LT | Released: -1, Pressed: 1 |
| axes[6] | D-pad (Horizontal) | Positive = Left, Negative = Right |
| axes[7] | D-pad (Vertical) | Positive = Up, Negative = Down |