1 USING: accessors alien alien.c-types alien.strings arrays
2 assocs byte-arrays combinators continuations game-input
3 game-input.dinput.keys-array io.encodings.utf16
4 io.encodings.utf16n kernel locals math math.bitwise
5 math.rectangles namespaces parser sequences shuffle
6 struct-arrays ui.backend.windows vectors windows.com
7 windows.dinput windows.dinput.constants windows.errors
8 windows.kernel32 windows.messages windows.ole32
9 windows.user32 classes.struct ;
11 CONSTANT: MOUSE-BUFFER-SIZE 16
13 SINGLETON: dinput-game-input-backend
15 dinput-game-input-backend game-input-backend set-global
17 SYMBOLS: +dinput+ +keyboard-device+ +keyboard-state+
18 +controller-devices+ +controller-guids+
19 +device-change-window+ +device-change-handle+
20 +mouse-device+ +mouse-state+ +mouse-buffer+ ;
22 : create-dinput ( -- )
23 f GetModuleHandle DIRECTINPUT_VERSION IDirectInput8W-iid
24 f <void*> [ f DirectInput8Create ole32-error ] keep *void*
27 : delete-dinput ( -- )
28 +dinput+ [ com-release f ] change-global ;
30 : device-for-guid ( guid -- device )
31 +dinput+ get swap f <void*>
32 [ f IDirectInput8W::CreateDevice ole32-error ] keep *void* ;
34 : set-coop-level ( device -- )
35 +device-change-window+ get DISCL_BACKGROUND DISCL_NONEXCLUSIVE bitor
36 IDirectInputDevice8W::SetCooperativeLevel ole32-error ;
38 : set-data-format ( device format-symbol -- )
39 get IDirectInputDevice8W::SetDataFormat ole32-error ;
41 : <buffer-size-diprop> ( size -- DIPROPDWORD )
42 DIPROPDWORD <struct> [
44 DIPROPDWORD heap-size >>dwSize
45 DIPROPHEADER heap-size >>dwHeaderSize
49 ] keep swap >>dwData ;
51 : set-buffer-size ( device size -- )
52 DIPROP_BUFFERSIZE swap <buffer-size-diprop>
53 IDirectInputDevice8W::SetProperty ole32-error ;
55 : configure-keyboard ( keyboard -- )
56 [ c_dfDIKeyboard_HID set-data-format ] [ set-coop-level ] bi ;
57 : configure-mouse ( mouse -- )
58 [ c_dfDIMouse2 set-data-format ]
59 [ MOUSE-BUFFER-SIZE set-buffer-size ]
60 [ set-coop-level ] tri ;
61 : configure-controller ( controller -- )
62 [ c_dfDIJoystick2 set-data-format ] [ set-coop-level ] bi ;
64 : find-keyboard ( -- )
65 GUID_SysKeyboard device-for-guid
66 [ configure-keyboard ]
67 [ +keyboard-device+ set-global ] bi
68 256 <byte-array> 256 <keys-array> keyboard-state boa
69 +keyboard-state+ set-global ;
72 GUID_SysMouse device-for-guid
74 [ +mouse-device+ set-global ] bi
75 0 0 0 0 8 f <array> mouse-state boa
76 +mouse-state+ set-global
77 MOUSE-BUFFER-SIZE DIDEVICEOBJECTDATA <struct-array>
78 +mouse-buffer+ set-global ;
80 : device-info ( device -- DIDEVICEIMAGEINFOW )
81 DIDEVICEINSTANCEW <struct>
82 DIDEVICEINSTANCEW heap-size >>dwSize
83 [ IDirectInputDevice8W::GetDeviceInfo ole32-error ] keep ; inline
84 : device-caps ( device -- DIDEVCAPS )
86 DIDEVCAPS heap-size >>dwSize
87 [ IDirectInputDevice8W::GetCapabilities ole32-error ] keep ; inline
89 : device-guid ( device -- guid )
90 device-info guidInstance>> ; inline
92 : device-attached? ( device -- ? )
93 +dinput+ get swap device-guid
94 IDirectInput8W::GetDeviceStatus S_OK = ;
96 : find-device-axes-callback ( -- alien )
97 [ ! ( lpddoi pvRef -- BOOL )
98 [ DIDEVICEOBJECTINSTANCEW memory>struct ] dip
99 +controller-devices+ get at
101 { [ dup GUID_XAxis = ] [ drop 0.0 >>x ] }
102 { [ dup GUID_YAxis = ] [ drop 0.0 >>y ] }
103 { [ dup GUID_ZAxis = ] [ drop 0.0 >>z ] }
104 { [ dup GUID_RxAxis = ] [ drop 0.0 >>rx ] }
105 { [ dup GUID_RyAxis = ] [ drop 0.0 >>ry ] }
106 { [ dup GUID_RzAxis = ] [ drop 0.0 >>rz ] }
107 { [ dup GUID_Slider = ] [ drop 0.0 >>slider ] }
111 ] LPDIENUMDEVICEOBJECTSCALLBACKW ;
113 : find-device-axes ( device controller-state -- controller-state )
114 swap [ +controller-devices+ get set-at ] 2keep
115 find-device-axes-callback over DIDFT_AXIS
116 IDirectInputDevice8W::EnumObjects ole32-error ;
118 : controller-state-template ( device -- controller-state )
121 [ dwButtons>> f <array> >>buttons ]
122 [ dwPOVs>> zero? f pov-neutral ? >>pov ] bi
125 : device-known? ( guid -- ? )
126 +controller-guids+ get key? ; inline
128 : (add-controller) ( guid -- )
130 [ configure-controller ]
131 [ controller-state-template ]
132 [ dup device-guid clone +controller-guids+ get set-at ]
133 [ +controller-devices+ get set-at ]
136 : add-controller ( guid -- )
137 dup device-known? [ drop ] [ (add-controller) ] if ;
139 : remove-controller ( device -- )
140 [ +controller-devices+ get delete-at ]
141 [ device-guid +controller-guids+ get delete-at ]
142 [ com-release ] tri ;
144 : find-controller-callback ( -- alien )
145 [ ! ( lpddi pvRef -- BOOL )
146 drop DIDEVICEINSTANCEW memory>struct guidInstance>> add-controller
148 ] LPDIENUMDEVICESCALLBACKW ; inline
150 : find-controllers ( -- )
151 +dinput+ get DI8DEVCLASS_GAMECTRL find-controller-callback
152 f DIEDFL_ATTACHEDONLY IDirectInput8W::EnumDevices ole32-error ;
154 : set-up-controllers ( -- )
155 4 <vector> +controller-devices+ set-global
156 4 <vector> +controller-guids+ set-global
159 : find-and-remove-detached-devices ( -- )
160 +controller-devices+ get keys
161 [ device-attached? not ] filter
162 [ remove-controller ] each ;
164 : device-interface? ( dbt-broadcast-hdr -- ? )
165 dbch_devicetype>> DBT_DEVTYP_DEVICEINTERFACE = ;
167 : device-arrived ( dbt-broadcast-hdr -- )
168 device-interface? [ find-controllers ] when ;
170 : device-removed ( dbt-broadcast-hdr -- )
171 device-interface? [ find-and-remove-detached-devices ] when ;
173 : handle-wm-devicechange ( hWnd uMsg wParam lParam -- )
174 [ 2drop ] 2dip swap {
175 { [ dup DBT_DEVICEARRIVAL = ] [ drop <alien> device-arrived ] }
176 { [ dup DBT_DEVICEREMOVECOMPLETE = ] [ drop <alien> device-removed ] }
180 TUPLE: window-rect < rect window-loc ;
181 : <zero-window-rect> ( -- window-rect )
187 : (device-notification-filter) ( -- DEV_BROADCAST_DEVICEW )
188 DEV_BROADCAST_DEVICEW <struct>
189 DEV_BROADCAST_DEVICEW heap-size >>dbcc_size
190 DBT_DEVTYP_DEVICEINTERFACE >>dbcc_devicetype ;
192 : create-device-change-window ( -- )
193 <zero-window-rect> WS_OVERLAPPEDWINDOW 0 create-window
195 (device-notification-filter)
196 DEVICE_NOTIFY_WINDOW_HANDLE DEVICE_NOTIFY_ALL_INTERFACE_CLASSES bitor
197 RegisterDeviceNotification
198 +device-change-handle+ set-global
200 [ +device-change-window+ set-global ] bi ;
202 : close-device-change-window ( -- )
203 +device-change-handle+ [ UnregisterDeviceNotification drop f ] change-global
204 +device-change-window+ [ DestroyWindow win32-error=0/f f ] change-global ;
206 : add-wm-devicechange ( -- )
207 [ 4dup handle-wm-devicechange DefWindowProc ]
208 WM_DEVICECHANGE add-wm-handler ;
210 : remove-wm-devicechange ( -- )
211 WM_DEVICECHANGE wm-handlers get-global delete-at ;
213 : release-controllers ( -- )
214 +controller-devices+ [ [ drop com-release ] assoc-each f ] change-global
215 f +controller-guids+ set-global ;
217 : release-keyboard ( -- )
218 +keyboard-device+ [ com-release f ] change-global
219 f +keyboard-state+ set-global ;
221 : release-mouse ( -- )
222 +mouse-device+ [ com-release f ] change-global
223 f +mouse-state+ set-global ;
225 M: dinput-game-input-backend (open-game-input)
227 create-device-change-window
231 add-wm-devicechange ;
233 M: dinput-game-input-backend (close-game-input)
234 remove-wm-devicechange
238 close-device-change-window
241 M: dinput-game-input-backend (reset-game-input)
244 +dinput+ +keyboard-device+ +keyboard-state+
245 +controller-devices+ +controller-guids+
246 +device-change-window+ +device-change-handle+
250 M: dinput-game-input-backend get-controllers
251 +controller-devices+ get
252 [ drop controller boa ] { } assoc>map ;
254 M: dinput-game-input-backend product-string
255 handle>> device-info tszProductName>>
256 utf16n alien>string ;
258 M: dinput-game-input-backend product-id
259 handle>> device-info guidProduct>> ;
260 M: dinput-game-input-backend instance-id
261 handle>> device-guid ;
263 :: with-acquisition ( device acquired-quot succeeded-quot failed-quot -- result/f )
264 device IDirectInputDevice8W::Acquire succeeded? [
265 device acquired-quot call
267 ] failed-quot if ; inline
271 pov-up pov-up-right pov-right pov-down-right
272 pov-down pov-down-left pov-left pov-up-left
275 : >axis ( long -- float )
276 32767 - 32767.0 /f ; inline
277 : >slider ( long -- float )
279 : >pov ( long -- symbol )
280 dup HEX: FFFF bitand HEX: FFFF =
282 [ 2750 + 4500 /i pov-values nth ] if ; inline
284 : (fill-if) ( controller-state DIJOYSTATE2 ? quot -- )
285 [ drop ] compose [ 2drop ] if ; inline
287 : fill-controller-state ( controller-state DIJOYSTATE2 -- controller-state )
289 [ over x>> [ lX>> >axis >>x ] (fill-if) ]
290 [ over y>> [ lY>> >axis >>y ] (fill-if) ]
291 [ over z>> [ lZ>> >axis >>z ] (fill-if) ]
292 [ over rx>> [ lRx>> >axis >>rx ] (fill-if) ]
293 [ over ry>> [ lRy>> >axis >>ry ] (fill-if) ]
294 [ over rz>> [ lRz>> >axis >>rz ] (fill-if) ]
295 [ over slider>> [ rglSlider>> first >slider >>slider ] (fill-if) ]
296 [ over pov>> [ rgdwPOV>> first >pov >>pov ] (fill-if) ]
297 [ rgbButtons>> over buttons>> length <keys-array> >>buttons ]
300 : read-device-buffer ( device buffer count -- buffer count' )
301 [ DIDEVICEOBJECTDATA heap-size ] 2dip <uint>
302 [ 0 IDirectInputDevice8W::GetDeviceData ole32-error ] 2keep *uint ;
304 : (fill-mouse-state) ( state DIDEVICEOBJECTDATA -- state )
305 [ dwData>> 32 >signed ] [ dwOfs>> ] bi {
306 { DIMOFS_X [ [ + ] curry change-dx ] }
307 { DIMOFS_Y [ [ + ] curry change-dy ] }
308 { DIMOFS_Z [ [ + ] curry change-scroll-dy ] }
309 [ [ c-bool> ] [ DIMOFS_BUTTON0 - ] bi* rot [ buttons>> set-nth ] keep ]
312 : fill-mouse-state ( buffer count -- state )
313 [ +mouse-state+ get ] 2dip swap [ nth (fill-mouse-state) ] curry each ;
315 : get-device-state ( device DIJOYSTATE2 -- )
316 [ dup IDirectInputDevice8W::Poll ole32-error ] dip
318 IDirectInputDevice8W::GetDeviceState ole32-error ;
320 : (read-controller) ( handle template -- state )
321 swap [ DIJOYSTATE2 <struct> [ get-device-state ] keep ]
322 [ fill-controller-state ] [ drop f ] with-acquisition ;
324 M: dinput-game-input-backend read-controller
325 handle>> dup +controller-devices+ get at
326 [ (read-controller) ] [ drop f ] if* ;
328 M: dinput-game-input-backend calibrate-controller
329 handle>> f 0 IDirectInputDevice8W::RunControlPanel ole32-error ;
331 M: dinput-game-input-backend read-keyboard
332 +keyboard-device+ get
333 [ +keyboard-state+ get [ keys>> underlying>> get-device-state ] keep ]
334 [ ] [ f ] with-acquisition ;
336 M: dinput-game-input-backend read-mouse
337 +mouse-device+ get [ +mouse-buffer+ get MOUSE-BUFFER-SIZE read-device-buffer ]
338 [ fill-mouse-state ] [ f ] with-acquisition ;
340 M: dinput-game-input-backend reset-mouse
341 +mouse-device+ get [ f MOUSE-BUFFER-SIZE read-device-buffer ]
342 [ 2drop ] [ ] with-acquisition