Last active
October 6, 2024 22:23
-
-
Save CypherpunkSamurai/1488b4b896e122065a78963c5b9d04f5 to your computer and use it in GitHub Desktop.
My Own ViGEm Client using CTypes in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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