pyglet 2.1.12__py3-none-any.whl → 3.0.dev1__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.
Files changed (267) hide show
  1. pyglet/__init__.py +67 -61
  2. pyglet/__init__.pyi +15 -8
  3. pyglet/app/__init__.py +22 -13
  4. pyglet/app/async_app.py +212 -0
  5. pyglet/app/base.py +2 -1
  6. pyglet/app/{xlib.py → linux.py} +3 -3
  7. pyglet/config/__init__.py +101 -0
  8. pyglet/config/gl/__init__.py +30 -0
  9. pyglet/config/gl/egl.py +120 -0
  10. pyglet/config/gl/macos.py +262 -0
  11. pyglet/config/gl/windows.py +267 -0
  12. pyglet/config/gl/x11.py +142 -0
  13. pyglet/customtypes.py +43 -2
  14. pyglet/display/__init__.py +8 -6
  15. pyglet/display/base.py +3 -63
  16. pyglet/display/cocoa.py +12 -17
  17. pyglet/display/emscripten.py +39 -0
  18. pyglet/display/headless.py +23 -30
  19. pyglet/display/wayland.py +157 -0
  20. pyglet/display/win32.py +4 -17
  21. pyglet/display/xlib.py +19 -27
  22. pyglet/display/xlib_vidmoderestore.py +2 -2
  23. pyglet/enums.py +183 -0
  24. pyglet/event.py +0 -1
  25. pyglet/experimental/geoshader_sprite.py +15 -13
  26. pyglet/experimental/hidraw.py +6 -15
  27. pyglet/experimental/multitexture_sprite.py +31 -19
  28. pyglet/experimental/particles.py +13 -35
  29. pyglet/font/__init__.py +251 -85
  30. pyglet/font/base.py +116 -61
  31. pyglet/font/dwrite/__init__.py +349 -204
  32. pyglet/font/dwrite/dwrite_lib.py +27 -5
  33. pyglet/font/fontconfig.py +14 -6
  34. pyglet/font/freetype.py +138 -87
  35. pyglet/font/freetype_lib.py +19 -0
  36. pyglet/font/group.py +179 -0
  37. pyglet/font/harfbuzz/__init__.py +3 -3
  38. pyglet/font/pyodide_js.py +310 -0
  39. pyglet/font/quartz.py +319 -126
  40. pyglet/font/ttf.py +45 -3
  41. pyglet/font/user.py +14 -19
  42. pyglet/font/win32.py +45 -21
  43. pyglet/graphics/__init__.py +8 -787
  44. pyglet/graphics/allocation.py +115 -1
  45. pyglet/graphics/api/__init__.py +77 -0
  46. pyglet/graphics/api/base.py +299 -0
  47. pyglet/graphics/api/gl/__init__.py +58 -0
  48. pyglet/graphics/api/gl/base.py +24 -0
  49. pyglet/graphics/{vertexbuffer.py → api/gl/buffer.py} +104 -159
  50. pyglet/graphics/api/gl/cocoa/context.py +76 -0
  51. pyglet/graphics/api/gl/context.py +391 -0
  52. pyglet/graphics/api/gl/default_shaders.py +0 -0
  53. pyglet/graphics/api/gl/draw.py +627 -0
  54. pyglet/graphics/api/gl/egl/__init__.py +0 -0
  55. pyglet/graphics/api/gl/egl/context.py +92 -0
  56. pyglet/graphics/api/gl/enums.py +76 -0
  57. pyglet/graphics/api/gl/framebuffer.py +315 -0
  58. pyglet/graphics/api/gl/gl.py +5463 -0
  59. pyglet/graphics/api/gl/gl_info.py +188 -0
  60. pyglet/graphics/api/gl/global_opengl.py +226 -0
  61. pyglet/{gl → graphics/api/gl}/lib.py +34 -18
  62. pyglet/graphics/api/gl/shader.py +1476 -0
  63. pyglet/graphics/api/gl/shapes.py +55 -0
  64. pyglet/graphics/api/gl/sprite.py +102 -0
  65. pyglet/graphics/api/gl/state.py +219 -0
  66. pyglet/graphics/api/gl/text.py +190 -0
  67. pyglet/graphics/api/gl/texture.py +1526 -0
  68. pyglet/graphics/{vertexarray.py → api/gl/vertexarray.py} +11 -13
  69. pyglet/graphics/api/gl/vertexdomain.py +751 -0
  70. pyglet/graphics/api/gl/win32/__init__.py +0 -0
  71. pyglet/graphics/api/gl/win32/context.py +108 -0
  72. pyglet/graphics/api/gl/win32/wgl_info.py +24 -0
  73. pyglet/graphics/api/gl/xlib/__init__.py +0 -0
  74. pyglet/graphics/api/gl/xlib/context.py +174 -0
  75. pyglet/{gl → graphics/api/gl/xlib}/glx_info.py +26 -31
  76. pyglet/graphics/api/gl1/__init__.py +0 -0
  77. pyglet/{gl → graphics/api/gl1}/gl_compat.py +3 -2
  78. pyglet/graphics/api/gl2/__init__.py +0 -0
  79. pyglet/graphics/api/gl2/buffer.py +320 -0
  80. pyglet/graphics/api/gl2/draw.py +600 -0
  81. pyglet/graphics/api/gl2/global_opengl.py +122 -0
  82. pyglet/graphics/api/gl2/shader.py +200 -0
  83. pyglet/graphics/api/gl2/shapes.py +51 -0
  84. pyglet/graphics/api/gl2/sprite.py +79 -0
  85. pyglet/graphics/api/gl2/text.py +175 -0
  86. pyglet/graphics/api/gl2/vertexdomain.py +364 -0
  87. pyglet/graphics/api/webgl/__init__.py +233 -0
  88. pyglet/graphics/api/webgl/buffer.py +302 -0
  89. pyglet/graphics/api/webgl/context.py +234 -0
  90. pyglet/graphics/api/webgl/draw.py +590 -0
  91. pyglet/graphics/api/webgl/enums.py +76 -0
  92. pyglet/graphics/api/webgl/framebuffer.py +360 -0
  93. pyglet/graphics/api/webgl/gl.py +1537 -0
  94. pyglet/graphics/api/webgl/gl_info.py +130 -0
  95. pyglet/graphics/api/webgl/shader.py +1346 -0
  96. pyglet/graphics/api/webgl/shapes.py +92 -0
  97. pyglet/graphics/api/webgl/sprite.py +102 -0
  98. pyglet/graphics/api/webgl/state.py +227 -0
  99. pyglet/graphics/api/webgl/text.py +187 -0
  100. pyglet/graphics/api/webgl/texture.py +1227 -0
  101. pyglet/graphics/api/webgl/vertexarray.py +54 -0
  102. pyglet/graphics/api/webgl/vertexdomain.py +616 -0
  103. pyglet/graphics/api/webgl/webgl_js.pyi +307 -0
  104. pyglet/{image → graphics}/atlas.py +33 -32
  105. pyglet/graphics/base.py +10 -0
  106. pyglet/graphics/buffer.py +245 -0
  107. pyglet/graphics/draw.py +578 -0
  108. pyglet/graphics/framebuffer.py +26 -0
  109. pyglet/graphics/instance.py +178 -69
  110. pyglet/graphics/shader.py +267 -1553
  111. pyglet/graphics/state.py +83 -0
  112. pyglet/graphics/texture.py +703 -0
  113. pyglet/graphics/vertexdomain.py +695 -538
  114. pyglet/gui/ninepatch.py +10 -10
  115. pyglet/gui/widgets.py +120 -10
  116. pyglet/image/__init__.py +20 -1973
  117. pyglet/image/animation.py +12 -12
  118. pyglet/image/base.py +730 -0
  119. pyglet/image/codecs/__init__.py +9 -0
  120. pyglet/image/codecs/bmp.py +53 -30
  121. pyglet/image/codecs/dds.py +53 -31
  122. pyglet/image/codecs/gdiplus.py +38 -14
  123. pyglet/image/codecs/gdkpixbuf2.py +0 -2
  124. pyglet/image/codecs/js_image.py +99 -0
  125. pyglet/image/codecs/ktx2.py +161 -0
  126. pyglet/image/codecs/pil.py +1 -1
  127. pyglet/image/codecs/png.py +1 -1
  128. pyglet/image/codecs/wic.py +11 -2
  129. pyglet/info.py +26 -24
  130. pyglet/input/__init__.py +8 -0
  131. pyglet/input/base.py +163 -105
  132. pyglet/input/controller.py +13 -19
  133. pyglet/input/controller_db.py +39 -24
  134. pyglet/input/emscripten/__init__.py +18 -0
  135. pyglet/input/emscripten/gamepad_js.py +397 -0
  136. pyglet/input/linux/__init__.py +11 -5
  137. pyglet/input/linux/evdev.py +10 -11
  138. pyglet/input/linux/x11_xinput.py +2 -2
  139. pyglet/input/linux/x11_xinput_tablet.py +1 -1
  140. pyglet/input/macos/__init__.py +7 -2
  141. pyglet/input/macos/darwin_gc.py +559 -0
  142. pyglet/input/win32/__init__.py +1 -1
  143. pyglet/input/win32/directinput.py +34 -29
  144. pyglet/input/win32/xinput.py +11 -61
  145. pyglet/lib.py +3 -3
  146. pyglet/libs/__init__.py +1 -1
  147. pyglet/{gl → libs/darwin}/agl.py +1 -1
  148. pyglet/libs/darwin/cocoapy/__init__.py +2 -2
  149. pyglet/libs/darwin/cocoapy/cocoahelpers.py +181 -0
  150. pyglet/libs/darwin/cocoapy/cocoalibs.py +31 -0
  151. pyglet/libs/darwin/cocoapy/cocoatypes.py +27 -0
  152. pyglet/libs/darwin/cocoapy/runtime.py +81 -45
  153. pyglet/libs/darwin/coreaudio.py +4 -4
  154. pyglet/{gl → libs/darwin}/lib_agl.py +9 -8
  155. pyglet/libs/darwin/quartzkey.py +1 -3
  156. pyglet/libs/egl/__init__.py +2 -0
  157. pyglet/libs/egl/egl_lib.py +576 -0
  158. pyglet/libs/egl/eglext.py +51 -5
  159. pyglet/libs/linux/__init__.py +0 -0
  160. pyglet/libs/linux/egl/__init__.py +0 -0
  161. pyglet/libs/linux/egl/eglext.py +22 -0
  162. pyglet/libs/linux/glx/__init__.py +0 -0
  163. pyglet/{gl → libs/linux/glx}/glx.py +13 -14
  164. pyglet/{gl → libs/linux/glx}/glxext_arb.py +408 -192
  165. pyglet/{gl → libs/linux/glx}/glxext_mesa.py +1 -1
  166. pyglet/{gl → libs/linux/glx}/glxext_nv.py +345 -164
  167. pyglet/{gl → libs/linux/glx}/lib_glx.py +3 -2
  168. pyglet/libs/linux/wayland/__init__.py +0 -0
  169. pyglet/libs/linux/wayland/client.py +1068 -0
  170. pyglet/libs/linux/wayland/lib_wayland.py +207 -0
  171. pyglet/libs/linux/wayland/wayland_egl.py +38 -0
  172. pyglet/libs/{wayland → linux/wayland}/xkbcommon.py +26 -0
  173. pyglet/libs/{x11 → linux/x11}/xf86vmode.py +4 -4
  174. pyglet/libs/{x11 → linux/x11}/xinerama.py +2 -2
  175. pyglet/libs/{x11 → linux/x11}/xinput.py +10 -10
  176. pyglet/libs/linux/x11/xrandr.py +0 -0
  177. pyglet/libs/{x11 → linux/x11}/xrender.py +1 -1
  178. pyglet/libs/shared/__init__.py +0 -0
  179. pyglet/libs/shared/spirv/__init__.py +0 -0
  180. pyglet/libs/shared/spirv/lib_shaderc.py +85 -0
  181. pyglet/libs/shared/spirv/lib_spirv_cross.py +126 -0
  182. pyglet/libs/win32/__init__.py +27 -5
  183. pyglet/libs/win32/constants.py +59 -48
  184. pyglet/libs/win32/context_managers.py +20 -3
  185. pyglet/libs/win32/dinput.py +105 -88
  186. pyglet/{gl → libs/win32}/lib_wgl.py +52 -26
  187. pyglet/libs/win32/types.py +58 -23
  188. pyglet/{gl → libs/win32}/wgl.py +32 -25
  189. pyglet/{gl → libs/win32}/wglext_arb.py +364 -2
  190. pyglet/media/__init__.py +9 -10
  191. pyglet/media/codecs/__init__.py +12 -1
  192. pyglet/media/codecs/base.py +99 -96
  193. pyglet/media/codecs/ffmpeg.py +2 -2
  194. pyglet/media/codecs/ffmpeg_lib/libavformat.py +3 -8
  195. pyglet/media/codecs/webaudio_pyodide.py +111 -0
  196. pyglet/media/drivers/__init__.py +9 -4
  197. pyglet/media/drivers/base.py +4 -4
  198. pyglet/media/drivers/openal/__init__.py +1 -1
  199. pyglet/media/drivers/openal/adaptation.py +3 -3
  200. pyglet/media/drivers/pulse/__init__.py +1 -1
  201. pyglet/media/drivers/pulse/adaptation.py +3 -3
  202. pyglet/media/drivers/pyodide_js/__init__.py +8 -0
  203. pyglet/media/drivers/pyodide_js/adaptation.py +288 -0
  204. pyglet/media/drivers/xaudio2/adaptation.py +3 -3
  205. pyglet/media/player.py +276 -193
  206. pyglet/media/player_worker_thread.py +1 -1
  207. pyglet/model/__init__.py +39 -29
  208. pyglet/model/codecs/base.py +4 -4
  209. pyglet/model/codecs/gltf.py +3 -3
  210. pyglet/model/codecs/obj.py +71 -43
  211. pyglet/resource.py +129 -78
  212. pyglet/shapes.py +147 -177
  213. pyglet/sprite.py +47 -164
  214. pyglet/text/__init__.py +44 -54
  215. pyglet/text/caret.py +12 -7
  216. pyglet/text/document.py +19 -17
  217. pyglet/text/formats/html.py +2 -2
  218. pyglet/text/formats/structured.py +10 -40
  219. pyglet/text/layout/__init__.py +20 -13
  220. pyglet/text/layout/base.py +176 -287
  221. pyglet/text/layout/incremental.py +9 -10
  222. pyglet/text/layout/scrolling.py +7 -95
  223. pyglet/window/__init__.py +183 -172
  224. pyglet/window/cocoa/__init__.py +62 -51
  225. pyglet/window/cocoa/pyglet_delegate.py +2 -25
  226. pyglet/window/cocoa/pyglet_view.py +9 -8
  227. pyglet/window/dialog/__init__.py +184 -0
  228. pyglet/window/dialog/base.py +99 -0
  229. pyglet/window/dialog/darwin.py +121 -0
  230. pyglet/window/dialog/linux.py +72 -0
  231. pyglet/window/dialog/windows.py +194 -0
  232. pyglet/window/emscripten/__init__.py +779 -0
  233. pyglet/window/headless/__init__.py +44 -28
  234. pyglet/window/key.py +2 -0
  235. pyglet/window/mouse.py +2 -2
  236. pyglet/window/wayland/__init__.py +377 -0
  237. pyglet/window/win32/__init__.py +101 -46
  238. pyglet/window/xlib/__init__.py +104 -66
  239. {pyglet-2.1.12.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
  240. pyglet-3.0.dev1.dist-info/RECORD +322 -0
  241. {pyglet-2.1.12.dist-info → pyglet-3.0.dev1.dist-info}/WHEEL +1 -1
  242. pyglet/gl/__init__.py +0 -208
  243. pyglet/gl/base.py +0 -499
  244. pyglet/gl/cocoa.py +0 -309
  245. pyglet/gl/gl.py +0 -4625
  246. pyglet/gl/gl.pyi +0 -2320
  247. pyglet/gl/gl_compat.pyi +0 -3097
  248. pyglet/gl/gl_info.py +0 -190
  249. pyglet/gl/headless.py +0 -166
  250. pyglet/gl/wgl_info.py +0 -36
  251. pyglet/gl/wglext_nv.py +0 -1096
  252. pyglet/gl/win32.py +0 -268
  253. pyglet/gl/xlib.py +0 -295
  254. pyglet/image/buffer.py +0 -274
  255. pyglet/image/codecs/s3tc.py +0 -354
  256. pyglet/libs/x11/xrandr.py +0 -166
  257. pyglet-2.1.12.dist-info/RECORD +0 -234
  258. /pyglet/{libs/wayland → graphics/api/gl/cocoa}/__init__.py +0 -0
  259. /pyglet/libs/{egl → linux/egl}/egl.py +0 -0
  260. /pyglet/libs/{egl → linux/egl}/lib.py +0 -0
  261. /pyglet/libs/{ioctl.py → linux/ioctl.py} +0 -0
  262. /pyglet/libs/{wayland → linux/wayland}/gbm.py +0 -0
  263. /pyglet/libs/{x11 → linux/x11}/__init__.py +0 -0
  264. /pyglet/libs/{x11 → linux/x11}/cursorfont.py +0 -0
  265. /pyglet/libs/{x11 → linux/x11}/xlib.py +0 -0
  266. /pyglet/libs/{x11 → linux/x11}/xsync.py +0 -0
  267. {pyglet-2.1.12.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
@@ -0,0 +1,559 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ import warnings
5
+ import weakref
6
+ from ctypes import cdll, util, c_void_p, byref
7
+ from enum import Enum, auto
8
+ from typing import Protocol
9
+
10
+ import pyglet
11
+ from pyglet.event import EventDispatcher
12
+ from pyglet.libs.darwin import ObjCSubclass, ObjCInstance, send_super, \
13
+ AutoReleasePool, ns_to_py, nsdict_to_py, PyObjectEncoding, nsnum_to_py
14
+ from pyglet.libs.darwin.cocoapy.runtime import get_callback_block
15
+ from pyglet.math import Vec2
16
+
17
+ from pyglet.window.cocoa.pyglet_delegate import NSNotification
18
+
19
+ from pyglet.input.base import Device, Control, Controller, Button, AbsoluteAxis, ControllerManager, Sign
20
+
21
+ from pyglet.libs.darwin import ObjCClass, get_selector
22
+ from pyglet.window.cocoa.pyglet_view import NSNotificationCenter
23
+
24
+ lib = util.find_library('GameController')
25
+
26
+ # Hack for compatibility with macOS > 11.0
27
+ if lib is None:
28
+ lib = '/System/Library/Frameworks/GameController.framework/GameController'
29
+
30
+ gc = cdll.LoadLibrary(lib)
31
+
32
+ NSObject = ObjCClass('NSObject')
33
+ GCController = ObjCClass("GCController")
34
+ NSArray = ObjCClass('NSArray')
35
+
36
+
37
+ class _GCController(Protocol):
38
+ """Just a type hint to better understand the controller API's"""
39
+
40
+ def playerIndex(self) -> int: ...
41
+
42
+ def vendorName(self) -> str: ...
43
+
44
+ def battery(self): ...
45
+
46
+ def haptics(self): ...
47
+
48
+ def light(self): ...
49
+
50
+ def physicalInputProfile(self): ...
51
+
52
+
53
+ GCControllerDidConnectNotification = c_void_p.in_dll(gc, 'GCControllerDidConnectNotification')
54
+ GCControllerDidDisconnectNotification = c_void_p.in_dll(gc, 'GCControllerDidDisconnectNotification')
55
+ GCInputDualShockTouchpadButton = c_void_p.in_dll(gc, 'GCInputDualShockTouchpadButton')
56
+
57
+ GCHapticsLocalityDefault = c_void_p.in_dll(gc, 'GCHapticsLocalityDefault')
58
+ GCHapticsLocalityAll = c_void_p.in_dll(gc, 'GCHapticsLocalityAll')
59
+ GCHapticsLocalityHandles = c_void_p.in_dll(gc, 'GCHapticsLocalityHandles')
60
+ GCHapticsLocalityLeftHandle = c_void_p.in_dll(gc, 'GCHapticsLocalityLeftHandle')
61
+ GCHapticsLocalityRightHandle = c_void_p.in_dll(gc, 'GCHapticsLocalityRightHandle')
62
+ GCHapticsLocalityTriggers = c_void_p.in_dll(gc, 'GCHapticsLocalityTriggers')
63
+ GCHapticsLocalityLeftTrigger = c_void_p.in_dll(gc, 'GCHapticsLocalityLeftTrigger')
64
+ GCHapticsLocalityRightTrigger = c_void_p.in_dll(gc, 'GCHapticsLocalityRightTrigger')
65
+
66
+ CHHapticEventParameterIDHapticSharpness = c_void_p.in_dll(gc, 'CHHapticEventParameterIDHapticSharpness')
67
+ CHHapticEventParameterIDHapticIntensity = c_void_p.in_dll(gc, 'CHHapticEventParameterIDHapticIntensity')
68
+ CHHapticEventParameterIDDecayTime = c_void_p.in_dll(gc, 'CHHapticEventParameterIDDecayTime')
69
+ CHHapticEventParameterIDReleaseTime = c_void_p.in_dll(gc, 'CHHapticEventParameterIDReleaseTime')
70
+ CHHapticEventParameterIDSustained = c_void_p.in_dll(gc, 'CHHapticEventParameterIDSustained')
71
+
72
+ CHHapticEventTypeAudioContinuous = c_void_p.in_dll(gc, 'CHHapticEventTypeAudioContinuous')
73
+ CHHapticEventTypeAudioCustom = c_void_p.in_dll(gc, 'CHHapticEventTypeAudioCustom')
74
+ CHHapticEventTypeHapticTransient = c_void_p.in_dll(gc, 'CHHapticEventTypeHapticTransient')
75
+ CHHapticEventTypeHapticContinuous = c_void_p.in_dll(gc, 'CHHapticEventTypeHapticContinuous')
76
+
77
+ GCHapticDurationInfinite = c_void_p.in_dll(gc, 'GCHapticDurationInfinite')
78
+
79
+ GCSystemGestureStateDisabled = 2
80
+
81
+ CHHapticDynamicParameterIDHapticIntensityControl = c_void_p.in_dll(gc,
82
+ 'CHHapticDynamicParameterIDHapticIntensityControl')
83
+
84
+ CHHapticEventParameter = ObjCClass('CHHapticEventParameter')
85
+ CHHapticEvent = ObjCClass('CHHapticEvent')
86
+ CHHapticPattern = ObjCClass('CHHapticPattern')
87
+ CHHapticDynamicParameter = ObjCClass('CHHapticDynamicParameter')
88
+
89
+ GCDeviceBatteryStateUnknown = -1
90
+ GCDeviceBatteryStateDischarging = 0
91
+ GCDeviceBatteryStateCharging = 1
92
+ GCDeviceBatteryStateFull = 2
93
+
94
+
95
+ class BatteryState(Enum):
96
+ UNKNOWN = auto()
97
+ DISCHARGING = auto()
98
+ CHARGING = auto()
99
+ FULL = auto()
100
+
101
+
102
+ _state_mapping = {
103
+ GCDeviceBatteryStateUnknown: BatteryState.UNKNOWN,
104
+ GCDeviceBatteryStateDischarging: BatteryState.DISCHARGING,
105
+ GCDeviceBatteryStateCharging: BatteryState.CHARGING,
106
+ GCDeviceBatteryStateFull: BatteryState.FULL,
107
+ }
108
+
109
+ _button_mapping = {
110
+ "Direction Pad Up": "dpup",
111
+ "Direction Pad Down": "dpdown",
112
+ "Direction Pad Left": "dpleft",
113
+ "Direction Pad Right": "dpright",
114
+ "Button Menu": "start",
115
+ "Button Options": "back",
116
+ "Button Home": "guide",
117
+ "Left Thumbstick Button": "leftthumb",
118
+ "Right Thumbstick Button": "rightthumb",
119
+ "Left Shoulder": "leftshoulder",
120
+ "Right Shoulder": "rightshoulder",
121
+ "Left Trigger": "lefttrigger",
122
+ "Right Trigger": "righttrigger",
123
+ "Button A": "a",
124
+ "Button B": "b",
125
+ "Button X": "x",
126
+ "Button Y": "y",
127
+ # "Touchpad Button": "touchpad",
128
+ }
129
+
130
+ _axis_mapping = {
131
+ "Right Thumbstick Y Axis": "righty",
132
+ "Right Thumbstick X Axis": "rightx",
133
+
134
+ "Left Thumbstick X Axis": "leftx",
135
+ "Left Thumbstick Y Axis": "lefty",
136
+
137
+ "Left Trigger": "lefttrigger",
138
+ "Right Trigger": "righttrigger",
139
+
140
+ # "Direction Pad X Axis": "leftx",
141
+ # "Direction Pad Y Axis": "lefty",
142
+
143
+ # "Touchpad 1 Y Axis": "unsupport",
144
+ # "Touchpad 1 X Axis": "unsupport",
145
+ # "Touchpad 2 Y Axis": "unsupport",
146
+ # "Touchpad 2 X Axis": "unsupport",
147
+ }
148
+
149
+ _dpads_mapping = {
150
+ "Direction Pad": AbsoluteAxis.HAT,
151
+ # "Touchpad 2": "unknown",
152
+ # "Touchpad 1": "unknown",
153
+ # "Right Thumbstick": "unknown",
154
+ # "Left Thumbstick": "unknown",
155
+ }
156
+
157
+
158
+ class HapticEngine:
159
+ def __init__(self, name: str, engine):
160
+ self.name = name
161
+ self.engine = engine
162
+
163
+ # !!! Must retain or it will release on ObjC side.
164
+ self.engine.retain()
165
+
166
+ self._player = None
167
+ self.is_playing = False
168
+
169
+ self.error = c_void_p()
170
+
171
+ self._create_player()
172
+
173
+ def _create_player(self):
174
+ with AutoReleasePool():
175
+ event_param = CHHapticEventParameter.alloc().initWithParameterID_value_(
176
+ CHHapticEventParameterIDHapticIntensity, 1.0,
177
+ )
178
+ params_arr = NSArray.arrayWithObject_(event_param)
179
+
180
+ self.event = CHHapticEvent.alloc().initWithEventType_parameters_relativeTime_duration_(
181
+ CHHapticEventTypeHapticContinuous,
182
+ params_arr,
183
+ 0.0,
184
+ 10000.0
185
+ )
186
+ event_arr = NSArray.arrayWithObject_(self.event)
187
+ empty_arr = NSArray.alloc().init()
188
+
189
+ pattern = CHHapticPattern.alloc().initWithEvents_parameters_error_(event_arr, empty_arr,
190
+ byref(self.error))
191
+
192
+ if not pattern:
193
+ self.as_nserror()
194
+ return
195
+
196
+ self._player = self.engine.createPlayerWithPattern_error_(pattern, byref(self.error))
197
+
198
+ if not self._player:
199
+ self.as_nserror()
200
+ return
201
+
202
+ self._player.retain()
203
+
204
+ def as_nserror(self):
205
+ ns_error = ObjCInstance(self.error.value)
206
+ # print("macos GC error:", ns_error.localizedDescription())
207
+
208
+ def trigger_event(self, intensity, sharpness, duration):
209
+ self.is_playing = True
210
+
211
+ param = CHHapticDynamicParameter.alloc().initWithParameterID_value_relativeTime_(
212
+ CHHapticDynamicParameterIDHapticIntensityControl, intensity, 0,
213
+ )
214
+
215
+ dynam_param_arr = NSArray.arrayWithObject_(param)
216
+
217
+ self._player.sendParameters_atTime_error_(dynam_param_arr, 0, byref(self.error))
218
+ if self.error:
219
+ # print("macos GC: Failed to update parameter")
220
+ return
221
+
222
+ self._player.startAtTime_error_(0, None)
223
+
224
+ pyglet.clock.unschedule(self._schedule_stop)
225
+ pyglet.clock.schedule_once(self._schedule_stop, duration)
226
+
227
+ def _schedule_stop(self, dt):
228
+ self.stop_event()
229
+
230
+ def stop_event(self):
231
+ if self.is_playing and self._player:
232
+ self._player.stopAtTime_error_(0, None)
233
+ self.is_playing = False
234
+
235
+ def delete(self):
236
+ if self._player:
237
+ pyglet.clock.unschedule(self._schedule_stop)
238
+ self.stop_event()
239
+ self._player.cancelAndReturnError_(None)
240
+ self._player.release()
241
+ self._player = None
242
+
243
+ if self.engine:
244
+ self.engine.stopWithCompletionHandler_(None)
245
+ self.engine.release()
246
+ self.engine = None
247
+
248
+ def __del__(self):
249
+ self.delete()
250
+
251
+
252
+ class AppleGamepad(Device):
253
+
254
+ def __init__(self, manager, controller: _GCController) -> None:
255
+
256
+ with AutoReleasePool():
257
+ self.manager = weakref.proxy(manager)
258
+ self.device_name = ns_to_py(controller.vendorName())
259
+ self.product_category = ns_to_py(controller.productCategory())
260
+
261
+ super().__init__(None, self.device_name)
262
+ self.controller = controller
263
+
264
+ self.index = controller.playerIndex()
265
+
266
+ self.battery = controller.battery() # GCDeviceBattery
267
+ self.haptics = controller.haptics() # GCDeviceHaptics
268
+ self.light = controller.light() # GCDeviceLight
269
+
270
+ self.weak_motor_engine = None
271
+ self.strong_motor_engine = None
272
+
273
+ if self.haptics:
274
+ # self.weak_motor_engine = self._get_motor_engine(GCHapticsLocalityDefault)
275
+ self.weak_motor_engine = self._get_motor_engine(GCHapticsLocalityLeftHandle)
276
+ self.strong_motor_engine = self._get_motor_engine(GCHapticsLocalityRightHandle)
277
+
278
+ # Can not get a strong or weak motor, just use default.
279
+ if self.weak_motor_engine is None and self.strong_motor_engine is None:
280
+ engine = self._get_motor_engine(GCHapticsLocalityDefault)
281
+ self.weak_motor_engine = engine
282
+ self.strong_motor_engine = engine
283
+ # No weak motor, just use the strong one?
284
+ elif self.weak_motor_engine is None and self.strong_motor_engine is not None:
285
+ self.weak_motor_engine = self.strong_motor_engine
286
+ # No strong motor, use the weak one?
287
+ elif self.weak_motor_engine is not None and self.strong_motor_engine is None:
288
+ self.strong_motor_engine = self.weak_motor_engine
289
+
290
+ self.profile = controller.physicalInputProfile()
291
+
292
+ self.buttons = ns_to_py(self.profile.buttons())
293
+ self.axes = ns_to_py(self.profile.axes())
294
+ self.dpads = ns_to_py(self.profile.dpads())
295
+
296
+ self._button_ptrs = {}
297
+ if self.buttons:
298
+ self._button_cb_block = get_callback_block(self._button_changed_callback, encoding=['v', '@', 'f'])
299
+ for button_name, button_objc in self.buttons.items():
300
+ assert button_objc.ptr.value not in self._button_ptrs
301
+ pyglet_name = _button_mapping.get(button_name)
302
+ if not pyglet_name:
303
+ # print(f"Found: {button_name} button, but does not map to anything. Ignoring.")
304
+ continue
305
+ # Try to disable any "gestured" buttons so they can be used like actual buttons.
306
+ if button_objc.isBoundToSystemGesture():
307
+ button_objc.setPreferredSystemGestureState_(GCSystemGestureStateDisabled)
308
+ self._button_ptrs[button_objc.ptr.value] = pyglet_name
309
+
310
+ button_objc.setValueChangedHandler_(self._button_cb_block)
311
+
312
+ self._axes_ptrs = {}
313
+ if self.axes:
314
+ self._axes_cb_block = get_callback_block(self._axis_changed_callback, encoding=['v', '@', 'f'])
315
+ for axis_name, axis_obj in self.axes.items():
316
+ assert axis_obj.ptr.value not in self._axes_ptrs
317
+ pyglet_name = _axis_mapping.get(axis_name)
318
+ if not pyglet_name:
319
+ # print(f"Found: {axis_name} axis, but does not map to anything. Ignoring.")
320
+ continue
321
+ self._axes_ptrs[axis_obj.ptr.value] = pyglet_name
322
+ axis_obj.setValueChangedHandler_(self._axes_cb_block)
323
+
324
+ self._dpad_ptrs = {}
325
+ if self.dpads:
326
+ self._dpad_cb_block = get_callback_block(self._dpads_changed_callback, encoding=['v', '@', 'f', 'f'])
327
+ for dpad_name, dpad_obj in self.dpads.items():
328
+ assert dpad_obj.ptr.value not in self._dpad_ptrs
329
+ pyglet_name = _dpads_mapping.get(dpad_name)
330
+
331
+ if not pyglet_name:
332
+ continue
333
+ self._dpad_ptrs[dpad_obj.ptr.value] = pyglet_name
334
+ dpad_obj.setValueChangedHandler_(self._dpad_cb_block)
335
+
336
+ # print("DEVICE NAME", repr(self.device_name), "index", self.index, self.product_category)
337
+
338
+ # We need to store the Block's so callbacks don't get GC'd, as it contains CFUNCTYPES.
339
+ self.cb_blocks = {}
340
+
341
+ self.controls = {
342
+ 'a': Button('a'),
343
+ 'b': Button('b'),
344
+ 'x': Button('x'),
345
+ 'y': Button('y'),
346
+ 'back': Button('back'),
347
+ 'start': Button('start'),
348
+ 'guide': Button('guide'),
349
+ 'leftshoulder': Button('leftshoulder'),
350
+ 'rightshoulder': Button('rightshoulder'),
351
+ 'leftthumb': Button('leftthumb'),
352
+ 'rightthumb': Button('rightthumb'),
353
+ 'dpup': Button('dpup'),
354
+ 'dpdown': Button('dpdown'),
355
+ 'dpleft': Button('dpleft'),
356
+ 'dpright': Button('dpright'),
357
+
358
+ 'leftx': AbsoluteAxis('leftx', -1, 1),
359
+ 'lefty': AbsoluteAxis('lefty', -1, 1, inverted=True),
360
+ 'rightx': AbsoluteAxis('rightx', -1, 1),
361
+ 'righty': AbsoluteAxis('righty', -1, 1, inverted=True),
362
+ 'lefttrigger': AbsoluteAxis('lefttrigger', 0, 1),
363
+ 'righttrigger': AbsoluteAxis('righttrigger', 0, 1),
364
+
365
+ "hat": AbsoluteAxis('hat', 0, 1),
366
+ }
367
+
368
+ def _axis_changed_callback(self, axes_obj, value):
369
+ name = self._axes_ptrs[axes_obj]
370
+ self.controls[name].value = value
371
+
372
+ def _button_changed_callback(self, button_obj, value):
373
+ name = self._button_ptrs[button_obj]
374
+ self.controls[name].value = value
375
+
376
+ def _dpads_changed_callback(self, dpads_obj, value, value2):
377
+ name = self._dpad_ptrs[dpads_obj]
378
+ self.controls[name].value = value
379
+
380
+ def get_battery_level(self) -> float:
381
+ """Returns the current battery level.
382
+
383
+ 0.0 being discharged, or 1.0 as 100%. Defaults to 0.0 if not found.
384
+ """
385
+ if self.battery:
386
+ return self.battery.batteryLevel()
387
+
388
+ return 0.0
389
+
390
+ def get_battery_state(self) -> BatteryState:
391
+ if self.battery:
392
+ battery_state = self.battery.batteryState()
393
+ return _state_mapping.get(battery_state, BatteryState.UNKNOWN)
394
+
395
+ return BatteryState.UNKNOWN
396
+
397
+ def _get_motor_engine(self, locality):
398
+ if self.haptics is None:
399
+ return None
400
+
401
+ locality_str = ns_to_py(ObjCInstance(locality))
402
+
403
+ if locality_str not in ns_to_py(self.haptics.supportedLocalities()):
404
+ warnings.warn(f"Controller supports haptics, but not locality: {locality}.")
405
+ return None
406
+
407
+ engine = self.haptics.createEngineWithLocality_(locality)
408
+ if not engine:
409
+ warnings.warn("Could not create motor engine.")
410
+ return None
411
+
412
+ err = c_void_p()
413
+
414
+ error = engine.startAndReturnError_(err)
415
+ if not error:
416
+ # print("Error starting engine")
417
+ return None
418
+
419
+ self.haptic_engine = HapticEngine(locality, engine)
420
+ return self.haptic_engine
421
+
422
+ def get_controls(self) -> list[Control]:
423
+ return list(self.controls.values())
424
+
425
+ def get_guid(self) -> str:
426
+ return "MFI_APPLE_CONTROLLER"
427
+
428
+
429
+ class AppleController(Controller):
430
+ """Javascript Gamepad Controller object that handles buttons and controls."""
431
+ device: AppleGamepad
432
+
433
+ def __init__(self, device: AppleGamepad, mapping: dict) -> None:
434
+ super().__init__(device, mapping)
435
+ self._last_updated = 0.0
436
+
437
+ def _initialize_controls(self) -> None:
438
+ for button_name in _button_mapping.values():
439
+ # Ignore any controls not mapped by pyglet...
440
+ if button_name not in self.device.controls:
441
+ continue
442
+ control = self.device.controls[button_name]
443
+ self.button_controls.append(control)
444
+ self._bind_button_control(control, button_name)
445
+
446
+ for axis_name in _axis_mapping.values():
447
+ control = self.device.controls[axis_name]
448
+ self.relative_axis_controls.append(control)
449
+ self._bind_axis_control(control, axis_name, Sign.DEFAULT)
450
+
451
+ def rumble_play_weak(self, strength: float = 1.0, duration: float = 0.5) -> None:
452
+ if self.device and self.device.weak_motor_engine:
453
+ strength_clamp = int(max(min(1.0, strength), 0))
454
+ self.device.weak_motor_engine.trigger_event(strength_clamp, sharpness=1.0, duration=duration)
455
+
456
+ def rumble_play_strong(self, strength: float = 1.0, duration: float = 0.5) -> None:
457
+ if self.device and self.device.strong_motor_engine:
458
+ strength_clamp = int(max(min(1.0, strength), 0))
459
+ self.device.strong_motor_engine.trigger_event(strength_clamp, sharpness=1.0, duration=duration)
460
+
461
+ def rumble_stop_weak(self) -> None:
462
+ if self.device and self.device.weak_motor_engine:
463
+ self.device.weak_motor_engine.stop_event()
464
+
465
+ def rumble_stop_strong(self) -> None:
466
+ if self.device and self.device.strong_motor_engine:
467
+ self.device.strong_motor_engine.stop_event()
468
+
469
+
470
+ class _AppleControllerManager_Implementation(EventDispatcher):
471
+ _PygletAppleControllerManager = ObjCSubclass('NSObject', '_PygletAppleControllerManager')
472
+
473
+ @_PygletAppleControllerManager.method(b'@' + PyObjectEncoding)
474
+ def initWithDispatcher(self, dispatcher: _SingletonAppleDispatcher):
475
+ self = ObjCInstance(send_super(self, 'init'))
476
+ if self is None:
477
+ return None
478
+
479
+ center = NSNotificationCenter.defaultCenter()
480
+ center.addObserver_selector_name_object_(
481
+ self,
482
+ get_selector("controllerConnected:"),
483
+ GCControllerDidConnectNotification,
484
+ None,
485
+ )
486
+ center.addObserver_selector_name_object_(
487
+ self,
488
+ get_selector("controllerDisconnected:"),
489
+ GCControllerDidDisconnectNotification,
490
+ None,
491
+ )
492
+
493
+ controllers = {}
494
+ self.associate("controllers", controllers)
495
+
496
+ self.dispatcher = dispatcher
497
+
498
+ GCController.startWirelessControllerDiscoveryWithCompletionHandler_(None)
499
+ return self
500
+
501
+ @_PygletAppleControllerManager.method('v@')
502
+ def controllerConnected_(self, notification: NSNotification):
503
+ device: GCController = notification.object()
504
+
505
+ wrapper = AppleGamepad(self, device)
506
+ controller = AppleController(wrapper, {"name": wrapper.device_name, "guid": "MFI_APPLE_CONTROLLER"})
507
+
508
+ self.controllers[device] = controller
509
+
510
+ self.dispatcher.dispatch_event('on_connect', controller)
511
+
512
+ @_PygletAppleControllerManager.method('v@')
513
+ def controllerDisconnected_(self, notification: NSNotification):
514
+ device: GCController = notification.object()
515
+
516
+ if device in self.controllers:
517
+ self.dispatcher.dispatch_event('on_disconnect', self.controllers[device])
518
+
519
+ del self.controllers[device]
520
+
521
+ def get_controllers(self):
522
+ return list(self.controllers.values())
523
+
524
+
525
+ _PygletAppleControllerManager = ObjCClass('_PygletAppleControllerManager')
526
+
527
+
528
+ class _SingletonAppleDispatcher(EventDispatcher):
529
+ """Only keep this as we only need one."""
530
+
531
+ def __init__(self):
532
+ self._obj_mgr = _PygletAppleControllerManager.alloc().initWithDispatcher(self)
533
+
534
+
535
+ _SingletonAppleDispatcher.register_event_type("on_connect")
536
+ _SingletonAppleDispatcher.register_event_type("on_disconnect")
537
+
538
+ _apple_controller = _SingletonAppleDispatcher()
539
+
540
+
541
+ class AppleControllerManager(ControllerManager):
542
+
543
+ def __init__(self):
544
+ self._controllers = {}
545
+
546
+ @_apple_controller.event
547
+ def on_connect(controller):
548
+ pyglet.app.platform_event_loop.post_event(self, 'on_connect', controller)
549
+
550
+ @_apple_controller.event
551
+ def on_disconnect(controller):
552
+ pyglet.app.platform_event_loop.post_event(self, 'on_disconnect', controller)
553
+
554
+ def get_controllers(self):
555
+ return list(self._controllers.values())
556
+
557
+
558
+ def get_controllers(display=None):
559
+ return []
@@ -20,7 +20,7 @@ except:
20
20
 
21
21
 
22
22
  _xinput_enabled = False
23
- if not pyglet.options["win32_disable_xinput"]:
23
+ if not pyglet.options.win32_disable_xinput:
24
24
  try:
25
25
  from pyglet.input.win32.xinput import XInputControllerManager, XInputController, XInputDevice
26
26
  from pyglet.input.win32.xinput import _device_manager as _xinput_device_manager