93 Commits

Author SHA1 Message Date
311b047bf5 Merge pull request 'Removed debuging prints. /JL' (#28) from 0.2.5 into main
Reviewed-on: #28
2025-05-07 21:46:57 +02:00
13901aeb50 Removed debuging prints. /JL
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 21:44:07 +02:00
5f3f25cc8c Merge pull request 'Updated initialization code. /JL' (#27) from 0.2.4 into main
Reviewed-on: #27
2025-05-07 21:41:01 +02:00
96ae8860d5 Updated initialization code. /JL
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 21:40:40 +02:00
8a8f6deb89 Merge pull request 'Updated DualShock4 support. /JL' (#26) from 0.2.3 into main
Reviewed-on: #26
2025-05-07 21:34:21 +02:00
79230bfef3 Updated DualShock4 support. /JL
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 21:33:46 +02:00
063af49887 Merge pull request '0.2.2' (#25) from 0.2.2 into main
Reviewed-on: #25
2025-05-07 16:49:36 +02:00
21da6857b0 Updated. /JL
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 16:48:39 +02:00
0a892386ae Update README.md
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 07:30:05 +02:00
83d7177a78 Update README.md
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 07:21:12 +02:00
cc8afa8519 Update README.md
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 07:20:11 +02:00
4cf83ce9d1 Update README.md
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 07:19:22 +02:00
30379bd8e3 Add .gitea/workflows/test.yml
Some checks failed
Run Controller Tests / test (push) Has been cancelled
2025-05-07 07:10:10 +02:00
a6b4964e80 Update pygameControls/tests/test_controller.py 2025-05-07 06:49:57 +02:00
98ea8ef5b9 Add pygameControls/tests/test_controller.py 2025-05-07 06:29:41 +02:00
985e6a769d Merge pull request 'Cleanup code. /JL' (#24) from 0.2.1 into main
Reviewed-on: #24
2025-05-06 20:58:28 +02:00
b0d364b15e Cleanup code. /JL 2025-05-06 20:57:58 +02:00
f99b53d4b7 Merge pull request '0.2.0' (#23) from 0.2.0 into main
Reviewed-on: #23
2025-05-06 20:50:15 +02:00
e02148c937 GUID identification used to determine gamepad. /JL 2025-05-06 20:47:01 +02:00
e99f8f761c Update pygameControls/globals.py 2025-05-06 08:13:16 +02:00
074bff27d6 Update pygameControls/globals.py 2025-05-06 08:07:35 +02:00
52264dc7cf Update pygameControls/globals.py 2025-05-06 07:21:39 +02:00
25794ce68c Update pygameControls/globals.py 2025-05-06 07:08:07 +02:00
8acc3666dc Update pygameControls/logitech_f710_controller.py 2025-05-06 07:05:22 +02:00
53b3dc3761 Update pygameControls/logitech_f510_controller.py 2025-05-06 07:04:22 +02:00
b236be16b7 Update pygameControls/globals.py 2025-05-05 13:57:38 +02:00
97908392f6 Update pygameControls/globals.py 2025-05-05 13:28:39 +02:00
1004d0fef5 Update pygameControls/controller.py 2025-05-05 13:06:33 +02:00
422cb858ac Update pygameControls/globals.py 2025-05-05 13:05:17 +02:00
ae528e516b Add pygameControls/globals.py 2025-05-05 13:00:12 +02:00
9954e3c308 Update pygameControls/controller.py 2025-05-05 12:48:01 +02:00
263853da7f Update pygameControls/xbox_series_x_controller.py 2025-05-05 11:49:42 +02:00
e5f6d5697b Update pygameControls/enums.py 2025-05-05 11:31:23 +02:00
74f2665a2f Update pygameControls/xbox_360_controller.py 2025-05-05 11:29:44 +02:00
d2bf9a8a1e Update pygameControls/enums.py 2025-05-05 11:26:55 +02:00
480411b50f Add pygameControls/xbox_360_controller.py 2025-05-05 11:00:27 +02:00
4e8af089a0 Update pygameControls/controller.py 2025-05-05 10:59:35 +02:00
7c6275db45 Add pygameControls/sony_playstation4_controller.py 2025-05-05 09:34:10 +02:00
86b7e5dd13 Add pygameControls/playstation4_controller.py 2025-05-05 09:33:28 +02:00
3f9dfec413 Update pygameControls/sony_playstation3_controller.py 2025-05-05 09:31:48 +02:00
803df7e087 Update pygameControls/xbox_series_x_controller.py 2025-05-05 09:30:54 +02:00
82f908ae0a Update pygameControls/playstation3_controller.py 2025-05-05 09:29:57 +02:00
94564057b9 Update pygameControls/logitech_f710_controller.py 2025-05-05 09:27:49 +02:00
40c6af15ef Update pygameControls/logitech_dual_action_controller.py 2025-05-05 09:26:43 +02:00
b3603680d8 Update pygameControls/logitech_f310_controller.py 2025-05-05 09:26:25 +02:00
9dea5d4c10 Update pygameControls/logitech_f510_controller.py 2025-05-05 09:26:03 +02:00
b356ce2d9f Update pygameControls/logitech_f310_controller.py 2025-05-05 09:24:46 +02:00
8ac6883f17 Update pygameControls/logitech_dual_action_controller.py 2025-05-05 09:23:59 +02:00
1c2565cf39 Update pygameControls/generic_controller.py 2025-05-05 09:22:33 +02:00
3cccc1d1c7 Update pygameControls/dualsense_edge_controller.py 2025-05-05 09:20:02 +02:00
3b898462e0 Update pygameControls/dualsense_controller.py 2025-05-05 09:18:27 +02:00
f2ea6a014b Update pygameControls/enums.py 2025-05-05 09:14:57 +02:00
88c5208aea Add pygameControls/enums.py 2025-05-05 09:13:06 +02:00
b78cc61b21 Update pygameControls/xbox_series_x_controller.py 2025-05-05 09:11:29 +02:00
d9d604318c Update pygameControls/sony_playstation3_controller.py 2025-05-05 09:11:15 +02:00
a5bf138ea5 Update pygameControls/playstation3_controller.py 2025-05-05 09:11:00 +02:00
95170bcd0d Update pygameControls/logitech_f310_controller.py 2025-05-05 09:10:32 +02:00
6eb50802d4 Update pygameControls/logitech_dual_action_controller.py 2025-05-05 09:10:17 +02:00
f1a6f6e21d Update pygameControls/generic_controller.py 2025-05-05 09:10:00 +02:00
148205d27a Update pygameControls/dualsense_controller.py 2025-05-05 09:09:42 +02:00
ff6f5ffa13 Update pygameControls/dualsense_edge_controller.py 2025-05-05 09:09:24 +02:00
7791e1de0b Update pygameControls/logitech_f510_controller.py 2025-05-05 09:08:07 +02:00
124c961ff0 Update pygameControls/logitech_f710_controller.py 2025-05-05 09:07:56 +02:00
e5a1ff1bbd Update pygameControls/xbox_series_x_controller.py 2025-05-05 09:07:42 +02:00
8c2fff3be1 Update pygameControls/sony_playstation3_controller.py 2025-05-05 09:07:15 +02:00
50fa5106a3 Update pygameControls/playstation3_controller.py 2025-05-05 09:06:24 +02:00
d5790b538c Update pygameControls/logitech_f710_controller.py 2025-05-05 09:06:02 +02:00
4c4aed6fa8 Update pygameControls/logitech_f510_controller.py 2025-05-05 09:05:34 +02:00
baa3675406 Update pygameControls/logitech_f310_controller.py 2025-05-05 09:05:13 +02:00
1342f281d7 Update pygameControls/logitech_dual_action_controller.py 2025-05-05 09:04:50 +02:00
cefd61a97a Update pygameControls/generic_controller.py 2025-05-05 09:04:23 +02:00
7b2641f174 Update pygameControls/dualsense_edge_controller.py 2025-05-05 09:03:55 +02:00
7d4037a748 Update pygameControls/dualsense_controller.py
Added connection_type. /JL
2025-05-05 09:03:32 +02:00
d26316d273 Update pygameControls/controller.py
Added connection type to class init. /JL
2025-05-05 09:02:09 +02:00
2a9746d510 Update pygameControls/controller.py
Added support for getting connection type of controller. /JL
2025-05-05 08:30:54 +02:00
2285535276 Merge pull request 'Added Playstation 3 controller. /JL' (#22) from 0.1.13 into main
Reviewed-on: #22
2025-05-04 14:45:25 +02:00
2bbf4e19d1 Added Playstation 3 controller. /JL 2025-05-04 14:44:53 +02:00
caebb2be77 Merge pull request 'Added DualShock3 controller. /JL' (#21) from 0.1.12 into main
Reviewed-on: #21
2025-05-03 14:03:28 +02:00
304e42025c Added DualShock3 controller. /JL 2025-05-03 14:02:32 +02:00
0dc32bd979 Merge pull request 'Updated mappings. /JL' (#20) from 0.1.11 into main
Reviewed-on: #20
2025-04-25 18:19:44 +02:00
17c947b6fb Updated mappings. /JL 2025-04-25 18:19:05 +02:00
085355e0f9 Merge pull request 'Working on Xbox mapping. /JL' (#19) from 0.1.10 into main
Reviewed-on: #19
2025-04-25 18:16:32 +02:00
029eb3095e Working on Xbox mapping. /JL 2025-04-25 18:03:44 +02:00
6eca515cf7 Merge pull request 'Updated Xbox controller. /JL' (#18) from 0.1.9 into main
Reviewed-on: #18
2025-04-20 23:37:38 +02:00
57d2d60f67 Updated Xbox controller. /JL 2025-04-20 23:37:16 +02:00
1ccceeeb06 Merge pull request 'Updated Xbox controller selection. /JL' (#17) from 0.1.8 into main
Reviewed-on: #17
2025-04-20 23:25:30 +02:00
ff3bfc66d2 Updated Xbox controller selection. /JL 2025-04-20 23:25:09 +02:00
5be0dace93 Merge pull request 'Added close() method to all controller classes. /JL' (#16) from 0.1.7 into main
Reviewed-on: #16
2025-04-20 23:21:01 +02:00
d6f72a8e74 Added close() method to all controller classes. /JL 2025-04-20 23:20:37 +02:00
5a5acdf583 Merge pull request 'Added stop_rumble() to all controller classes. /JL' (#15) from 0.1.6 into main
Reviewed-on: #15
2025-04-20 23:15:59 +02:00
9c66fe8930 Added stop_rumble() to all controller classes. /JL 2025-04-20 23:15:35 +02:00
3980bd92ca Merge pull request 'Update Xbox controller. /JL' (#14) from 0.1.5 into main
Reviewed-on: #14
2025-04-20 23:09:50 +02:00
75fb3f577b Update Xbox controller. /JL 2025-04-20 23:09:25 +02:00
25 changed files with 843 additions and 270 deletions

29
.gitea/workflows/test.yml Normal file
View File

@@ -0,0 +1,29 @@
name: Run Controller Tests
on:
push:
branches-ignore: [ main ]
pull-request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/setup-python@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install Dependencies
run:
python -m pip install --upgrade pip
pip install pygame
- name: Run Unit Tests
run:
python -m unittest discover tests

View File

@@ -1,3 +1,6 @@
# PyGame-Controller
Small module to make it easy to add controller support.
Small module to make it easy to add controller support.
![Tests](https://gitpot-lerking.servehttp.com/api/v1/badges/CodingPirates/PyGame-Controller/workflows/test.yml)
![Version](https://img.shields.io/badge/version-0.2.5-blue)

View File

@@ -30,7 +30,7 @@ class TextPrint:
def main():
# Set the width and height of the screen (width, height), and name the window.
screen = pygame.display.set_mode((500, 700))
screen = pygame.display.set_mode((800, 700))
pygame.display.set_caption("Joystick example")
# Used to manage how fast the screen updates.

55
joystick_debug.py Normal file
View File

@@ -0,0 +1,55 @@
import os
import pygame
from evdev import InputDevice, list_devices
def format_vidpid(info):
return f"{info.vendor:04x}:{info.product:04x}"
def get_evdev_devices():
evdev_devices = {}
for path in list_devices():
try:
dev = InputDevice(path)
evdev_devices[os.path.basename(path)] = {
'name': dev.name,
'phys': dev.phys,
'vidpid': format_vidpid(dev.info),
'path': path
}
except Exception:
pass
return evdev_devices
def match_evdev_to_pygame():
pygame.init()
pygame.joystick.init()
evdev_devices = get_evdev_devices()
for i in range(pygame.joystick.get_count()):
js = pygame.joystick.Joystick(i)
js.init()
name = js.get_name()
guid = js.get_guid()
# Try to guess the matching evdev device based on name
matched = None
for ev in evdev_devices.values():
if name.lower() in ev['name'].lower() or ev['name'].lower() in name.lower():
matched = ev
break
print(f"Joystick {i}:")
print(f" pygame name : {name}")
print(f" pygame guid : {guid}")
if matched:
print(f" evdev name : {matched['name']}")
print(f" path : {matched['path']}")
print(f" phys : {matched['phys']}")
print(f" VID:PID : {matched['vidpid']}")
else:
print(f" evdev info : [not matched]")
print("-" * 40)
if __name__ == "__main__":
match_evdev_to_pygame()

View File

@@ -1,5 +1,6 @@
import pygame
import pygameControls as PC
from pygameControls import globals
if __name__ == "__main__":
pygame.init()

View File

@@ -1,31 +1,19 @@
import pygame
from .controlsbase import ControlsBase
from .dualsense_controller import DualSenseController
from .dualsense_edge_controller import DualSenseEdgeController
from .logitech_f310_controller import LogitechF310Controller
from .logitech_f510_controller import LogitechF510Controller
from .logitech_f710_controller import LogitechF710Controller
from .xbox_series_x_controller import XboxSeriesXController
from .generic_controller import GenericController
from .logitech_dual_action_controller import LogitechDualActionController
from . import globals
__version__ = "0.1.4"
CONTROLLERS = {
"DualSense Wireless Controller": DualSenseController,
"DualSense Edge Wireless Controller": DualSenseEdgeController,
"Logitech Gamepad F310": LogitechF310Controller,
"Logitech Gamepad F510": LogitechF510Controller,
"Logitech Gamepad F710": LogitechF710Controller,
"Logitech Dual Action": LogitechDualActionController,
"X box Series X Controller": XboxSeriesXController
}
__version__ = "0.2.5"
class Controllers:
def __init__(self, joy):
globals.init()
self.controllers = []
if not joy.get_name() in CONTROLLERS:
self.controllers.append(GenericController(joy))
else:
self.controllers.append(CONTROLLERS[joy.get_name()](joy))
cont = self.detect_controller(joy.get_guid())
self.controllers.append(cont(joy))
def detect_controller(self, guid):
for gp in globals.GAMEPADS:
for p in globals.GAMEPADS[gp]:
if p["guid"] != guid:
continue
return p["class"]
return globals.CONTROLLERS["Generic Controller"]

View File

@@ -30,4 +30,12 @@ class ControlsBase(ABC):
@abstractmethod
def rumble(self):
pass
@abstractmethod
def stop_rumble(self):
pass
@abstractmethod
def close(self):
pass

View File

@@ -15,6 +15,7 @@ class DualSenseController(ControlsBase):
self.device = pydualsense()
self.device.init()
self.name = self.device.device.get_product_string()
self.guid = self.device.get_guid()
self.powerlevel = self.device.battery.Level
self.batterystate = BATTERY_STATE[str(self.device.battery.State)]
self.set_player_id(PlayerID.PLAYER_1)
@@ -25,25 +26,17 @@ class DualSenseController(ControlsBase):
self.numbuttons: int = joy.get_numbuttons()
self.buttons: list = [joy.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[3],
"right stick y": self.axis[4],
"right trigger": self.buttons[5],
"left trigger": self.buttons[2],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[4],
"right button": self.buttons[5],
"cross button": self.buttons[0],
"triangle button": self.buttons[2],
"circle button": self.buttons[1],
"square button": self.buttons[3],
"left stick button": self.buttons[11],
"right stick button": self.buttons[12],
"connect button": self.buttons[8],
"list button": self.buttons[9],
"logo button": self.buttons[10]
"l1 button": 4,
"r1 button": 5,
"cross button": 0,
"triangle button": 2,
"circle button": 1,
"square button": 3,
"left stick button": 11,
"right stick button": 12,
"connect button": 8,
"list button": 9,
"logo button": 10
}
print(f"{self.name} connected")
print(f"Power level: {self.powerlevel}")

View File

@@ -7,6 +7,7 @@ class DualSenseEdgeController(ControlsBase):
self.device = pydualsense()
self.device.init()
self.name = self.device.device.get_product_string()
self.guid = self.device.get_guid()
self.powerlevel = self.device.battery.Level
self.batterystate = BATTERY_STATE[str(self.device.battery.State)]
self.set_player_id(PlayerID.PLAYER_1)

12
pygameControls/enums.py Normal file
View File

@@ -0,0 +1,12 @@
from enum import Enum
class ConnectionType(Enum):
USB = 1
BLUETOOTH = 2
WIRELESS = 3
Unknown = -1
class InputType(Enum):
DirectInput = 1
XInput = 2
Unknown = -1

View File

@@ -14,28 +14,25 @@ class GenericController(ControlsBase):
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[2],
"right stick y": self.axis[3],
"right trigger": self.buttons[7],
"left trigger": self.buttons[6],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[4],
"right button": self.buttons[5],
"X button": self.buttons[0],
"Y button": self.buttons[3],
"A button": self.buttons[1],
"B button": self.buttons[2],
"left stick button": self.buttons[10],
"right stick button": self.buttons[11],
"back button": self.buttons[8],
"start button": self.buttons[9],
"r2 trigger": 7,
"l2 trigger": 6,
"l1 button": 4,
"r1 button": 5,
"X button": 0,
"Y button": 3,
"A button": 1,
"B button": 2,
"left stick button": 10,
"right stick button": 11,
"back button": 8,
"start button": 9,
"logo button": None
}
print(f"{self.name} connected.")
def close(self):
pass
def handle_input(self, event):
pass
@@ -57,6 +54,9 @@ class GenericController(ControlsBase):
def rumble(self):
pass
def stop_rumble(self):
pass
@property
def name(self) -> str:
return self._name

207
pygameControls/globals.py Normal file
View File

@@ -0,0 +1,207 @@
from .enums import ConnectionType, InputType
from .controlsbase import ControlsBase
from .dualsense_controller import DualSenseController
from .dualsense_edge_controller import DualSenseEdgeController
from .logitech_f310_controller import LogitechF310Controller
from .logitech_f510_controller import LogitechF510Controller
from .logitech_f710_controller import LogitechF710Controller
from .xbox_series_x_controller import XboxSeriesXController
from .sony_playstation3_controller import SonyPlayStation3Controller
from .playstation3_controller import PlayStation3Controller
from .sony_playstation4_controller import SonyPlayStation4Controller
from .playstation4_controller import PlayStation4Controller
from .generic_controller import GenericController
from .logitech_dual_action_controller import LogitechDualActionController
def init():
global VID_PID
VID_PID = {
"046d:c216": "Logitech Gamepad F310",
"046d:c21d": "Microsoft X-Box 360 pad",
"046d:c21d": "Logitech Dual Action",
"045e:0b12": "Xbox Series X Controller",
"045e:0b13": "Xbox Series X Controller",
"045e:0b20": "Xbox Series X Controller",
"045e:0b21": "Xbox Series X Controller",
"054c:0ce6": "DualSense Wireless Controller",
"054c:0df2": "DualSense Wireless Controller",
}
global CONTROLLERS
CONTROLLERS = {
"DualSense Wireless Controller": DualSenseController,
"DualSense Edge Wireless Controller": DualSenseEdgeController,
"Logitech Gamepad F310": LogitechF310Controller,
"Logitech Gamepad F510": LogitechF510Controller,
"Logitech Gamepad F710": LogitechF710Controller,
"Logitech Dual Action": LogitechDualActionController,
"Microsoft X-Box 360 pad": LogitechDualActionController,
"Xbox Series X Controller": XboxSeriesXController,
"Sony PLAYSTATION(R)3 Controller": SonyPlayStation3Controller,
"PLAYSTATION(R)3 Controller": PlayStation3Controller,
"Sony PLAYSTATION(R)4 Controller": SonyPlayStation4Controller,
"PLAYSTATION(R)4 Controller": PlayStation4Controller,
"Generic Controller": GenericController
}
global GAMEPADS
GAMEPADS = {
"Sony Controller": [
{
"vidpid": "054c:0ce6",
"guid": "0300fd574c050000e60c000011810000",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": [
"Sony Interactive Entertainment DualSense Wireless Controller",
"Sony Corp. DualSense wireless controller (PS5)",
"DualSense Wireless Controller"
],
"class": CONTROLLERS["DualSense Wireless Controller"]
},
{
"vidpid": "054c:0df2",
"guid": "050057564c050000e60c000000810000",
"connection": ConnectionType.BLUETOOTH,
"input": InputType.DirectInput,
"name": [
"DualSense Wireless Controller"
],
"class": CONTROLLERS["DualSense Wireless Controller"]
},
{
"vidpid": "054c:0dfc",
"guid": "",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": ["DualSense Edge Wireless Controller"],
"class": CONTROLLERS["DualSense Edge Wireless Controller"]
},
{
"vidpid": "054c:0dfc",
"guid": "",
"connection": ConnectionType.BLUETOOTH,
"input": InputType.DirectInput,
"name": ["DualSense Edge Wireless Controller"],
"class": CONTROLLERS["DualSense Edge Wireless Controller"]
},
{
"vidpid": "054c:0268",
"guid": "0300afd34c0500006802000011810000",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": ["Sony PLAYSTATION(R)3 Controller"],
"class": CONTROLLERS["Sony PLAYSTATION(R)3 Controller"]
},
{
"vidpid": "",
"guid": "0500f9d24c0500006802000000800000",
"connection": ConnectionType.BLUETOOTH,
"input": InputType.DirectInput,
"name": ["PLAYSTATION(R)3 Controller"],
"class": CONTROLLERS["PLAYSTATION(R)3 Controller"]
},
{
"vidpid": "054c:05c4",
"guid": "",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": ["DualShock 4 v1 Controller"],
"class": CONTROLLERS["PLAYSTATION(R)4 Controller"]
},
{
"vidpid": "054c:05c4",
"guid": "",
"connection": ConnectionType.BLUETOOTH,
"input": InputType.DirectInput,
"name": ["DualShock 4 v1 Controller"],
"class": CONTROLLERS["Sony PLAYSTATION(R)4 Controller"]
},
{
"vidpid": "054c:09cc",
"guid": "",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": ["DualShock 4 v2 Controller"],
"class": CONTROLLERS["PLAYSTATION(R)4 Controller"]
},
{
"vidpid": "054c:09cc",
"guid": "05009b514c050000cc09000000810000",
"connection": ConnectionType.BLUETOOTH,
"input": InputType.DirectInput,
"name": ["Wireless Controller"],
"class": CONTROLLERS["Sony PLAYSTATION(R)4 Controller"]
}
],
"Microsoft Controller": [
{
"vidpid": "045e:0b12",
"guid": "0300509d5e040000120b000017050000",
"connection": ConnectionType.USB,
"input": InputType.XInput,
"name": [
"Xbox Series X Controller",
"Microsoft Corp. Xbox Controller"
],
"class": CONTROLLERS["Xbox Series X Controller"]
},
{
"vidpid": "045e:0b13",
"guid": "0500509d5e040000130b000023050000",
"connection": ConnectionType.BLUETOOTH,
"input": InputType.XInput,
"name": [
"Xbox Series X Controller",
"Xbox Wireless Controller"
],
"class": CONTROLLERS["Xbox Series X Controller"]
}
],
"Logitech Controller": [
{
"vidpid": "046d:c21d",
"guid": "030005ff6d0400001dc2000014400000",
"connection": ConnectionType.USB,
"input": InputType.XInput,
"name": [
"Logitech, Inc. F310 Gamepad [XInput Mode]",
"Logitech Gamepad F310"
],
"class": CONTROLLERS["Logitech Gamepad F310"]
},
{
"vidpid": "046d:c216",
"guid": "0300040e6d04000016c2000011010000",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": [
"Logitech, Inc. F310 Gamepad [DirectInput Mode]",
"Logitech Dual Action",
"Logitech Logitech Dual Action"
],
"class": CONTROLLERS["Logitech Dual Action"]
},
{
"vidpid": "046d:c21d",
"guid": "",
"connection": ConnectionType.USB,
"input": InputType.XInput,
"name": [
"Logitech, Inc. F710 Gamepad [XInput Mode]",
"Logitech Gamepad F710"
],
"class": CONTROLLERS["Logitech Gamepad F710"]
},
{
"vidpid": "046d:c216",
"guid": "",
"connection": ConnectionType.USB,
"input": InputType.DirectInput,
"name": [
"Logitech, Inc. F710 Gamepad [DirectInput Mode]",
"Logitech Dual Action"
],
"class": CONTROLLERS["Logitech Dual Action"]
}
]
}

View File

@@ -14,12 +14,7 @@ This controller is a usb controller, with the following features.
import pygame
from pygameControls.controlsbase import ControlsBase
from enum import Enum
class InputMode(Enum):
DirectInput = 1
XInput = 2
class LogitechDualActionController(ControlsBase):
def __init__(self, joy):
self.device = joy
@@ -33,30 +28,26 @@ class LogitechDualActionController(ControlsBase):
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.input_mode = InputMode.DirectInput
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[2],
"right stick y": self.axis[3],
"right trigger": self.buttons[7],
"left trigger": self.buttons[6],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[4],
"right button": self.buttons[5],
"X button": self.buttons[0],
"Y button": self.buttons[3],
"A button": self.buttons[1],
"B button": self.buttons[2],
"left stick button": self.buttons[10],
"right stick button": self.buttons[11],
"back button": self.buttons[8],
"start button": self.buttons[9],
"r2 trigger": 7,
"l2 trigger": 6,
"l1 button": 4,
"r1 button": 5,
"X button": 0,
"Y button": 3,
"A button": 1,
"B button": 2,
"left stick button": 10,
"right stick button": 11,
"back button": 8,
"start button": 9,
"logo button": None
}
print(f"{self.name} connected.")
def close(self):
pass
def handle_input(self, event):
pass
@@ -78,6 +69,9 @@ class LogitechDualActionController(ControlsBase):
def rumble(self):
pass
def stop_rumble(self):
pass
@property
def name(self) -> str:
return self._name
@@ -85,12 +79,4 @@ class LogitechDualActionController(ControlsBase):
@name.setter
def name(self, name: str) -> None:
self._name = name
@property
def input_mode(self) -> int:
return self._inputmode
@input_mode.setter
def input_mode(self, mode: int) -> None:
self._inputmode = mode

View File

@@ -14,12 +14,7 @@ This controller is a usb controller, with the following features.
import pygame
from pygameControls.controlsbase import ControlsBase
from enum import Enum
class InputMode(Enum):
DirectInput = 1
XInput = 2
class LogitechF310Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
@@ -33,30 +28,24 @@ class LogitechF310Controller(ControlsBase):
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.input_mode = InputMode.XInput
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[3],
"right stick y": self.axis[4],
"right trigger": self.axis[2],
"left trigger": self.axis[5],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[4],
"right button": self.buttons[5],
"X button": self.buttons[2],
"Y button": self.buttons[3],
"A button": self.buttons[0],
"B button": self.buttons[1],
"left stick button": self.buttons[9],
"right stick button": self.buttons[10],
"back button": self.buttons[6],
"start button": self.buttons[7],
"logo button": self.buttons[8]
"l1 button": 4,
"r1 button": 5,
"X button": 2,
"Y button": 3,
"A button": 0,
"B button": 1,
"left stick button": 9,
"right stick button": 10,
"back button": 6,
"start button": 7,
"logo button": 8
}
print(f"{self.name} connected.")
def close(self):
pass
def handle_input(self, event):
pass
@@ -78,6 +67,9 @@ class LogitechF310Controller(ControlsBase):
def rumble(self):
pass
def stop_rumble(self):
pass
@property
def name(self) -> str:
return self._name
@@ -85,12 +77,4 @@ class LogitechF310Controller(ControlsBase):
@name.setter
def name(self, name: str) -> None:
self._name = name
@property
def input_mode(self) -> int:
return self._inputmode
@input_mode.setter
def input_mode(self, mode: int) -> None:
self._inputmode = mode

View File

@@ -1,64 +1,43 @@
"""
Logitech F310 Controller class.
This controller is a usb controller, with the following features.
(XInput mode)
6 axis
11 buttons
1 hat
(DirectInput mode)
4 axis
12 buttons
1 hat
Logitech F510 Controller class.
This controller should have the same setup as the F310, but with the addition of rumble effect.
I don't have this controller, so I haven't been able to verify the workings!
Subsequent updates will be done, based on updates for the F310.
"""
import pygame
from pygameControls.controlsbase import ControlsBase
from enum import Enum
class InputMode(Enum):
DirectInput = 1
XInput = 2
class ConnectionType(Enum):
WIRED = 1
WIRELESS = 2
class LogitechF510Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxis()
self.axis: list = []
self.numhats: int = self.device.get_numhats()
self.hats: list = []
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = []
self.input_mode: InputMode.DirectInput
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[3],
"right stick y": self.axis[4],
"right trigger": self.axis[2],
"left trigger": self.axis[5],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[4],
"right button": self.buttons[5],
"X button": self.buttons[2],
"Y button": self.buttons[3],
"A button": self.buttons[0],
"B button": self.buttons[1],
"left stick button": self.buttons[9],
"right stick button": self.buttons[10],
"back button": self.buttons[6],
"start button": self.buttons[7],
"logo button": self.buttons[8]
"l1 button": 4,
"r1 button": 5,
"X button": 2,
"Y button": 3,
"A button": 0,
"B button": 1,
"left stick button": 9,
"right stick button": 10,
"back button": 6,
"start button": 7,
"logo button": 8
}
print(f"{self.name} connected.")
def close(self):
pass
def handle_input(self, event):
pass
@@ -80,6 +59,9 @@ class LogitechF510Controller(ControlsBase):
def rumble(self):
pass
def stop_rumble(self):
pass
@property
def name(self) -> str:
return self._name
@@ -111,19 +93,4 @@ class LogitechF510Controller(ControlsBase):
@buttons.setter
def buttons(self) -> None:
self._buttons = [self.device.get_buttons(b) for b in range(self.numbuttons)]
@property
def input_mode(self) -> int:
return self._inputmode
@input_mode.setter
def input_mode(self, mode: int) -> None:
self._inputmode = mode
@property
def input_connection(self) -> int:
return self._input_connection
@input_connection.setter
def input_connection(self, conn: int) -> None:
self._input_connection = conn

View File

@@ -1,64 +1,41 @@
"""
Logitech F310 Controller class.
This controller is a usb controller, with the following features.
(XInput mode)
6 axis
11 buttons
1 hat
(DirectInput mode)
4 axis
12 buttons
1 hat
Logitech F710 Controller class.
This controller is a usb/wireless controller.
"""
import pygame
from pygameControls.controlsbase import ControlsBase
from enum import Enum
class InputMode(Enum):
DirectInput = 1
XInput = 2
class ConnectionType(Enum):
WIRED = 1
WIRELESS = 2
class LogitechF710Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxis()
self.axis: list = []
self.numhats: int = self.device.get_numhats()
self.hats: list = []
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = []
self.input_mode: InputMode.DirectInput
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[3],
"right stick y": self.axis[4],
"right trigger": self.axis[2],
"left trigger": self.axis[5],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[4],
"right button": self.buttons[5],
"X button": self.buttons[2],
"Y button": self.buttons[3],
"A button": self.buttons[0],
"B button": self.buttons[1],
"left stick button": self.buttons[9],
"right stick button": self.buttons[10],
"back button": self.buttons[6],
"start button": self.buttons[7],
"logo button": self.buttons[8]
"l1 button": 4,
"r1 button": 5,
"X button": 2,
"Y button": 3,
"A button": 0,
"B button": 1,
"left stick button": 9,
"right stick button": 10,
"back button": 6,
"start button": 7,
"logo button": 8
}
print(f"{self.name} connected.")
def close(self):
pass
def handle_input(self, event):
pass
@@ -80,6 +57,9 @@ class LogitechF710Controller(ControlsBase):
def rumble(self):
pass
def stop_rumble(self):
pass
@property
def name(self) -> str:
return self._name
@@ -111,19 +91,4 @@ class LogitechF710Controller(ControlsBase):
@buttons.setter
def buttons(self) -> None:
self._buttons = [self.device.get_buttons(b) for b in range(self.numbuttons)]
@property
def input_mode(self) -> int:
return self._inputmode
@input_mode.setter
def input_mode(self, mode: int) -> None:
self._inputmode = mode
@property
def input_connection(self) -> int:
return self._input_connection
@input_connection.setter
def input_connection(self, conn: int) -> None:
self._input_connection = conn

View File

@@ -0,0 +1,71 @@
from pygameControls.controlsbase import ControlsBase
import pygame
class PlayStation3Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxes()
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
self.numhats: int = self.device.get_numhats()
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"l1 button": 4,
"r1 button": 5,
"cross button": 0,
"triangle button": 2,
"circle button": 1,
"square button": 3,
"left stick button": 11,
"right stick button": 12,
"logo button": 10,
"select button": 8,
"start button": 9,
"down button": 14,
"up button": 13,
"left button": 15,
"right button": 16
}
print(f"{self.name} connected.")
def close(self):
self.device.quit()
def handle_input(self, event):
pass
def left(self):
pass
def right(self):
pass
def up(self):
pass
def down(self):
pass
def pause(self):
pass
def rumble(self, left, right, duration=0):
if not left in range(256) or not right in range(256):
raise ValueError("left and right values must be in the range 0 - 255")
self.device.rumble(left / 255, right / 255, duration)
def stop_rumble(self):
self.device.stop_rumble()
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, name: str) -> None:
self._name = name

View File

@@ -0,0 +1,71 @@
from pygameControls.controlsbase import ControlsBase
import pygame
class PlayStation4Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxes()
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
self.numhats: int = self.device.get_numhats()
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"l1 button": 4,
"r1 button": 5,
"cross button": 0,
"triangle button": 2,
"circle button": 1,
"square button": 3,
"left stick button": 11,
"right stick button": 12,
"logo button": 10,
"select button": 8,
"start button": 9,
"down button": 14,
"up button": 13,
"left button": 15,
"right button": 16
}
print(f"{self.name} connected.")
def close(self):
self.device.quit()
def handle_input(self, event):
pass
def left(self):
pass
def right(self):
pass
def up(self):
pass
def down(self):
pass
def pause(self):
pass
def rumble(self, left, right, duration=0):
if not left in range(256) or not right in range(256):
raise ValueError("left and right values must be in the range 0 - 255")
self.device.rumble(left / 255, right / 255, duration)
def stop_rumble(self):
self.device.stop_rumble()
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, name: str) -> None:
self._name = name

View File

@@ -0,0 +1,71 @@
from pygameControls.controlsbase import ControlsBase
import pygame
class SonyPlayStation3Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxes()
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
self.numhats: int = self.device.get_numhats()
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"l1 button": 4,
"r1 button": 5,
"cross button": 0,
"triangle button": 2,
"circle button": 1,
"square button": 3,
"left stick button": 11,
"right stick button": 12,
"logo button": 10,
"select button": 8,
"start button": 9,
"down button": 14,
"up button": 13,
"left button": 15,
"right button": 16
}
print(f"{self.name} connected.")
def close(self):
self.device.quit()
def handle_input(self, event):
pass
def left(self):
pass
def right(self):
pass
def up(self):
pass
def down(self):
pass
def pause(self):
pass
def rumble(self, left, right, duration=0):
if not left in range(256) or not right in range(256):
raise ValueError("left and right values must be in the range 0 - 255")
self.device.rumble(left / 255, right / 255, duration)
def stop_rumble(self):
self.device.stop_rumble()
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, name: str) -> None:
self._name = name

View File

@@ -0,0 +1,67 @@
from pygameControls.controlsbase import ControlsBase
import pygame
class SonyPlayStation4Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxes()
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
self.numhats: int = self.device.get_numhats()
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"l1 button": 4,
"r1 button": 5,
"cross button": 0,
"triangle button": 2,
"circle button": 1,
"square button": 3,
"left stick button": 11,
"right stick button": 12,
"logo button": 10,
"share button": 8,
"options button": 9
}
print(f"{self.name} connected.")
def close(self):
self.device.quit()
def handle_input(self, event):
pass
def left(self):
pass
def right(self):
pass
def up(self):
pass
def down(self):
pass
def pause(self):
pass
def rumble(self, left, right, duration=0):
if not left in range(256) or not right in range(256):
raise ValueError("left and right values must be in the range 0 - 255")
self.device.rumble(left / 255, right / 255, duration)
def stop_rumble(self):
self.device.stop_rumble()
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, name: str) -> None:
self._name = name

View File

@@ -0,0 +1,31 @@
import unittest
from unittest.mock import MagicMock
from pygameControls import Controller
class TestController(unittest.TestCase):
def setUp(self):
self.mock_js = MagicMock()
self.mock_js.get_button.side_effect = lambda i: 1 if i == 0 else 0
self.mock_js.get_axis.side_effect = lambda i: 0.5 if i == 1 else 0.0
self.mock_js.get_name.return_value = "DualSense Wireless Controller"
self.mock_js.get_guid.return_value = "030000004c0500000c0e000011010000"
self.controller = Controller(self.mock_js)
def test_button_press(self):
self.assertEqual(self.controller.get_button(0), 1)
self.assertEqual(self.controller.get_button(1), 0)
def test_axis_reading(self):
self.assertAlmostEqual(self.controller.get_axis(1), 0.5)
def test_profile_mapping(self):
self.assertEqual(self.controller.get_mapping(), "Sony DualSense")
def test_custom_config(self):
cfg = self.controller.get_custom_config()
self.assertIn("cross", cfg)
self.assertEqual(cfg["cross"], 0)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,68 @@
from pygameControls.controlsbase import ControlsBase
import pygame
class Xbox360Controller(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
self.name = self.device.get_name()
self.guid = self.device.get_guid()
self.numaxis: int = self.device.get_numaxes()
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
self.numhats: int = self.device.get_numhats()
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"l1 button": 6,
"r1 button": 7,
"X button": 3,
"Y button": 4,
"A button": 0,
"B button": 1,
"left stick button": 13,
"right stick button": 14,
"logo button": 12,
"share button": 15,
"list button": 11,
"copy button": 10
}
print(f"{self.name} connected.")
def close(self):
self.device.quit()
def handle_input(self, event):
pass
def left(self):
pass
def right(self):
pass
def up(self):
pass
def down(self):
pass
def pause(self):
pass
def rumble(self, left, right, duration=0):
if not left in range(256) or not right in range(256):
raise ValueError("left and right values must be in the range 0 - 255")
self.device.rumble(left / 255, right / 255, duration)
def stop_rumble(self):
self.device.stop_rumble()
@property
def name(self) -> str:
return self._name
@name.setter
def name(self, name: str) -> None:
self._name = name

View File

@@ -1,7 +1,7 @@
import time
import threading
from pygameControls.controlsbase import ControlsBase
import pygame
class XboxSeriesXController:
class XboxSeriesXController(ControlsBase):
def __init__(self, joy):
self.device = joy
self.instance_id: int = self.device.get_instance_id()
@@ -14,29 +14,24 @@ class XboxSeriesXController:
self.numbuttons: int = self.device.get_numbuttons()
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
self.mapping = {
"left stick x": self.axis[0],
"left stick y": self.axis[1],
"right stick x": self.axis[2],
"right stick y": self.axis[3],
"right trigger": self.axis[4],
"left trigger": self.axis[5],
"dhat x": self.hats[0][0],
"dhat y": self.hats[0][1],
"left button": self.buttons[6],
"right button": self.buttons[7],
"X button": self.buttons[3],
"Y button": self.buttons[4],
"A button": self.buttons[0],
"B button": self.buttons[1],
"left stick button": self.buttons[13],
"right stick button": self.buttons[14],
"logo button": self.buttons[12],
"share button": self.buttons[15],
"list button": self.buttons[11],
"copy button": self.buttons[10]
"l1 button": 6,
"r1 button": 7,
"X button": 3,
"Y button": 4,
"A button": 0,
"B button": 1,
"left stick button": 13,
"right stick button": 14,
"logo button": 12,
"share button": 15,
"list button": 11,
"copy button": 10
}
print(f"{self.name} connected.")
def close(self):
self.device.quit()
def handle_input(self, event):
pass
@@ -55,13 +50,13 @@ class XboxSeriesXController:
def pause(self):
pass
def rumble(self, left, right):
def rumble(self, left, right, duration=0):
if not left in range(256) or not right in range(256):
raise ValueError("left and right values must be in the range 0 - 255")
self.joy.rumble(left, right)
self.device.rumble(left / 255, right / 255, duration)
def stop_rumble(self):
self.joy.rumble(0, 0)
self.device.stop_rumble()
@property
def name(self) -> str:

View File

@@ -3,4 +3,4 @@ pulsectl==24.12.0
pydualsense==0.7.3
pygame==2.6.1
setuptools==68.2.2
sounddevice==0.5.1
sounddevice==0.5.1

View File

@@ -3,7 +3,7 @@ if __name__ == "__main__":
setup(
name='pygameControls',
version='0.1.4',
version='0.2.5',
packages=find_packages(),
install_requires=[],
author='Jan Lerking',