1# ----------------------------------------------------------------------------
2# pyglet
3# Copyright (c) 2006-2008 Alex Holkner
4# Copyright (c) 2008-2020 pyglet contributors
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10#
11#  * Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13#  * Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in
15#    the documentation and/or other materials provided with the
16#    distribution.
17#  * Neither the name of pyglet nor the names of its
18#    contributors may be used to endorse or promote products
19#    derived from this software without specific prior written
20#    permission.
21#
22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33# POSSIBILITY OF SUCH DAMAGE.
34# ----------------------------------------------------------------------------
35import ctypes
36
37from pyglet import com
38
39lib = ctypes.oledll.dinput8
40
41LPVOID = ctypes.c_void_p
42WORD = ctypes.c_uint16
43DWORD = ctypes.c_uint32
44LPDWORD = ctypes.POINTER(DWORD)
45BOOL = ctypes.c_int
46WCHAR = ctypes.c_wchar
47UINT = ctypes.c_uint
48HWND = ctypes.c_uint32
49HANDLE = LPVOID
50MAX_PATH = 260
51
52DIENUM_STOP = 0
53DIENUM_CONTINUE = 1
54
55DIEDFL_ALLDEVICES = 0x00000000
56DIEDFL_ATTACHEDONLY = 0x00000001
57DIEDFL_FORCEFEEDBACK = 0x00000100
58DIEDFL_INCLUDEALIASES = 0x00010000
59DIEDFL_INCLUDEPHANTOMS = 0x00020000
60DIEDFL_INCLUDEHIDDEN = 0x00040000
61
62DI8DEVCLASS_ALL = 0
63DI8DEVCLASS_DEVICE = 1
64DI8DEVCLASS_POINTER = 2
65DI8DEVCLASS_KEYBOARD = 3
66DI8DEVCLASS_GAMECTRL = 4
67
68DI8DEVTYPE_DEVICE = 0x11
69DI8DEVTYPE_MOUSE = 0x12
70DI8DEVTYPE_KEYBOARD = 0x13
71DI8DEVTYPE_JOYSTICK = 0x14
72DI8DEVTYPE_GAMEPAD = 0x15
73DI8DEVTYPE_DRIVING = 0x16
74DI8DEVTYPE_FLIGHT = 0x17
75DI8DEVTYPE_1STPERSON = 0x18
76DI8DEVTYPE_DEVICECTRL = 0x19
77DI8DEVTYPE_SCREENPOINTER = 0x1A
78DI8DEVTYPE_REMOTE = 0x1B
79DI8DEVTYPE_SUPPLEMENTAL = 0x1C
80DI8DEVTYPEMOUSE_UNKNOWN = 1
81DI8DEVTYPEMOUSE_TRADITIONAL = 2
82DI8DEVTYPEMOUSE_FINGERSTICK = 3
83DI8DEVTYPEMOUSE_TOUCHPAD = 4
84DI8DEVTYPEMOUSE_TRACKBALL = 5
85DI8DEVTYPEMOUSE_ABSOLUTE = 6
86
87DI8DEVTYPEKEYBOARD_UNKNOWN = 0
88DI8DEVTYPEKEYBOARD_PCXT = 1
89DI8DEVTYPEKEYBOARD_OLIVETTI = 2
90DI8DEVTYPEKEYBOARD_PCAT = 3
91DI8DEVTYPEKEYBOARD_PCENH = 4
92DI8DEVTYPEKEYBOARD_NOKIA1050 = 5
93DI8DEVTYPEKEYBOARD_NOKIA9140 = 6
94DI8DEVTYPEKEYBOARD_NEC98 = 7
95DI8DEVTYPEKEYBOARD_NEC98LAPTOP = 8
96DI8DEVTYPEKEYBOARD_NEC98106 = 9
97DI8DEVTYPEKEYBOARD_JAPAN106 = 10
98DI8DEVTYPEKEYBOARD_JAPANAX = 11
99DI8DEVTYPEKEYBOARD_J3100 = 12
100
101DI8DEVTYPE_LIMITEDGAMESUBTYPE = 1
102
103DI8DEVTYPEJOYSTICK_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE
104DI8DEVTYPEJOYSTICK_STANDARD = 2
105
106DI8DEVTYPEGAMEPAD_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE
107DI8DEVTYPEGAMEPAD_STANDARD = 2
108DI8DEVTYPEGAMEPAD_TILT = 3
109
110DI8DEVTYPEDRIVING_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE
111DI8DEVTYPEDRIVING_COMBINEDPEDALS = 2
112DI8DEVTYPEDRIVING_DUALPEDALS = 3
113DI8DEVTYPEDRIVING_THREEPEDALS = 4
114DI8DEVTYPEDRIVING_HANDHELD = 5
115
116DI8DEVTYPEFLIGHT_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE
117DI8DEVTYPEFLIGHT_STICK = 2
118DI8DEVTYPEFLIGHT_YOKE = 3
119DI8DEVTYPEFLIGHT_RC = 4
120
121DI8DEVTYPE1STPERSON_LIMITED = DI8DEVTYPE_LIMITEDGAMESUBTYPE
122DI8DEVTYPE1STPERSON_UNKNOWN = 2
123DI8DEVTYPE1STPERSON_SIXDOF = 3
124DI8DEVTYPE1STPERSON_SHOOTER = 4
125
126DI8DEVTYPESCREENPTR_UNKNOWN = 2
127DI8DEVTYPESCREENPTR_LIGHTGUN = 3
128DI8DEVTYPESCREENPTR_LIGHTPEN = 4
129DI8DEVTYPESCREENPTR_TOUCH = 5
130
131DI8DEVTYPEREMOTE_UNKNOWN = 2
132
133DI8DEVTYPEDEVICECTRL_UNKNOWN = 2
134DI8DEVTYPEDEVICECTRL_COMMSSELECTION = 3
135DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED = 4
136
137DI8DEVTYPESUPPLEMENTAL_UNKNOWN = 2
138DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER = 3
139DI8DEVTYPESUPPLEMENTAL_HEADTRACKER = 4
140DI8DEVTYPESUPPLEMENTAL_HANDTRACKER = 5
141DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE = 6
142DI8DEVTYPESUPPLEMENTAL_SHIFTER = 7
143DI8DEVTYPESUPPLEMENTAL_THROTTLE = 8
144DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE = 9
145DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS = 10
146DI8DEVTYPESUPPLEMENTAL_DUALPEDALS = 11
147DI8DEVTYPESUPPLEMENTAL_THREEPEDALS = 12
148DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS = 13
149DIDC_ATTACHED = 0x00000001
150DIDC_POLLEDDEVICE = 0x00000002
151DIDC_EMULATED = 0x00000004
152DIDC_POLLEDDATAFORMAT = 0x00000008
153DIDC_FORCEFEEDBACK = 0x00000100
154DIDC_FFATTACK = 0x00000200
155DIDC_FFFADE = 0x00000400
156DIDC_SATURATION = 0x00000800
157DIDC_POSNEGCOEFFICIENTS = 0x00001000
158DIDC_POSNEGSATURATION = 0x00002000
159DIDC_DEADBAND = 0x00004000
160DIDC_STARTDELAY = 0x00008000
161DIDC_ALIAS = 0x00010000
162DIDC_PHANTOM = 0x00020000
163DIDC_HIDDEN = 0x00040000
164
165def DIDFT_GETINSTANCE(n):
166    return (n >> 8) & 0xffff
167
168DIDFT_ALL = 0x00000000
169
170DIDFT_RELAXIS = 0x00000001
171DIDFT_ABSAXIS = 0x00000002
172DIDFT_AXIS = 0x00000003
173
174DIDFT_PSHBUTTON = 0x00000004
175DIDFT_TGLBUTTON = 0x00000008
176DIDFT_BUTTON = 0x0000000C
177
178DIDFT_POV = 0x00000010
179DIDFT_COLLECTION = 0x00000040
180DIDFT_NODATA = 0x00000080
181
182DIDFT_ANYINSTANCE = 0x00FFFF00
183DIDFT_INSTANCEMASK = DIDFT_ANYINSTANCE
184DIDFT_FFACTUATOR = 0x01000000
185DIDFT_FFEFFECTTRIGGER = 0x02000000
186DIDFT_OUTPUT = 0x10000000
187DIDFT_VENDORDEFINED = 0x04000000
188DIDFT_ALIAS = 0x08000000
189DIDFT_OPTIONAL = 0x80000000
190
191DIDFT_NOCOLLECTION = 0x00FFFF00
192
193DIA_FORCEFEEDBACK = 0x00000001
194DIA_APPMAPPED = 0x00000002
195DIA_APPNOMAP = 0x00000004
196DIA_NORANGE = 0x00000008
197DIA_APPFIXED = 0x00000010
198
199DIAH_UNMAPPED = 0x00000000
200DIAH_USERCONFIG = 0x00000001
201DIAH_APPREQUESTED = 0x00000002
202DIAH_HWAPP = 0x00000004
203DIAH_HWDEFAULT = 0x00000008
204DIAH_DEFAULT = 0x00000020
205DIAH_ERROR = 0x80000000
206DIAFTS_NEWDEVICELOW = 0xFFFFFFFF
207DIAFTS_NEWDEVICEHIGH = 0xFFFFFFFF
208DIAFTS_UNUSEDDEVICELOW = 0x00000000
209DIAFTS_UNUSEDDEVICEHIGH = 0x00000000
210
211DIDBAM_DEFAULT = 0x00000000
212DIDBAM_PRESERVE = 0x00000001
213DIDBAM_INITIALIZE = 0x00000002
214DIDBAM_HWDEFAULTS = 0x00000004
215
216DIDSAM_DEFAULT = 0x00000000
217DIDSAM_NOUSER = 0x00000001
218DIDSAM_FORCESAVE = 0x00000002
219
220DICD_DEFAULT = 0x00000000
221DICD_EDIT = 0x00000001
222
223DIDOI_FFACTUATOR = 0x00000001
224DIDOI_FFEFFECTTRIGGER = 0x00000002
225DIDOI_POLLED = 0x00008000
226DIDOI_ASPECTPOSITION = 0x00000100
227DIDOI_ASPECTVELOCITY = 0x00000200
228DIDOI_ASPECTACCEL = 0x00000300
229DIDOI_ASPECTFORCE = 0x00000400
230DIDOI_ASPECTMASK = 0x00000F00
231DIDOI_GUIDISUSAGE = 0x00010000
232
233DIPH_DEVICE = 0
234DIPH_BYOFFSET = 1
235DIPH_BYID = 2
236DIPH_BYUSAGE = 3
237
238DISCL_EXCLUSIVE = 0x00000001
239DISCL_NONEXCLUSIVE = 0x00000002
240DISCL_FOREGROUND = 0x00000004
241DISCL_BACKGROUND = 0x00000008
242DISCL_NOWINKEY = 0x00000010
243
244DIPROP_BUFFERSIZE = 1
245
246GUID_XAxis = \
247    com.GUID(0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00)
248
249
250class DIDEVICEINSTANCE(ctypes.Structure):
251    _fields_ = (
252        ('dwSize', DWORD),
253        ('guidInstance', com.GUID),
254        ('guidProduct', com.GUID),
255        ('dwDevType', DWORD),
256        ('tszInstanceName', WCHAR * MAX_PATH),
257        ('tszProductName', WCHAR * MAX_PATH),
258        ('guidFFDriver', com.GUID),
259        ('wUsagePage', WORD),
260        ('wUsage', WORD)
261    )
262LPDIDEVICEINSTANCE = ctypes.POINTER(DIDEVICEINSTANCE)
263LPDIENUMDEVICESCALLBACK = ctypes.WINFUNCTYPE(BOOL, LPDIDEVICEINSTANCE, LPVOID)
264
265class DIDEVICEOBJECTINSTANCE(ctypes.Structure):
266    _fields_ = (
267        ('dwSize', DWORD),
268        ('guidType', com.GUID),
269        ('dwOfs', DWORD),
270        ('dwType', DWORD),
271        ('dwFlags', DWORD),
272        ('tszName', WCHAR * MAX_PATH),
273        ('dwFFMaxForce', DWORD),
274        ('dwFFForceResolution', DWORD),
275        ('wCollectionNumber', WORD),
276        ('wDesignatorIndex', WORD),
277        ('wUsagePage', WORD),
278        ('wUsage', WORD),
279        ('dwDimension', DWORD),
280        ('wExponent', WORD),
281        ('wReportId', WORD)
282    )
283LPDIDEVICEOBJECTINSTANCE = ctypes.POINTER(DIDEVICEOBJECTINSTANCE)
284LPDIENUMDEVICEOBJECTSCALLBACK = \
285    ctypes.WINFUNCTYPE( BOOL, LPDIDEVICEOBJECTINSTANCE, LPVOID)
286
287class DIOBJECTDATAFORMAT(ctypes.Structure):
288    _fields_ = (
289        ('pguid', ctypes.POINTER(com.GUID)),
290        ('dwOfs', DWORD),
291        ('dwType', DWORD),
292        ('dwFlags', DWORD)
293    )
294    __slots__ = [n for n, t in _fields_]
295LPDIOBJECTDATAFORMAT = ctypes.POINTER(DIOBJECTDATAFORMAT)
296
297class DIDATAFORMAT(ctypes.Structure):
298    _fields_ = (
299        ('dwSize', DWORD),
300        ('dwObjSize', DWORD),
301        ('dwFlags', DWORD),
302        ('dwDataSize', DWORD),
303        ('dwNumObjs', DWORD),
304        ('rgodf', LPDIOBJECTDATAFORMAT)
305    )
306    __slots__ = [n for n, t in _fields_]
307LPDIDATAFORMAT = ctypes.POINTER(DIDATAFORMAT)
308
309class DIDEVICEOBJECTDATA(ctypes.Structure):
310    _fields_ = (
311        ('dwOfs', DWORD),
312        ('dwData', DWORD),
313        ('dwTimeStamp', DWORD),
314        ('dwSequence', DWORD),
315        ('uAppData', ctypes.POINTER(UINT))
316    )
317LPDIDEVICEOBJECTDATA = ctypes.POINTER(DIDEVICEOBJECTDATA)
318
319class DIPROPHEADER(ctypes.Structure):
320    _fields_ = (
321        ('dwSize', DWORD),
322        ('dwHeaderSize', DWORD),
323        ('dwObj', DWORD),
324        ('dwHow', DWORD)
325    )
326LPDIPROPHEADER = ctypes.POINTER(DIPROPHEADER)
327
328class DIPROPDWORD(ctypes.Structure):
329    _fields_ = (
330        ('diph', DIPROPHEADER),
331        ('dwData', DWORD)
332    )
333
334# All method names in the interfaces are filled in, but unused (so far)
335# methods have no parameters.. they'll crash when we try and use them, at
336# which point we can go in and fill them in.
337
338# IDirect* interfaces are all Unicode (e.g. IDirectInputDevice8W).
339
340class IDirectInputDevice8(com.IUnknown):
341    _methods_ = [
342        ('GetCapabilities',
343         com.STDMETHOD()),
344        ('EnumObjects',
345         com.STDMETHOD(LPDIENUMDEVICEOBJECTSCALLBACK, LPVOID, DWORD)),
346        ('GetProperty',
347         com.STDMETHOD()),
348        ('SetProperty',
349         com.STDMETHOD(LPVOID, LPDIPROPHEADER)),
350        ('Acquire',
351         com.STDMETHOD()),
352        ('Unacquire',
353         com.STDMETHOD()),
354        ('GetDeviceState',
355         com.STDMETHOD()),
356        ('GetDeviceData',
357         com.STDMETHOD(DWORD, LPDIDEVICEOBJECTDATA, LPDWORD, DWORD)),
358        ('SetDataFormat',
359         com.STDMETHOD(LPDIDATAFORMAT)),
360        ('SetEventNotification',
361         com.STDMETHOD(HANDLE)),
362        ('SetCooperativeLevel',
363         com.STDMETHOD(HWND, DWORD)),
364        ('GetObjectInfo',
365         com.STDMETHOD()),
366        ('GetDeviceInfo',
367         com.STDMETHOD()),
368        ('RunControlPanel',
369         com.STDMETHOD()),
370        ('Initialize',
371         com.STDMETHOD()),
372        ('CreateEffect',
373         com.STDMETHOD()),
374        ('EnumEffects',
375         com.STDMETHOD()),
376        ('GetEffectInfo',
377         com.STDMETHOD()),
378        ('GetForceFeedbackState',
379         com.STDMETHOD()),
380        ('SendForceFeedbackCommand',
381         com.STDMETHOD()),
382        ('EnumCreatedEffectObjects',
383         com.STDMETHOD()),
384        ('Escape',
385         com.STDMETHOD()),
386        ('Poll',
387         com.STDMETHOD()),
388        ('SendDeviceData',
389         com.STDMETHOD()),
390        ('EnumEffectsInFile',
391         com.STDMETHOD()),
392        ('WriteEffectToFile',
393         com.STDMETHOD()),
394        ('BuildActionMap',
395         com.STDMETHOD()),
396        ('SetActionMap',
397         com.STDMETHOD()),
398        ('GetImageInfo',
399         com.STDMETHOD()),
400     ]
401
402class IDirectInput8(com.IUnknown):
403    _methods_ = [
404        ('CreateDevice',
405         com.STDMETHOD(ctypes.POINTER(com.GUID),
406                       ctypes.POINTER(IDirectInputDevice8),
407                       ctypes.c_void_p)),
408        ('EnumDevices',
409         com.STDMETHOD(DWORD, LPDIENUMDEVICESCALLBACK, LPVOID, DWORD)),
410        ('GetDeviceStatus',
411         com.STDMETHOD()),
412        ('RunControlPanel',
413         com.STDMETHOD()),
414        ('Initialize',
415         com.STDMETHOD()),
416        ('FindDevice',
417         com.STDMETHOD()),
418        ('EnumDevicesBySemantics',
419         com.STDMETHOD()),
420        ('ConfigureDevices',
421         com.STDMETHOD()),
422    ]
423
424IID_IDirectInput8W = \
425    com.GUID(0xBF798031,0x483A,0x4DA2,0xAA,0x99,0x5D,0x64,0xED,0x36,0x97,0x00)
426
427DIRECTINPUT_VERSION = 0x0800
428DirectInput8Create = lib.DirectInput8Create
429DirectInput8Create.argtypes = \
430    (ctypes.c_void_p, DWORD, com.LPGUID, ctypes.c_void_p, ctypes.c_void_p)
431
432