Skip to content

Instantly share code, notes, and snippets.

@CypherpunkSamurai
Last active October 6, 2024 22:23
Show Gist options
  • Save CypherpunkSamurai/1488b4b896e122065a78963c5b9d04f5 to your computer and use it in GitHub Desktop.
Save CypherpunkSamurai/1488b4b896e122065a78963c5b9d04f5 to your computer and use it in GitHub Desktop.
My Own ViGEm Client using CTypes in Python
"""
Loads the ViGEmClient DLL, connects to the ViGEmBus, creates an X360 target, and simulates input by pressing the B button.
# Links
collect release: https://github.com/ViGEm/ViGEmBus/releases
collect builds: https://buildbot.nefarius.at/builds/ViGEmClient/master/
This code demonstrates how to use the ViGEmClient library to interact with the ViGEmBus, which allows virtual game controllers to be created and used in Windows applications.
The code performs the following steps:
1. Loads the ViGEmClient DLL
2. Allocates a client object
3. Connects the client to the ViGEmBus
4. Allocates an X360 target
5. Adds the X360 target to the client
6. Simulates input by pressing the B button
7. Waits for 10 seconds
8. Removes the X360 target from the client
9. Frees the X360 target
10. Disconnects the client from the ViGEmBus
11. Frees the client
# reference: https://github.com/fsadannn/pyvjoystick/blob/8265486ca871b5baef4e91834870f2dd317498e9/pyvjoystick/vigem/_sdk.py#L10
# client testing: https://takeover-studios.itch.io/tos-gamepad-tester
This code can be used as a starting point for building applications that require virtual game controller functionality, such as game automation, input remapping, or controller emulation.
"""
import ctypes
import time
# Load the ViGEmClient DLL
vigem = ctypes.cdll.LoadLibrary("./ViGEmClient.dll")
# allocate
vigem_alloc = vigem.vigem_alloc
vigem_alloc.argtypes = ()
vigem_alloc.restype = ctypes.c_void_p
# test
client = vigem_alloc()
print(client)
# connect
vigem_connect = vigem.vigem_connect
vigem_connect.argtypes = (ctypes.c_void_p,)
vigem_connect.restype = ctypes.c_uint
# connect client
result = vigem_connect(client)
print("result: ", result)
# according to https://github.com/fsadannn/pyvjoystick/blob/8265486ca871b5baef4e91834870f2dd317498e9/pyvjoystick/vigem/constants.py#L183
if result == 0x20000000:
print("Connected successfully")
else:
print("Failed to connect")
# Add X360 target
vigem_target_x360_alloc = vigem.vigem_target_x360_alloc
vigem_target_x360_alloc.argtypes = ()
vigem_target_x360_alloc.restype = ctypes.c_void_p
x360_target = vigem_target_x360_alloc()
print(x360_target)
# Add target to client
vigem_target_add = vigem.vigem_target_add
vigem_target_add.argtypes = (ctypes.c_void_p, ctypes.c_void_p)
vigem_target_add.restype = ctypes.c_uint
add_result = vigem_target_add(client, x360_target)
if add_result == 0x20000000:
print("X360 target added successfully")
else:
print("Failed to add X360 target")
# Simulate input (example: press A button)
class XUSB_REPORT(ctypes.Structure):
_fields_ = [
("wButtons", ctypes.c_ushort),
("bLeftTrigger", ctypes.c_byte),
("bRightTrigger", ctypes.c_byte),
("sThumbLX", ctypes.c_short),
("sThumbLY", ctypes.c_short),
("sThumbRX", ctypes.c_short),
("sThumbRY", ctypes.c_short)
]
vigem_target_x360_update = vigem.vigem_target_x360_update
vigem_target_x360_update.argtypes = (ctypes.c_void_p, ctypes.c_void_p, XUSB_REPORT)
vigem_target_x360_update.restype = ctypes.c_uint
XUSB_GAMEPAD_A = 0x1000
XUSB_GAMEPAD_B = 0x2000
# report = XUSB_REPORT(wButtons=XUSB_GAMEPAD_A)
report = XUSB_REPORT(wButtons=XUSB_GAMEPAD_B)
update_result = vigem_target_x360_update(client, x360_target, report)
if update_result == 0x20000000:
print("Input simulated successfully")
else:
print("Failed to simulate input")
time.sleep(10)
# Disconnect target
vigem_target_remove = vigem.vigem_target_remove
vigem_target_remove.argtypes = (ctypes.c_void_p, ctypes.c_void_p)
vigem_target_remove.restype = ctypes.c_uint
remove_result = vigem_target_remove(client, x360_target)
if remove_result == 0x20000000:
print("Target removed successfully")
else:
print("Failed to remove target")
# Free target
vigem_target_free = vigem.vigem_target_free
vigem_target_free.argtypes = (ctypes.c_void_p,)
vigem_target_free(x360_target)
# Disconnect client
vigem_disconnect = vigem.vigem_disconnect
vigem_disconnect.argtypes = (ctypes.c_void_p,)
vigem_disconnect.restype = ctypes.c_void_p
result = vigem_disconnect(client)
print(result)
# Free client
vigem_free = vigem.vigem_free
vigem_free.argtypes = (ctypes.c_void_p,)
vigem_free.restype = ctypes.c_void_p
result = vigem_free(client)
print(result)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment