pygameControls 0.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pygamecontrols-0.0.4/LICENSE +9 -0
- pygamecontrols-0.0.4/PKG-INFO +24 -0
- pygamecontrols-0.0.4/README.md +3 -0
- pygamecontrols-0.0.4/pygameControls/__init__.py +1 -0
- pygamecontrols-0.0.4/pygameControls/controller.py +31 -0
- pygamecontrols-0.0.4/pygameControls/controlsbase.py +33 -0
- pygamecontrols-0.0.4/pygameControls/dualsense_audio.py +70 -0
- pygamecontrols-0.0.4/pygameControls/dualsense_controller.py +74 -0
- pygamecontrols-0.0.4/pygameControls/dualsense_edge_controller.py +199 -0
- pygamecontrols-0.0.4/pygameControls/generic_controller.py +45 -0
- pygamecontrols-0.0.4/pygameControls/logitech_dual_action_controller.py +74 -0
- pygamecontrols-0.0.4/pygameControls/logitech_f310_controller.py +74 -0
- pygamecontrols-0.0.4/pygameControls/logitech_f510_controller.py +108 -0
- pygamecontrols-0.0.4/pygameControls/logitech_f710_controller.py +108 -0
- pygamecontrols-0.0.4/pygameControls/xbox_series_x_controller.py +45 -0
- pygamecontrols-0.0.4/pygameControls.egg-info/PKG-INFO +24 -0
- pygamecontrols-0.0.4/pygameControls.egg-info/SOURCES.txt +19 -0
- pygamecontrols-0.0.4/pygameControls.egg-info/dependency_links.txt +1 -0
- pygamecontrols-0.0.4/pygameControls.egg-info/top_level.txt +1 -0
- pygamecontrols-0.0.4/setup.cfg +4 -0
- pygamecontrols-0.0.4/setup.py +21 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 CodingPirates
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pygameControls
|
3
|
+
Version: 0.0.4
|
4
|
+
Summary: A simple controller class for pygame.
|
5
|
+
Home-page:
|
6
|
+
Author: Jan Lerking
|
7
|
+
Author-email:
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.12
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
License-File: LICENSE
|
14
|
+
Dynamic: author
|
15
|
+
Dynamic: classifier
|
16
|
+
Dynamic: description
|
17
|
+
Dynamic: description-content-type
|
18
|
+
Dynamic: license-file
|
19
|
+
Dynamic: requires-python
|
20
|
+
Dynamic: summary
|
21
|
+
|
22
|
+
# PyGame-Controller
|
23
|
+
|
24
|
+
Small module to make it easy to add controller support.
|
@@ -0,0 +1 @@
|
|
1
|
+
from . import controller
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import pygame
|
2
|
+
from .controlsbase import ControlsBase
|
3
|
+
from .dualsense_controller import DualSenseController
|
4
|
+
from .dualsense_edge_controller import DualSenseEdgeController
|
5
|
+
from .logitech_f310_controller import LogitechF310Controller
|
6
|
+
from .logitech_f510_controller import LogitechF510Controller
|
7
|
+
from .logitech_f710_controller import LogitechF710Controller
|
8
|
+
from .xbox_series_x_controller import XboxSeriesXController
|
9
|
+
from .generic_controller import GenericController
|
10
|
+
from .logitech_dual_action_controller import LogitechDualActionController
|
11
|
+
|
12
|
+
__version__ = "0.0.4"
|
13
|
+
|
14
|
+
CONTROLLERS = {
|
15
|
+
"DualSense Wireless Controller": DualSenseController,
|
16
|
+
"DualSense Edge Wireless Controller": DualSenseEdgeController,
|
17
|
+
"Logitech Gamepad F310": LogitechF310Controller,
|
18
|
+
"Logitech Gamepad F510": LogitechF510Controller,
|
19
|
+
"Logitech Gamepad F710": LogitechF710Controller,
|
20
|
+
"Logitech Dual Action": LogitechDualActionController,
|
21
|
+
"X box Series X Controller": XboxSeriesXController
|
22
|
+
}
|
23
|
+
|
24
|
+
class Controllers:
|
25
|
+
def __init__(self, joy):
|
26
|
+
self.controllers = []
|
27
|
+
if not joy.get_name() in CONTROLLERS:
|
28
|
+
self.controllers.append(GenericController(joy))
|
29
|
+
else:
|
30
|
+
self.controllers.append(CONTROLLERS[joy.get_name()](joy))
|
31
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
"""
|
2
|
+
This is an abstract baseclass for the controls of snake.
|
3
|
+
"""
|
4
|
+
from abc import ABC, abstractmethod
|
5
|
+
|
6
|
+
class ControlsBase(ABC):
|
7
|
+
@abstractmethod
|
8
|
+
def handle_input(self, event):
|
9
|
+
pass
|
10
|
+
|
11
|
+
@abstractmethod
|
12
|
+
def left(self):
|
13
|
+
pass
|
14
|
+
|
15
|
+
@abstractmethod
|
16
|
+
def right(self):
|
17
|
+
pass
|
18
|
+
|
19
|
+
@abstractmethod
|
20
|
+
def up(self):
|
21
|
+
pass
|
22
|
+
|
23
|
+
@abstractmethod
|
24
|
+
def down(self):
|
25
|
+
pass
|
26
|
+
|
27
|
+
@abstractmethod
|
28
|
+
def pause(self):
|
29
|
+
pass
|
30
|
+
|
31
|
+
@abstractmethod
|
32
|
+
def rumble(self):
|
33
|
+
pass
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import os
|
2
|
+
import time
|
3
|
+
import numpy as np
|
4
|
+
import sounddevice as sd
|
5
|
+
import alsaaudio
|
6
|
+
import pulsectl
|
7
|
+
|
8
|
+
class DualSenseAudio:
|
9
|
+
def __init__(self):
|
10
|
+
self.alsa_devices = self._get_alsa_devices()
|
11
|
+
self.pulse_devices = self._get_pulseaudio_devices()
|
12
|
+
self.dualsense_device = self._detect_dualsense()
|
13
|
+
|
14
|
+
def _get_alsa_devices(self):
|
15
|
+
try:
|
16
|
+
cards = alsaaudio.cards()
|
17
|
+
return cards
|
18
|
+
except Exception as e:
|
19
|
+
print("ALSA detection failed:", e)
|
20
|
+
return []
|
21
|
+
|
22
|
+
def _get_pulseaudio_devices(self):
|
23
|
+
try:
|
24
|
+
pulse = pulsectl.Pulse("dualsense-audio")
|
25
|
+
sinks = pulse.sink_list()
|
26
|
+
return sinks
|
27
|
+
except Exception as e:
|
28
|
+
print("PulseAudio detection failed:", e)
|
29
|
+
return []
|
30
|
+
|
31
|
+
def _detect_dualsense(self):
|
32
|
+
# Check ALSA names
|
33
|
+
for card in self.alsa_devices:
|
34
|
+
if "DualSense" in card:
|
35
|
+
return {'type': 'alsa', 'name': card}
|
36
|
+
|
37
|
+
# Check PulseAudio sinks
|
38
|
+
for sink in self.pulse_devices:
|
39
|
+
if "dualsense" in sink.description.lower():
|
40
|
+
return {'type': 'pulse', 'name': sink.name}
|
41
|
+
|
42
|
+
return None
|
43
|
+
|
44
|
+
def play_tone(self, frequency=440.0, duration=2.0, volume=0.5):
|
45
|
+
if not self.dualsense_device:
|
46
|
+
print("DualSense speaker not found.")
|
47
|
+
return
|
48
|
+
|
49
|
+
print(f"Playing tone on DualSense ({self.dualsense_device['type']})...")
|
50
|
+
|
51
|
+
fs = 48000 # Sample rate
|
52
|
+
t = np.linspace(0, duration, int(fs * duration), False)
|
53
|
+
tone = np.sin(frequency * 2 * np.pi * t) * volume
|
54
|
+
audio = tone.astype(np.float32)
|
55
|
+
|
56
|
+
if self.dualsense_device['type'] == 'pulse':
|
57
|
+
sd.play(audio, samplerate=fs, device=self.dualsense_device['name'])
|
58
|
+
elif self.dualsense_device['type'] == 'alsa':
|
59
|
+
device_index = self.alsa_devices.index(self.dualsense_device['name'])
|
60
|
+
sd.play(audio, samplerate=fs, device=device_index)
|
61
|
+
sd.wait()
|
62
|
+
|
63
|
+
def list_devices(self):
|
64
|
+
print("ALSA Devices:")
|
65
|
+
for card in self.alsa_devices:
|
66
|
+
print(f" - {card}")
|
67
|
+
print("\nPulseAudio Devices:")
|
68
|
+
for sink in self.pulse_devices:
|
69
|
+
print(f" - {sink.name} ({sink.description})")
|
70
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
from pygameControls.controlsbase import ControlsBase
|
2
|
+
from pydualsense import *
|
3
|
+
|
4
|
+
BATTERY_STATE = {
|
5
|
+
"0": "Discharging",
|
6
|
+
"1": "Charging",
|
7
|
+
"2": "Full",
|
8
|
+
"11": "Not charging",
|
9
|
+
"15": "Error",
|
10
|
+
"10": "Temp or voltage out of range"
|
11
|
+
}
|
12
|
+
|
13
|
+
class DualSenseController(ControlsBase):
|
14
|
+
def __init__(self, joy):
|
15
|
+
self.device = pydualsense()
|
16
|
+
self.device.init()
|
17
|
+
self.name = self.device.device.get_product_string()
|
18
|
+
self.powerlevel = self.device.battery.Level
|
19
|
+
self.batterystate = BATTERY_STATE[str(self.device.battery.State)]
|
20
|
+
self.set_player_id(PlayerID.PLAYER_1)
|
21
|
+
print(f"{self.name} connected")
|
22
|
+
print(f"Power level: {self.powerlevel}")
|
23
|
+
print(f"Battery state: {self.batterystate}")
|
24
|
+
|
25
|
+
def handle_input(self, event):
|
26
|
+
pass
|
27
|
+
|
28
|
+
def set_led(self, red: int, green: int, blue: int):
|
29
|
+
self.device.light.setColorI(red, green, blue)
|
30
|
+
|
31
|
+
def set_player_id(self, playerid: PlayerID):
|
32
|
+
self.device.light.setPlayerID(playerid)
|
33
|
+
|
34
|
+
def left(self):
|
35
|
+
pass
|
36
|
+
|
37
|
+
def right(self):
|
38
|
+
pass
|
39
|
+
|
40
|
+
def up(self):
|
41
|
+
pass
|
42
|
+
|
43
|
+
def down(self):
|
44
|
+
pass
|
45
|
+
|
46
|
+
def pause(self):
|
47
|
+
pass
|
48
|
+
|
49
|
+
def rumble(self):
|
50
|
+
pass
|
51
|
+
|
52
|
+
@property
|
53
|
+
def name(self) -> str:
|
54
|
+
return self._name
|
55
|
+
|
56
|
+
@name.setter
|
57
|
+
def name(self, name: str) -> None:
|
58
|
+
self._name = name
|
59
|
+
|
60
|
+
@property
|
61
|
+
def powerlevel(self) -> str:
|
62
|
+
return self._powerlevel
|
63
|
+
|
64
|
+
@powerlevel.setter
|
65
|
+
def powerlevel(self, lvl: str) -> None:
|
66
|
+
self._powerlevel = lvl
|
67
|
+
|
68
|
+
@property
|
69
|
+
def batterystate(self) -> int:
|
70
|
+
return self._batterystate
|
71
|
+
|
72
|
+
@batterystate.setter
|
73
|
+
def batterystate(self, state) -> None:
|
74
|
+
self._batterystate = state
|
@@ -0,0 +1,199 @@
|
|
1
|
+
import time
|
2
|
+
import threading
|
3
|
+
import numpy as np
|
4
|
+
import sounddevice as sd
|
5
|
+
import alsaaudio
|
6
|
+
import pulsectl
|
7
|
+
from pydualsense import *
|
8
|
+
|
9
|
+
|
10
|
+
class DualSenseEdgeController:
|
11
|
+
def __init__(self):
|
12
|
+
# DualSense input/output interface
|
13
|
+
self.ds = pydualsense()
|
14
|
+
self.ds.init()
|
15
|
+
self._listening = False
|
16
|
+
self._bindings = {}
|
17
|
+
|
18
|
+
# Audio detection
|
19
|
+
self.alsa_devices = self._get_alsa_devices()
|
20
|
+
self.pulse_devices = self._get_pulseaudio_devices()
|
21
|
+
self.dualsense_audio_device = self._detect_dualsense_audio()
|
22
|
+
|
23
|
+
print("DualSense initialized.")
|
24
|
+
|
25
|
+
# ---------------------- Device Controls ----------------------
|
26
|
+
|
27
|
+
def set_rumble(self, small_motor: int, big_motor: int):
|
28
|
+
self.ds.setRumble(small_motor, big_motor)
|
29
|
+
|
30
|
+
def stop_rumble(self):
|
31
|
+
self.set_rumble(0, 0)
|
32
|
+
|
33
|
+
def set_led_color(self, r: int, g: int, b: int):
|
34
|
+
self.ds.setLightBarColor(r, g, b)
|
35
|
+
|
36
|
+
def set_trigger_effects(self, left_mode='Off', right_mode='Off', force=0):
|
37
|
+
left = getattr(TriggerModes, left_mode.upper(), TriggerModes.Off)
|
38
|
+
right = getattr(TriggerModes, right_mode.upper(), TriggerModes.Off)
|
39
|
+
self.ds.triggerL.setMode(left)
|
40
|
+
self.ds.triggerR.setMode(right)
|
41
|
+
if force > 0:
|
42
|
+
self.ds.triggerL.setForce(force)
|
43
|
+
self.ds.triggerR.setForce(force)
|
44
|
+
|
45
|
+
# ---------------------- Predefined Rumble Patterns ----------------------
|
46
|
+
|
47
|
+
def rumble_pattern(self, pattern: str, duration: float = 1.0):
|
48
|
+
patterns = {
|
49
|
+
"pulse": self._pulse_rumble,
|
50
|
+
"heartbeat": self._heartbeat_rumble,
|
51
|
+
"buzz": self._buzz_rumble,
|
52
|
+
"wave": self._wave_rumble,
|
53
|
+
"alarm": self._alarm_rumble,
|
54
|
+
}
|
55
|
+
if pattern in patterns:
|
56
|
+
threading.Thread(target=patterns[pattern], args=(duration,), daemon=True).start()
|
57
|
+
else:
|
58
|
+
print(f"Unknown rumble pattern: {pattern}")
|
59
|
+
|
60
|
+
def _pulse_rumble(self, duration):
|
61
|
+
end = time.time() + duration
|
62
|
+
while time.time() < end:
|
63
|
+
self.set_rumble(50, 150)
|
64
|
+
time.sleep(0.2)
|
65
|
+
self.stop_rumble()
|
66
|
+
time.sleep(0.2)
|
67
|
+
|
68
|
+
def _heartbeat_rumble(self, duration):
|
69
|
+
end = time.time() + duration
|
70
|
+
while time.time() < end:
|
71
|
+
self.set_rumble(200, 200)
|
72
|
+
time.sleep(0.1)
|
73
|
+
self.stop_rumble()
|
74
|
+
time.sleep(0.1)
|
75
|
+
self.set_rumble(100, 100)
|
76
|
+
time.sleep(0.1)
|
77
|
+
self.stop_rumble()
|
78
|
+
time.sleep(0.4)
|
79
|
+
|
80
|
+
def _buzz_rumble(self, duration):
|
81
|
+
self.set_rumble(80, 255)
|
82
|
+
time.sleep(duration)
|
83
|
+
self.stop_rumble()
|
84
|
+
|
85
|
+
def _wave_rumble(self, duration):
|
86
|
+
start = time.time()
|
87
|
+
while time.time() - start < duration:
|
88
|
+
for i in range(0, 256, 25):
|
89
|
+
self.set_rumble(i, 255 - i)
|
90
|
+
time.sleep(0.05)
|
91
|
+
for i in reversed(range(0, 256, 25)):
|
92
|
+
self.set_rumble(i, 255 - i)
|
93
|
+
time.sleep(0.05)
|
94
|
+
self.stop_rumble()
|
95
|
+
|
96
|
+
def _alarm_rumble(self, duration):
|
97
|
+
end = time.time() + duration
|
98
|
+
while time.time() < end:
|
99
|
+
self.set_rumble(255, 0)
|
100
|
+
time.sleep(0.1)
|
101
|
+
self.set_rumble(0, 255)
|
102
|
+
time.sleep(0.1)
|
103
|
+
self.stop_rumble()
|
104
|
+
|
105
|
+
# ---------------------- Input Listener + Bindings ----------------------
|
106
|
+
|
107
|
+
def bind(self, button: str, action: callable):
|
108
|
+
"""Bind a button to a callable. Ex: controller.bind('cross', lambda: rumble_pattern('buzz'))"""
|
109
|
+
self._bindings[button] = action
|
110
|
+
|
111
|
+
def start_input_listener(self):
|
112
|
+
def listen():
|
113
|
+
while self._listening:
|
114
|
+
#self.ds.update()
|
115
|
+
for button, action in self._bindings.items():
|
116
|
+
if getattr(self.ds, button, False):
|
117
|
+
action()
|
118
|
+
self._listening = True
|
119
|
+
thread = threading.Thread(target=listen, daemon=True)
|
120
|
+
thread.start()
|
121
|
+
|
122
|
+
def stop_input_listener(self):
|
123
|
+
self._listening = False
|
124
|
+
|
125
|
+
# ---------------------- Audio Output ----------------------
|
126
|
+
|
127
|
+
def _get_alsa_devices(self):
|
128
|
+
try:
|
129
|
+
return alsaaudio.cards()
|
130
|
+
except Exception:
|
131
|
+
return []
|
132
|
+
|
133
|
+
def _get_pulseaudio_devices(self):
|
134
|
+
try:
|
135
|
+
pulse = pulsectl.Pulse("dualsense-audio")
|
136
|
+
return pulse.sink_list()
|
137
|
+
except Exception:
|
138
|
+
return []
|
139
|
+
|
140
|
+
def _detect_dualsense_audio(self):
|
141
|
+
# Check ALSA names
|
142
|
+
for card in self.alsa_devices:
|
143
|
+
if "DualSense" in card:
|
144
|
+
return {'type': 'alsa', 'name': card}
|
145
|
+
|
146
|
+
# Check PulseAudio sinks
|
147
|
+
for sink in self.pulse_devices:
|
148
|
+
if "dualsense" in sink.description.lower():
|
149
|
+
return {'type': 'pulse', 'name': sink.name}
|
150
|
+
|
151
|
+
return None
|
152
|
+
|
153
|
+
def play_tone(self, frequency=440.0, duration=2.0, volume=0.5):
|
154
|
+
if not self.dualsense_audio_device:
|
155
|
+
print("DualSense speaker not detected.")
|
156
|
+
return
|
157
|
+
|
158
|
+
print(f"Playing tone on DualSense ({self.dualsense_audio_device['type']})...")
|
159
|
+
|
160
|
+
fs = 48000 # Sample rate
|
161
|
+
t = np.linspace(0, duration, int(fs * duration), False)
|
162
|
+
tone = np.sin(frequency * 2 * np.pi * t) * volume
|
163
|
+
audio = tone.astype(np.float32)
|
164
|
+
|
165
|
+
try:
|
166
|
+
if self.dualsense_audio_device['type'] == 'pulse':
|
167
|
+
sd.play(audio, samplerate=fs, device=self.dualsense_audio_device['name'])
|
168
|
+
elif self.dualsense_audio_device['type'] == 'alsa':
|
169
|
+
device_index = self.alsa_devices.index(self.dualsense_audio_device['name'])
|
170
|
+
sd.play(audio, samplerate=fs, device=device_index)
|
171
|
+
sd.wait()
|
172
|
+
except Exception as e:
|
173
|
+
print("Failed to play tone:", e)
|
174
|
+
|
175
|
+
def list_audio_devices(self):
|
176
|
+
print("ALSA Devices:")
|
177
|
+
for card in self.alsa_devices:
|
178
|
+
print(f" - {card}")
|
179
|
+
print("\nPulseAudio Devices:")
|
180
|
+
for sink in self.pulse_devices:
|
181
|
+
print(f" - {sink.name} ({sink.description})")
|
182
|
+
|
183
|
+
# ---------------------- Cleanup ----------------------
|
184
|
+
|
185
|
+
def close(self):
|
186
|
+
self.ds.close()
|
187
|
+
|
188
|
+
if __name__ == "__main__":
|
189
|
+
|
190
|
+
controller = DualSenseController()
|
191
|
+
|
192
|
+
# Bind buttons to patterns
|
193
|
+
controller.bind("cross", lambda: controller.rumble_pattern("heartbeat", 1.5))
|
194
|
+
controller.bind("circle", lambda: controller.rumble_pattern("buzz", 0.5))
|
195
|
+
controller.bind("triangle", lambda: controller.rumble_pattern("pulse", 2))
|
196
|
+
controller.bind("square", lambda: controller.set_led_color(255, 0, 0))
|
197
|
+
|
198
|
+
# Start listening
|
199
|
+
controller.start_input_listener()
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import pygame
|
2
|
+
from pygameControls.controlsbase import ControlsBase
|
3
|
+
|
4
|
+
class GenericController(ControlsBase):
|
5
|
+
def __init__(self, joy):
|
6
|
+
self.device = joy
|
7
|
+
self.instance_id: int = self.device.get_instance_id()
|
8
|
+
self.name = self.device.get_name()
|
9
|
+
self.guid = self.device.get_guid()
|
10
|
+
self.numaxis: int = self.device.get_numaxes()
|
11
|
+
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
|
12
|
+
self.numhats: int = self.device.get_numhats()
|
13
|
+
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
|
14
|
+
self.numbuttons: int = self.device.get_numbuttons()
|
15
|
+
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
|
16
|
+
|
17
|
+
def handle_input(self, event):
|
18
|
+
pass
|
19
|
+
|
20
|
+
def left(self):
|
21
|
+
pass
|
22
|
+
|
23
|
+
def right(self):
|
24
|
+
pass
|
25
|
+
|
26
|
+
def up(self):
|
27
|
+
pass
|
28
|
+
|
29
|
+
def down(self):
|
30
|
+
pass
|
31
|
+
|
32
|
+
def pause(self):
|
33
|
+
pass
|
34
|
+
|
35
|
+
def rumble(self):
|
36
|
+
pass
|
37
|
+
|
38
|
+
@property
|
39
|
+
def name(self) -> str:
|
40
|
+
return self._name
|
41
|
+
|
42
|
+
@name.setter
|
43
|
+
def name(self, name: str) -> None:
|
44
|
+
self._name = name
|
45
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
"""
|
2
|
+
Logitech F310 Controller class.
|
3
|
+
This controller is a usb controller, with the following features.
|
4
|
+
(XInput mode)
|
5
|
+
6 axis
|
6
|
+
11 buttons
|
7
|
+
1 hat
|
8
|
+
|
9
|
+
(DirectInput mode)
|
10
|
+
4 axis
|
11
|
+
12 buttons
|
12
|
+
1 hat
|
13
|
+
"""
|
14
|
+
|
15
|
+
import pygame
|
16
|
+
from pygameControls.controlsbase import ControlsBase
|
17
|
+
from enum import Enum
|
18
|
+
|
19
|
+
class InputMode(Enum):
|
20
|
+
DirectInput = 1
|
21
|
+
XInput = 2
|
22
|
+
|
23
|
+
class LogitechDualActionController(ControlsBase):
|
24
|
+
def __init__(self, joy):
|
25
|
+
self.device = joy
|
26
|
+
self.instance_id: int = self.device.get_instance_id()
|
27
|
+
self.name = self.device.get_name()
|
28
|
+
self.guid = self.device.get_guid()
|
29
|
+
self.powerlevel = self.device.get_power_level()
|
30
|
+
self.numaxis: int = self.device.get_numaxes()
|
31
|
+
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
|
32
|
+
self.numhats: int = self.device.get_numhats()
|
33
|
+
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
|
34
|
+
self.numbuttons: int = self.device.get_numbuttons()
|
35
|
+
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
|
36
|
+
self.input_mode = InputMode.DirectInput
|
37
|
+
|
38
|
+
def handle_input(self, event):
|
39
|
+
pass
|
40
|
+
|
41
|
+
def left(self):
|
42
|
+
pass
|
43
|
+
|
44
|
+
def right(self):
|
45
|
+
pass
|
46
|
+
|
47
|
+
def up(self):
|
48
|
+
pass
|
49
|
+
|
50
|
+
def down(self):
|
51
|
+
pass
|
52
|
+
|
53
|
+
def pause(self):
|
54
|
+
pass
|
55
|
+
|
56
|
+
def rumble(self):
|
57
|
+
pass
|
58
|
+
|
59
|
+
@property
|
60
|
+
def name(self) -> str:
|
61
|
+
return self._name
|
62
|
+
|
63
|
+
@name.setter
|
64
|
+
def name(self, name: str) -> None:
|
65
|
+
self._name = name
|
66
|
+
|
67
|
+
@property
|
68
|
+
def input_mode(self) -> int:
|
69
|
+
return self._inputmode
|
70
|
+
|
71
|
+
@input_mode.setter
|
72
|
+
def input_mode(self, mode: int) -> None:
|
73
|
+
self._inputmode = mode
|
74
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
"""
|
2
|
+
Logitech F310 Controller class.
|
3
|
+
This controller is a usb controller, with the following features.
|
4
|
+
(XInput mode)
|
5
|
+
6 axis
|
6
|
+
11 buttons
|
7
|
+
1 hat
|
8
|
+
|
9
|
+
(DirectInput mode)
|
10
|
+
4 axis
|
11
|
+
12 buttons
|
12
|
+
1 hat
|
13
|
+
"""
|
14
|
+
|
15
|
+
import pygame
|
16
|
+
from pygameControls.controlsbase import ControlsBase
|
17
|
+
from enum import Enum
|
18
|
+
|
19
|
+
class InputMode(Enum):
|
20
|
+
DirectInput = 1
|
21
|
+
XInput = 2
|
22
|
+
|
23
|
+
class LogitechF310Controller(ControlsBase):
|
24
|
+
def __init__(self, joy):
|
25
|
+
self.device = joy
|
26
|
+
self.instance_id: int = self.device.get_instance_id()
|
27
|
+
self.name = self.device.get_name()
|
28
|
+
self.guid = self.device.get_guid()
|
29
|
+
self.powerlevel = self.device.get_power_level()
|
30
|
+
self.numaxis: int = self.device.get_numaxes()
|
31
|
+
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
|
32
|
+
self.numhats: int = self.device.get_numhats()
|
33
|
+
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
|
34
|
+
self.numbuttons: int = self.device.get_numbuttons()
|
35
|
+
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
|
36
|
+
self.input_mode = InputMode.XInput
|
37
|
+
|
38
|
+
def handle_input(self, event):
|
39
|
+
pass
|
40
|
+
|
41
|
+
def left(self):
|
42
|
+
pass
|
43
|
+
|
44
|
+
def right(self):
|
45
|
+
pass
|
46
|
+
|
47
|
+
def up(self):
|
48
|
+
pass
|
49
|
+
|
50
|
+
def down(self):
|
51
|
+
pass
|
52
|
+
|
53
|
+
def pause(self):
|
54
|
+
pass
|
55
|
+
|
56
|
+
def rumble(self):
|
57
|
+
pass
|
58
|
+
|
59
|
+
@property
|
60
|
+
def name(self) -> str:
|
61
|
+
return self._name
|
62
|
+
|
63
|
+
@name.setter
|
64
|
+
def name(self, name: str) -> None:
|
65
|
+
self._name = name
|
66
|
+
|
67
|
+
@property
|
68
|
+
def input_mode(self) -> int:
|
69
|
+
return self._inputmode
|
70
|
+
|
71
|
+
@input_mode.setter
|
72
|
+
def input_mode(self, mode: int) -> None:
|
73
|
+
self._inputmode = mode
|
74
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
"""
|
2
|
+
Logitech F310 Controller class.
|
3
|
+
This controller is a usb controller, with the following features.
|
4
|
+
(XInput mode)
|
5
|
+
6 axis
|
6
|
+
11 buttons
|
7
|
+
1 hat
|
8
|
+
|
9
|
+
(DirectInput mode)
|
10
|
+
4 axis
|
11
|
+
12 buttons
|
12
|
+
1 hat
|
13
|
+
"""
|
14
|
+
|
15
|
+
import pygame
|
16
|
+
from pygameControls.controlsbase import ControlsBase
|
17
|
+
from enum import Enum
|
18
|
+
|
19
|
+
class InputMode(Enum):
|
20
|
+
DirectInput = 1
|
21
|
+
XInput = 2
|
22
|
+
|
23
|
+
class ConnectionType(Enum):
|
24
|
+
WIRED = 1
|
25
|
+
WIRELESS = 2
|
26
|
+
|
27
|
+
class LogitechF510Controller(ControlsBase):
|
28
|
+
def __init__(self, joy):
|
29
|
+
self.device = joy
|
30
|
+
self.instance_id: int = self.device.get_instance_id()
|
31
|
+
self.name = self.device.get_name()
|
32
|
+
self.numaxis: int = self.device.get_numaxis()
|
33
|
+
self.axis: list = []
|
34
|
+
self.numhats: int = self.device.get_numhats()
|
35
|
+
self.hats: list = []
|
36
|
+
self.numbuttons: int = self.device.get_numbuttons()
|
37
|
+
self.buttons: list = []
|
38
|
+
self.input_mode: InputMode.DirectInput
|
39
|
+
self.input_connection: ConnectionType.WIRED
|
40
|
+
|
41
|
+
def handle_input(self, event):
|
42
|
+
pass
|
43
|
+
|
44
|
+
def left(self):
|
45
|
+
pass
|
46
|
+
|
47
|
+
def right(self):
|
48
|
+
pass
|
49
|
+
|
50
|
+
def up(self):
|
51
|
+
pass
|
52
|
+
|
53
|
+
def down(self):
|
54
|
+
pass
|
55
|
+
|
56
|
+
def pause(self):
|
57
|
+
pass
|
58
|
+
|
59
|
+
def rumble(self):
|
60
|
+
pass
|
61
|
+
|
62
|
+
@property
|
63
|
+
def name(self) -> str:
|
64
|
+
return self._name
|
65
|
+
|
66
|
+
@name.setter
|
67
|
+
def name(self, name: str) -> None:
|
68
|
+
self._name = name
|
69
|
+
|
70
|
+
@property
|
71
|
+
def axis(self) -> list:
|
72
|
+
return self._axis
|
73
|
+
|
74
|
+
@axis.setter
|
75
|
+
def axis(self) -> None:
|
76
|
+
self._axis = [self.device.get_axis(a) for a in range(self.numaxis)]
|
77
|
+
|
78
|
+
@property
|
79
|
+
def hats(self) -> list:
|
80
|
+
return self._hats
|
81
|
+
|
82
|
+
@hats.setter
|
83
|
+
def hats(self) -> None:
|
84
|
+
self.hats = [self.device.get_hats(h) for h in range(self.numhats)]
|
85
|
+
|
86
|
+
@property
|
87
|
+
def buttons(self) -> list:
|
88
|
+
return self._buttons
|
89
|
+
|
90
|
+
@buttons.setter
|
91
|
+
def buttons(self) -> None:
|
92
|
+
self._buttons = [self.device.get_buttons(b) for b in range(self.numbuttons)]
|
93
|
+
|
94
|
+
@property
|
95
|
+
def input_mode(self) -> int:
|
96
|
+
return self._inputmode
|
97
|
+
|
98
|
+
@input_mode.setter
|
99
|
+
def input_mode(self, mode: int) -> None:
|
100
|
+
self._inputmode = mode
|
101
|
+
|
102
|
+
@property
|
103
|
+
def input_connection(self) -> int:
|
104
|
+
return self._input_connection
|
105
|
+
|
106
|
+
@input_connection.setter
|
107
|
+
def input_connection(self, conn: int) -> None:
|
108
|
+
self._input_connection = conn
|
@@ -0,0 +1,108 @@
|
|
1
|
+
"""
|
2
|
+
Logitech F310 Controller class.
|
3
|
+
This controller is a usb controller, with the following features.
|
4
|
+
(XInput mode)
|
5
|
+
6 axis
|
6
|
+
11 buttons
|
7
|
+
1 hat
|
8
|
+
|
9
|
+
(DirectInput mode)
|
10
|
+
4 axis
|
11
|
+
12 buttons
|
12
|
+
1 hat
|
13
|
+
"""
|
14
|
+
|
15
|
+
import pygame
|
16
|
+
from pygameControls.controlsbase import ControlsBase
|
17
|
+
from enum import Enum
|
18
|
+
|
19
|
+
class InputMode(Enum):
|
20
|
+
DirectInput = 1
|
21
|
+
XInput = 2
|
22
|
+
|
23
|
+
class ConnectionType(Enum):
|
24
|
+
WIRED = 1
|
25
|
+
WIRELESS = 2
|
26
|
+
|
27
|
+
class LogitechF710Controller(ControlsBase):
|
28
|
+
def __init__(self, joy):
|
29
|
+
self.device = joy
|
30
|
+
self.instance_id: int = self.device.get_instance_id()
|
31
|
+
self.name = self.device.get_name()
|
32
|
+
self.numaxis: int = self.device.get_numaxis()
|
33
|
+
self.axis: list = []
|
34
|
+
self.numhats: int = self.device.get_numhats()
|
35
|
+
self.hats: list = []
|
36
|
+
self.numbuttons: int = self.device.get_numbuttons()
|
37
|
+
self.buttons: list = []
|
38
|
+
self.input_mode: InputMode.DirectInput
|
39
|
+
self.input_connection: ConnectionType.WIRED
|
40
|
+
|
41
|
+
def handle_input(self, event):
|
42
|
+
pass
|
43
|
+
|
44
|
+
def left(self):
|
45
|
+
pass
|
46
|
+
|
47
|
+
def right(self):
|
48
|
+
pass
|
49
|
+
|
50
|
+
def up(self):
|
51
|
+
pass
|
52
|
+
|
53
|
+
def down(self):
|
54
|
+
pass
|
55
|
+
|
56
|
+
def pause(self):
|
57
|
+
pass
|
58
|
+
|
59
|
+
def rumble(self):
|
60
|
+
pass
|
61
|
+
|
62
|
+
@property
|
63
|
+
def name(self) -> str:
|
64
|
+
return self._name
|
65
|
+
|
66
|
+
@name.setter
|
67
|
+
def name(self, name: str) -> None:
|
68
|
+
self._name = name
|
69
|
+
|
70
|
+
@property
|
71
|
+
def axis(self) -> list:
|
72
|
+
return self._axis
|
73
|
+
|
74
|
+
@axis.setter
|
75
|
+
def axis(self) -> None:
|
76
|
+
self._axis = [self.device.get_axis(a) for a in range(self.numaxis)]
|
77
|
+
|
78
|
+
@property
|
79
|
+
def hats(self) -> list:
|
80
|
+
return self._hats
|
81
|
+
|
82
|
+
@hats.setter
|
83
|
+
def hats(self) -> None:
|
84
|
+
self.hats = [self.device.get_hats(h) for h in range(self.numhats)]
|
85
|
+
|
86
|
+
@property
|
87
|
+
def buttons(self) -> list:
|
88
|
+
return self._buttons
|
89
|
+
|
90
|
+
@buttons.setter
|
91
|
+
def buttons(self) -> None:
|
92
|
+
self._buttons = [self.device.get_buttons(b) for b in range(self.numbuttons)]
|
93
|
+
|
94
|
+
@property
|
95
|
+
def input_mode(self) -> int:
|
96
|
+
return self._inputmode
|
97
|
+
|
98
|
+
@input_mode.setter
|
99
|
+
def input_mode(self, mode: int) -> None:
|
100
|
+
self._inputmode = mode
|
101
|
+
|
102
|
+
@property
|
103
|
+
def input_connection(self) -> int:
|
104
|
+
return self._input_connection
|
105
|
+
|
106
|
+
@input_connection.setter
|
107
|
+
def input_connection(self, conn: int) -> None:
|
108
|
+
self._input_connection = conn
|
@@ -0,0 +1,45 @@
|
|
1
|
+
import time
|
2
|
+
import threading
|
3
|
+
|
4
|
+
class XboxSeriesXController:
|
5
|
+
def __init__(self, joy):
|
6
|
+
self.device = joy
|
7
|
+
self.instance_id: int = self.device.get_instance_id()
|
8
|
+
self.name = self.device.get_name()
|
9
|
+
self.guid = self.device.get_guid()
|
10
|
+
self.numaxis: int = self.device.get_numaxes()
|
11
|
+
self.axis: list = [self.device.get_axis(a) for a in range(self.numaxis)]
|
12
|
+
self.numhats: int = self.device.get_numhats()
|
13
|
+
self.hats: list = [self.device.get_hat(h) for h in range(self.numhats)]
|
14
|
+
self.numbuttons: int = self.device.get_numbuttons()
|
15
|
+
self.buttons: list = [self.device.get_button(b) for b in range(self.numbuttons)]
|
16
|
+
|
17
|
+
def handle_input(self, event):
|
18
|
+
pass
|
19
|
+
|
20
|
+
def left(self):
|
21
|
+
pass
|
22
|
+
|
23
|
+
def right(self):
|
24
|
+
pass
|
25
|
+
|
26
|
+
def up(self):
|
27
|
+
pass
|
28
|
+
|
29
|
+
def down(self):
|
30
|
+
pass
|
31
|
+
|
32
|
+
def pause(self):
|
33
|
+
pass
|
34
|
+
|
35
|
+
def rumble(self):
|
36
|
+
pass
|
37
|
+
|
38
|
+
@property
|
39
|
+
def name(self) -> str:
|
40
|
+
return self._name
|
41
|
+
|
42
|
+
@name.setter
|
43
|
+
def name(self, name: str) -> None:
|
44
|
+
self._name = name
|
45
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pygameControls
|
3
|
+
Version: 0.0.4
|
4
|
+
Summary: A simple controller class for pygame.
|
5
|
+
Home-page:
|
6
|
+
Author: Jan Lerking
|
7
|
+
Author-email:
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Operating System :: OS Independent
|
11
|
+
Requires-Python: >=3.12
|
12
|
+
Description-Content-Type: text/markdown
|
13
|
+
License-File: LICENSE
|
14
|
+
Dynamic: author
|
15
|
+
Dynamic: classifier
|
16
|
+
Dynamic: description
|
17
|
+
Dynamic: description-content-type
|
18
|
+
Dynamic: license-file
|
19
|
+
Dynamic: requires-python
|
20
|
+
Dynamic: summary
|
21
|
+
|
22
|
+
# PyGame-Controller
|
23
|
+
|
24
|
+
Small module to make it easy to add controller support.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
LICENSE
|
2
|
+
README.md
|
3
|
+
setup.py
|
4
|
+
pygameControls/__init__.py
|
5
|
+
pygameControls/controller.py
|
6
|
+
pygameControls/controlsbase.py
|
7
|
+
pygameControls/dualsense_audio.py
|
8
|
+
pygameControls/dualsense_controller.py
|
9
|
+
pygameControls/dualsense_edge_controller.py
|
10
|
+
pygameControls/generic_controller.py
|
11
|
+
pygameControls/logitech_dual_action_controller.py
|
12
|
+
pygameControls/logitech_f310_controller.py
|
13
|
+
pygameControls/logitech_f510_controller.py
|
14
|
+
pygameControls/logitech_f710_controller.py
|
15
|
+
pygameControls/xbox_series_x_controller.py
|
16
|
+
pygameControls.egg-info/PKG-INFO
|
17
|
+
pygameControls.egg-info/SOURCES.txt
|
18
|
+
pygameControls.egg-info/dependency_links.txt
|
19
|
+
pygameControls.egg-info/top_level.txt
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
pygameControls
|
@@ -0,0 +1,21 @@
|
|
1
|
+
if __name__ == "__main__":
|
2
|
+
from setuptools import setup, find_packages
|
3
|
+
|
4
|
+
setup(
|
5
|
+
name='pygameControls',
|
6
|
+
version='0.0.4',
|
7
|
+
packages=find_packages(),
|
8
|
+
install_requires=[],
|
9
|
+
author='Jan Lerking',
|
10
|
+
author_email='',
|
11
|
+
description='A simple controller class for pygame.',
|
12
|
+
long_description=open('README.md').read(),
|
13
|
+
long_description_content_type='text/markdown',
|
14
|
+
url='',
|
15
|
+
classifiers=[
|
16
|
+
'Programming Language :: Python :: 3',
|
17
|
+
'License :: OSI Approved :: MIT License',
|
18
|
+
'Operating System :: OS Independent',
|
19
|
+
],
|
20
|
+
python_requires='>=3.12',
|
21
|
+
)
|