dualsense-py 0.3.0__py3-none-any.whl
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.
- dualsense_py/__init__.py +7 -0
- dualsense_py/_version.py +24 -0
- dualsense_py/backends/__init__.py +3 -0
- dualsense_py/backends/backend.py +67 -0
- dualsense_py/backends/device_infos.py +270 -0
- dualsense_py/backends/hidapi/hidapi_backend.py +25 -0
- dualsense_py/backends/hidapi/hidapi_device_info.py +113 -0
- dualsense_py/backends/hidapi/in_report/__init__.py +6 -0
- dualsense_py/backends/hidapi/in_report/bt_01_in_report.py +11 -0
- dualsense_py/backends/hidapi/in_report/bt_31_in_report.py +25 -0
- dualsense_py/backends/hidapi/in_report/enums.py +8 -0
- dualsense_py/backends/hidapi/in_report/exceptions.py +21 -0
- dualsense_py/backends/hidapi/in_report/in_report.py +281 -0
- dualsense_py/backends/hidapi/in_report/usb_01_in_report.py +23 -0
- dualsense_py/backends/hidapi/out_report/__init__.py +4 -0
- dualsense_py/backends/hidapi/out_report/bt_01_out_report.py +8 -0
- dualsense_py/backends/hidapi/out_report/bt_31_out_report.py +70 -0
- dualsense_py/backends/hidapi/out_report/crc32.py +50 -0
- dualsense_py/backends/hidapi/out_report/enums.py +186 -0
- dualsense_py/backends/hidapi/out_report/out_report.py +65 -0
- dualsense_py/backends/hidapi/out_report/usb_01_out_report.py +96 -0
- dualsense_py/backends/hidapi/out_report/utils.py +6 -0
- dualsense_py/backends/sdl3/sdl3_backend.py +37 -0
- dualsense_py/backends/sdl3/sdl3_device_info.py +133 -0
- dualsense_py/change_detection.py +65 -0
- dualsense_py/dual_sense_controller.py +249 -0
- dualsense_py/mapping.py +139 -0
- dualsense_py/py.typed +0 -0
- dualsense_py/readable_value.py +114 -0
- dualsense_py/states/__init__.py +7 -0
- dualsense_py/states/accelerometer.py +7 -0
- dualsense_py/states/battery.py +7 -0
- dualsense_py/states/gyroscope.py +7 -0
- dualsense_py/states/joy_stick.py +6 -0
- dualsense_py/states/orientation.py +7 -0
- dualsense_py/states/touch_finger.py +8 -0
- dualsense_py/states/trigger_feedback.py +7 -0
- dualsense_py/utils.py +26 -0
- dualsense_py-0.3.0.dist-info/METADATA +245 -0
- dualsense_py-0.3.0.dist-info/RECORD +43 -0
- dualsense_py-0.3.0.dist-info/WHEEL +5 -0
- dualsense_py-0.3.0.dist-info/licenses/LICENSE.txt +21 -0
- dualsense_py-0.3.0.dist-info/top_level.txt +1 -0
dualsense_py/__init__.py
ADDED
dualsense_py/_version.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.3.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'gfde1784d8'
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Generic, TypeVar, Any, Type
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from .device_infos import DeviceInfo
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
_DeviceInfoType = TypeVar("_DeviceInfoType", bound=DeviceInfo[Any, Any])
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Backend(ABC, Generic[_DeviceInfoType]):
|
|
13
|
+
"""
|
|
14
|
+
Abstract base class for backend implementations.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
ActiveBackend: Type[Backend[Any]] | None = None
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def _get_available_devices() -> list[_DeviceInfoType]:
|
|
22
|
+
"""
|
|
23
|
+
Open a connection to the device at the specified path.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def _init() -> Type[Backend[_DeviceInfoType]]:
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
@abstractmethod
|
|
33
|
+
def _quit() -> None:
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
__slots__ = ( )
|
|
37
|
+
|
|
38
|
+
@classmethod
|
|
39
|
+
def init(cls) -> None:
|
|
40
|
+
"""
|
|
41
|
+
Initialize the backend.
|
|
42
|
+
"""
|
|
43
|
+
if cls == Backend:
|
|
44
|
+
raise TypeError("Cannot initialize the base Backend class directly.")
|
|
45
|
+
|
|
46
|
+
Backend.ActiveBackend = cls._init()
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def get_available_devices() -> list[_DeviceInfoType]:
|
|
50
|
+
"""
|
|
51
|
+
Open a connection to the device at the specified path.
|
|
52
|
+
"""
|
|
53
|
+
if Backend.ActiveBackend is None:
|
|
54
|
+
raise TypeError("Cannot call get_available_devices() without initializing the backend.")
|
|
55
|
+
|
|
56
|
+
return Backend.ActiveBackend._get_available_devices()
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def quit() -> None:
|
|
60
|
+
"""
|
|
61
|
+
Close the backend.
|
|
62
|
+
"""
|
|
63
|
+
if Backend.ActiveBackend is None:
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
Backend.ActiveBackend._quit()
|
|
67
|
+
Backend.ActiveBackend = None
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import time
|
|
3
|
+
from abc import abstractmethod
|
|
4
|
+
from typing import Generic, TypeVar, Final
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
from ..readable_value import ReadableValue, ButtonValue
|
|
8
|
+
from ..states import (
|
|
9
|
+
Accelerometer,
|
|
10
|
+
Battery,
|
|
11
|
+
Gyroscope,
|
|
12
|
+
JoyStick,
|
|
13
|
+
Orientation,
|
|
14
|
+
TouchFinger,
|
|
15
|
+
TriggerFeedback
|
|
16
|
+
)
|
|
17
|
+
ID = TypeVar("ID")
|
|
18
|
+
T = TypeVar("T")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DeviceInfo(Generic[ID, T]):
|
|
22
|
+
"""
|
|
23
|
+
Class to hold device information.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
"""def __init__(self, id: ID, orig_device_info: T):
|
|
27
|
+
self.id: ID = id
|
|
28
|
+
self.orig_device_info: T = orig_device_info"""
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def open(self):
|
|
32
|
+
"""
|
|
33
|
+
Open a connection to the device at the specified path.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def close(self):
|
|
38
|
+
"""
|
|
39
|
+
Close the connection to the device.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def _read(self):
|
|
44
|
+
"""
|
|
45
|
+
Read data from the device.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def write(self):
|
|
50
|
+
"""
|
|
51
|
+
Write data to the device.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
def set_led(self, r: int, g: int, b: int) -> None:
|
|
56
|
+
"""
|
|
57
|
+
Set the LED color of the device.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
__slots__ = (
|
|
61
|
+
"_orig_device_info",
|
|
62
|
+
"_read_time",
|
|
63
|
+
"_last_read_time",
|
|
64
|
+
"_square",
|
|
65
|
+
"_cross",
|
|
66
|
+
"_circle",
|
|
67
|
+
"_triangle",
|
|
68
|
+
"_dpad_up",
|
|
69
|
+
"_dpad_right",
|
|
70
|
+
"_dpad_down",
|
|
71
|
+
"_dpad_left",
|
|
72
|
+
"_l1",
|
|
73
|
+
"_r1",
|
|
74
|
+
"_l2",
|
|
75
|
+
"_r2",
|
|
76
|
+
"_share",
|
|
77
|
+
"_options",
|
|
78
|
+
"_l3",
|
|
79
|
+
"_r3",
|
|
80
|
+
"_ps",
|
|
81
|
+
"_touch",
|
|
82
|
+
"_mikrophone",
|
|
83
|
+
"_left_joy_stick",
|
|
84
|
+
"_right_joy_stick",
|
|
85
|
+
"_l2_trigger",
|
|
86
|
+
"_r2_trigger",
|
|
87
|
+
"_accelerometer",
|
|
88
|
+
"_gyroscope",
|
|
89
|
+
"_battery",
|
|
90
|
+
"_touch_finger_1",
|
|
91
|
+
"_touch_finger_2",
|
|
92
|
+
"_left_trigger_feedback",
|
|
93
|
+
"_right_trigger_feedback",
|
|
94
|
+
"_orientation",
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def __init__(self, orig_device_info: T):
|
|
98
|
+
self._orig_device_info: Final[T] = orig_device_info
|
|
99
|
+
self._read_time: float = 0.0
|
|
100
|
+
self._last_read_time: float = 0.0
|
|
101
|
+
|
|
102
|
+
self._square: Final[ButtonValue] = ButtonValue()
|
|
103
|
+
self._cross: Final[ButtonValue] = ButtonValue()
|
|
104
|
+
self._circle: Final[ButtonValue] = ButtonValue()
|
|
105
|
+
self._triangle: Final[ButtonValue] = ButtonValue()
|
|
106
|
+
self._dpad_up: Final[ButtonValue] = ButtonValue()
|
|
107
|
+
self._dpad_right: Final[ButtonValue] = ButtonValue()
|
|
108
|
+
self._dpad_down: Final[ButtonValue] = ButtonValue()
|
|
109
|
+
self._dpad_left: Final[ButtonValue] = ButtonValue()
|
|
110
|
+
self._l1: Final[ButtonValue] = ButtonValue()
|
|
111
|
+
self._r1: Final[ButtonValue] = ButtonValue()
|
|
112
|
+
self._l2: Final[ButtonValue] = ButtonValue()
|
|
113
|
+
self._r2: Final[ButtonValue] = ButtonValue()
|
|
114
|
+
self._share: Final[ButtonValue] = ButtonValue()
|
|
115
|
+
self._options: Final[ButtonValue] = ButtonValue()
|
|
116
|
+
self._l3: Final[ButtonValue] = ButtonValue()
|
|
117
|
+
self._r3: Final[ButtonValue] = ButtonValue()
|
|
118
|
+
self._ps: Final[ButtonValue] = ButtonValue()
|
|
119
|
+
self._touch: Final[ButtonValue] = ButtonValue()
|
|
120
|
+
self._mikrophone: Final[ButtonValue] = ButtonValue()
|
|
121
|
+
self._left_joy_stick: Final[ReadableValue[JoyStick]] = ReadableValue[JoyStick](JoyStick())
|
|
122
|
+
self._right_joy_stick: Final[ReadableValue[JoyStick]] = ReadableValue[JoyStick](JoyStick())
|
|
123
|
+
self._l2_trigger: Final[ReadableValue[float]] = ReadableValue[float](0.0)
|
|
124
|
+
self._r2_trigger: Final[ReadableValue[float]] = ReadableValue[float](0.0)
|
|
125
|
+
self._accelerometer: Final[ReadableValue[Accelerometer]] = ReadableValue[Accelerometer](Accelerometer())
|
|
126
|
+
self._gyroscope: Final[ReadableValue[Gyroscope]] = ReadableValue[Gyroscope](Gyroscope())
|
|
127
|
+
self._battery: Final[ReadableValue[Battery]] = ReadableValue[Battery](Battery())
|
|
128
|
+
self._touch_finger_1: Final[ReadableValue[TouchFinger]] = ReadableValue[TouchFinger](TouchFinger())
|
|
129
|
+
self._touch_finger_2: Final[ReadableValue[TouchFinger]] = ReadableValue[TouchFinger](TouchFinger())
|
|
130
|
+
self._left_trigger_feedback: Final[ReadableValue[TriggerFeedback]] = ReadableValue[TriggerFeedback](TriggerFeedback())
|
|
131
|
+
self._right_trigger_feedback: Final[ReadableValue[TriggerFeedback]] = ReadableValue[TriggerFeedback](TriggerFeedback())
|
|
132
|
+
self._orientation: Final[ReadableValue[Orientation]] = ReadableValue[Orientation](Orientation())
|
|
133
|
+
|
|
134
|
+
def before_start(self):
|
|
135
|
+
"""
|
|
136
|
+
Initialize the backend with the device information.
|
|
137
|
+
"""
|
|
138
|
+
pass
|
|
139
|
+
|
|
140
|
+
def read(self):
|
|
141
|
+
"""
|
|
142
|
+
Read data from the device.
|
|
143
|
+
"""
|
|
144
|
+
self._read_time = time.perf_counter() * 1000.0
|
|
145
|
+
self._read()
|
|
146
|
+
self._last_read_time = self._read_time
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def square(self) -> ButtonValue:
|
|
150
|
+
return self._square
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def cross(self) -> ButtonValue:
|
|
154
|
+
return self._cross
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def circle(self) -> ButtonValue:
|
|
158
|
+
return self._circle
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def triangle(self) -> ButtonValue:
|
|
162
|
+
return self._triangle
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def dpad_up(self) -> ButtonValue:
|
|
166
|
+
return self._dpad_up
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def dpad_right(self) -> ButtonValue:
|
|
170
|
+
return self._dpad_right
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def dpad_down(self) -> ButtonValue:
|
|
174
|
+
return self._dpad_down
|
|
175
|
+
|
|
176
|
+
@property
|
|
177
|
+
def dpad_left(self) -> ButtonValue:
|
|
178
|
+
return self._dpad_left
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def l1(self) -> ButtonValue:
|
|
182
|
+
return self._l1
|
|
183
|
+
|
|
184
|
+
@property
|
|
185
|
+
def r1(self) -> ButtonValue:
|
|
186
|
+
return self._r1
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def l2(self) -> ButtonValue:
|
|
190
|
+
return self._l2
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def r2(self) -> ButtonValue:
|
|
194
|
+
return self._r2
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def share(self) -> ButtonValue:
|
|
198
|
+
return self._share
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def options(self) -> ButtonValue:
|
|
202
|
+
return self._options
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def l3(self) -> ButtonValue:
|
|
206
|
+
return self._l3
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def r3(self) -> ButtonValue:
|
|
210
|
+
return self._r3
|
|
211
|
+
|
|
212
|
+
@property
|
|
213
|
+
def ps(self) -> ButtonValue:
|
|
214
|
+
return self._ps
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def touch(self) -> ButtonValue:
|
|
218
|
+
return self._touch
|
|
219
|
+
|
|
220
|
+
@property
|
|
221
|
+
def mikrophone(self) -> ButtonValue:
|
|
222
|
+
return self._mikrophone
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def left_joy_stick(self) -> ReadableValue[JoyStick]:
|
|
226
|
+
return self._left_joy_stick
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def right_joy_stick(self) -> ReadableValue[JoyStick]:
|
|
230
|
+
return self._right_joy_stick
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def l2_trigger(self) -> ReadableValue[float]:
|
|
234
|
+
return self._l2_trigger
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def r2_trigger(self) -> ReadableValue[float]:
|
|
238
|
+
return self._r2_trigger
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def accelerometer(self) -> ReadableValue[Accelerometer]:
|
|
242
|
+
return self._accelerometer
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def gyroscope(self) -> ReadableValue[Gyroscope]:
|
|
246
|
+
return self._gyroscope
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def battery(self) -> ReadableValue[Battery]:
|
|
250
|
+
return self._battery
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
def touch_finger_1(self) -> ReadableValue[TouchFinger]:
|
|
254
|
+
return self._touch_finger_1
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def touch_finger_2(self) -> ReadableValue[TouchFinger]:
|
|
258
|
+
return self._touch_finger_2
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def left_trigger_feedback(self) -> ReadableValue[TriggerFeedback]:
|
|
262
|
+
return self._left_trigger_feedback
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def right_trigger_feedback(self) -> ReadableValue[TriggerFeedback]:
|
|
266
|
+
return self._right_trigger_feedback
|
|
267
|
+
|
|
268
|
+
@property
|
|
269
|
+
def orientation(self) -> ReadableValue[Orientation]:
|
|
270
|
+
return self._orientation
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Type
|
|
3
|
+
|
|
4
|
+
from hidapi_py import get_all_device_infos
|
|
5
|
+
|
|
6
|
+
from .hidapi_device_info import HIDAPIDeviceInfo
|
|
7
|
+
from ..backend import Backend
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
SONY_VENDOR_ID: int = 0x054C
|
|
11
|
+
DS_PRODUCT_ID: int = 0x0CE6
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class HidAPIBackend(Backend[HIDAPIDeviceInfo]):
|
|
15
|
+
@staticmethod
|
|
16
|
+
def _get_available_devices() -> list[HIDAPIDeviceInfo]:
|
|
17
|
+
return [HIDAPIDeviceInfo(hid_device_info) for hid_device_info in get_all_device_infos(SONY_VENDOR_ID, DS_PRODUCT_ID)]
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def _init() -> Type[HidAPIBackend]:
|
|
21
|
+
return HidAPIBackend
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def _quit() -> None:
|
|
25
|
+
pass
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Final
|
|
3
|
+
|
|
4
|
+
from hidapi_py import HidDeviceInfo, HidDevice
|
|
5
|
+
|
|
6
|
+
from ..backend import DeviceInfo
|
|
7
|
+
from .in_report import (
|
|
8
|
+
InReport,
|
|
9
|
+
Usb01InReport,
|
|
10
|
+
Bt01InReport,
|
|
11
|
+
Bt31InReport,
|
|
12
|
+
InReportLength,
|
|
13
|
+
InvalidInReportLengthException,
|
|
14
|
+
)
|
|
15
|
+
from .out_report import OutReport, Usb01OutReport, Bt01OutReport, Bt31OutReport
|
|
16
|
+
from ...mapping import (
|
|
17
|
+
uint8_value_mapping,
|
|
18
|
+
uint8_bit_to_bool,
|
|
19
|
+
create_battery,
|
|
20
|
+
create_touch_finger,
|
|
21
|
+
uint8_to_float,
|
|
22
|
+
create_accelerometer,
|
|
23
|
+
create_gyroscope,
|
|
24
|
+
create_trigger_feedback,
|
|
25
|
+
create_orientation,
|
|
26
|
+
create_joy_stick,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class HIDAPIDeviceInfo(DeviceInfo[str, HidDeviceInfo]):
|
|
31
|
+
__slots__ = (
|
|
32
|
+
"_hid_device",
|
|
33
|
+
"__in_report",
|
|
34
|
+
"__out_report",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def __init__(self, hid_device_info: HidDeviceInfo):
|
|
38
|
+
super().__init__(hid_device_info)
|
|
39
|
+
self._hid_device: Final[HidDevice] = HidDevice(hid_device_info.path)
|
|
40
|
+
self.__in_report: InReport | None = None
|
|
41
|
+
self.__out_report: OutReport | None = None
|
|
42
|
+
|
|
43
|
+
def before_start(self):
|
|
44
|
+
data = self._hid_device.read()
|
|
45
|
+
|
|
46
|
+
match len(data):
|
|
47
|
+
case InReportLength.USB_01:
|
|
48
|
+
self.__in_report = Usb01InReport()
|
|
49
|
+
self.__out_report = Usb01OutReport()
|
|
50
|
+
case InReportLength.BT_31:
|
|
51
|
+
self.__in_report = Bt31InReport()
|
|
52
|
+
self.__out_report = Bt31OutReport()
|
|
53
|
+
case InReportLength.BT_01:
|
|
54
|
+
self.__in_report = Bt01InReport()
|
|
55
|
+
self.__out_report = Bt01OutReport()
|
|
56
|
+
case _:
|
|
57
|
+
raise InvalidInReportLengthException
|
|
58
|
+
|
|
59
|
+
def open(self):
|
|
60
|
+
self._hid_device.open()
|
|
61
|
+
|
|
62
|
+
def close(self):
|
|
63
|
+
self._hid_device.close()
|
|
64
|
+
|
|
65
|
+
def _read(self):
|
|
66
|
+
if self.__in_report is None:
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
self._hid_device.read(self.__in_report.data)
|
|
70
|
+
|
|
71
|
+
self._square.set_value(uint8_bit_to_bool(self.__in_report.buttons_0, InReport.SQUARE_BIT))
|
|
72
|
+
self._cross.set_value(uint8_bit_to_bool(self.__in_report.buttons_0, InReport.CROSS_BIT))
|
|
73
|
+
self._circle.set_value(uint8_bit_to_bool(self.__in_report.buttons_0, InReport.CIRCLE_BIT))
|
|
74
|
+
self._triangle.set_value(uint8_bit_to_bool(self.__in_report.buttons_0, InReport.TRIANGLE_BIT))
|
|
75
|
+
|
|
76
|
+
for readable_value, value in zip(
|
|
77
|
+
[self._dpad_up, self._dpad_right, self._dpad_down, self._dpad_left],
|
|
78
|
+
uint8_value_mapping(self.__in_report.buttons_0 & 0b1111, InReport.DPAD_MAPPING)
|
|
79
|
+
):
|
|
80
|
+
readable_value.set_value(value)
|
|
81
|
+
|
|
82
|
+
self._l1.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.L1_BIT))
|
|
83
|
+
self._r1.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.R1_BIT))
|
|
84
|
+
self._l2.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.L2_BIT))
|
|
85
|
+
self._r2.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.R2_BIT))
|
|
86
|
+
self._share.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.SHARE_BIT))
|
|
87
|
+
self._options.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.OPTIONS_BIT))
|
|
88
|
+
self._l3.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.L3_BIT))
|
|
89
|
+
self._r3.set_value(uint8_bit_to_bool(self.__in_report.buttons_1, InReport.R3_BIT))
|
|
90
|
+
self._ps.set_value(uint8_bit_to_bool(self.__in_report.buttons_2, InReport.PS_BIT))
|
|
91
|
+
self._touch.set_value(uint8_bit_to_bool(self.__in_report.buttons_2, InReport.TOUCH_BIT))
|
|
92
|
+
self._mikrophone.set_value(uint8_bit_to_bool(self.__in_report.buttons_2, InReport.MIKROPHONE_BIT))
|
|
93
|
+
self._left_joy_stick.set_value(create_joy_stick(self.__in_report.axes_0, self.__in_report.axes_1))
|
|
94
|
+
self._right_joy_stick.set_value(create_joy_stick(self.__in_report.axes_2, self.__in_report.axes_3))
|
|
95
|
+
self._l2_trigger.set_value(uint8_to_float(self.__in_report.axes_4, (0.0, 1.0)))
|
|
96
|
+
self._r2_trigger.set_value(uint8_to_float(self.__in_report.axes_5, (0.0, 1.0)))
|
|
97
|
+
self._accelerometer.set_value(create_accelerometer(x_0=self.__in_report.accel_x_0, x_1=self.__in_report.accel_x_1, y_0=self.__in_report.accel_y_0, y_1=self.__in_report.accel_y_1, z_0=self.__in_report.accel_z_0, z_1=self.__in_report.accel_z_1))
|
|
98
|
+
self._gyroscope.set_value(create_gyroscope(x_0=self.__in_report.gyro_x_0, x_1=self.__in_report.gyro_x_1, y_0=self.__in_report.gyro_y_0, y_1=self.__in_report.gyro_y_1, z_0=self.__in_report.gyro_z_0, z_1=self.__in_report.gyro_z_1))
|
|
99
|
+
self._battery.set_value(create_battery(self.__in_report.battery_0, self.__in_report.battery_1))
|
|
100
|
+
self._touch_finger_1.set_value(create_touch_finger(self.__in_report.touch_1_0, self.__in_report.touch_1_1, self.__in_report.touch_1_2, self.__in_report.touch_1_3))
|
|
101
|
+
self._touch_finger_2.set_value(create_touch_finger(self.__in_report.touch_2_0, self.__in_report.touch_2_1, self.__in_report.touch_2_2, self.__in_report.touch_2_3))
|
|
102
|
+
self._left_trigger_feedback.set_value(create_trigger_feedback(self.__in_report.left_trigger_feedback))
|
|
103
|
+
self._right_trigger_feedback.set_value(create_trigger_feedback(self.__in_report.right_trigger_feedback))
|
|
104
|
+
self._orientation.set_value(create_orientation(self._orientation.value, self._accelerometer.value, self._gyroscope.value, (self._read_time - self._last_read_time) if self._last_read_time else 0.0))
|
|
105
|
+
|
|
106
|
+
def write(self):
|
|
107
|
+
"""
|
|
108
|
+
Write data to the device.
|
|
109
|
+
"""
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
def set_led(self, r: int, g: int, b: int) -> None:
|
|
113
|
+
pass
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from .in_report import InReport, BytesLike
|
|
2
|
+
from .bt_01_in_report import Bt01InReport
|
|
3
|
+
from .bt_31_in_report import Bt31InReport
|
|
4
|
+
from .usb_01_in_report import Usb01InReport
|
|
5
|
+
from .enums import InReportLength
|
|
6
|
+
from .exceptions import AbstractBaseException, InvalidDeviceIndexException, InvalidInReportLengthException, NoDeviceDetectedException
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .in_report import InReport, BytesLike
|
|
2
|
+
from .enums import InReportLength
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Bt01InReport(InReport):
|
|
6
|
+
def __init__(self, data: BytesLike = bytearray(InReportLength.BT_01)):
|
|
7
|
+
super().__init__({
|
|
8
|
+
"axes_0": 0, "axes_1": 1, "axes_2": 2, "axes_3": 3,
|
|
9
|
+
"buttons_0": 4, "buttons_1": 5, "buttons_2": 6,
|
|
10
|
+
"axes_4": 7, "axes_5": 8
|
|
11
|
+
}, data=data)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .in_report import InReport, BytesLike
|
|
2
|
+
from .enums import InReportLength
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# ??? byte 0
|
|
6
|
+
# ??? byte 7?
|
|
7
|
+
# ??? byte 11
|
|
8
|
+
# ??? bytes 28-32
|
|
9
|
+
# ??? byte 41
|
|
10
|
+
# ??? bytes 44-52
|
|
11
|
+
# ??? bytes 55-76
|
|
12
|
+
class Bt31InReport(InReport):
|
|
13
|
+
|
|
14
|
+
def __init__(self, data: BytesLike = bytearray(InReportLength.BT_31)):
|
|
15
|
+
super().__init__({
|
|
16
|
+
"axes_0": 1, "axes_1": 2, "axes_2": 3, "axes_3": 4, "axes_4": 5, "axes_5": 6,
|
|
17
|
+
"buttons_0": 8, "buttons_1": 9, "buttons_2": 10,
|
|
18
|
+
"timestamp_0": 12, "timestamp_1": 13, "timestamp_2": 14, "timestamp_3": 15,
|
|
19
|
+
"gyro_x_0": 16, "gyro_x_1": 17, "gyro_y_0": 18, "gyro_y_1": 19, "gyro_z_0": 20, "gyro_z_1": 21,
|
|
20
|
+
"accel_x_0": 22, "accel_x_1": 23, "accel_y_0": 24, "accel_y_1": 25, "accel_z_0": 26, "accel_z_1": 27,
|
|
21
|
+
"touch_1_0": 33, "touch_1_1": 34, "touch_1_2": 35, "touch_1_3": 36,
|
|
22
|
+
"touch_2_0": 37, "touch_2_1": 38, "touch_2_2": 39, "touch_2_3": 40,
|
|
23
|
+
"right_trigger_feedback": 42, "left_trigger_feedback": 43,
|
|
24
|
+
"battery_0": 53, "battery_1": 54,
|
|
25
|
+
}, data=data)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class AbstractBaseException(ABC, Exception):
|
|
5
|
+
def __init__(self, msg: str):
|
|
6
|
+
super().__init__(msg)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NoDeviceDetectedException(AbstractBaseException):
|
|
10
|
+
def __init__(self):
|
|
11
|
+
super().__init__('No DualSense device detected')
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class InvalidDeviceIndexException(AbstractBaseException):
|
|
15
|
+
def __init__(self, idx: int):
|
|
16
|
+
super().__init__(f'Invalid DualSense device index given {idx}')
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class InvalidInReportLengthException(AbstractBaseException):
|
|
20
|
+
def __init__(self):
|
|
21
|
+
super().__init__(f'Invalid connection type')
|