1 USING: accessors alien alien.c-types alien.data alien.strings
2 arrays assocs byte-arrays combinators combinators.short-circuit
3 continuations game.input game.input.dinput.keys-array
4 io.encodings.utf16n kernel locals math
5 math.bitwise math.rectangles namespaces parser sequences shuffle
6 specialized-arrays ui.backend.windows vectors windows.com
7 windows.directx.dinput windows.directx.dinput.constants
8 windows.kernel32 windows.messages windows.ole32 windows.errors
9 windows.user32 classes.struct ;
10 SPECIALIZED-ARRAY: DIDEVICEOBJECTDATA
13 CONSTANT: MOUSE-BUFFER-SIZE 16
15 SINGLETON: dinput-game-input-backend
17 dinput-game-input-backend game-input-backend set-global
19 SYMBOLS: +dinput+ +keyboard-device+ +keyboard-state+
20 +controller-devices+ +controller-guids+
21 +device-change-window+ +device-change-handle+
22 +mouse-device+ +mouse-state+ +mouse-buffer+ ;
24 : create-dinput ( -- )
25 f GetModuleHandle DIRECTINPUT_VERSION IDirectInput8W-iid
26 f void* <ref> [ f DirectInput8Create check-ole32-error ] keep void* deref
29 : delete-dinput ( -- )
30 +dinput+ [ com-release f ] change-global ;
32 : device-for-guid ( guid -- device )
33 +dinput+ get-global swap f void* <ref>
34 [ f IDirectInput8W::CreateDevice check-ole32-error ] keep void* deref ;
36 : set-coop-level ( device -- )
37 +device-change-window+ get-global DISCL_BACKGROUND DISCL_NONEXCLUSIVE bitor
38 IDirectInputDevice8W::SetCooperativeLevel check-ole32-error ; inline
40 : set-data-format ( device format-symbol -- )
41 get-global IDirectInputDevice8W::SetDataFormat check-ole32-error ; inline
43 : <buffer-size-diprop> ( size -- DIPROPDWORD )
46 DIPROPDWORD heap-size >>dwSize
47 DIPROPHEADER heap-size >>dwHeaderSize
51 ] keep swap >>dwData ;
53 : set-buffer-size ( device size -- )
54 DIPROP_BUFFERSIZE swap <buffer-size-diprop>
55 IDirectInputDevice8W::SetProperty check-ole32-error ;
57 : configure-keyboard ( keyboard -- )
58 [ c_dfDIKeyboard_HID set-data-format ] [ set-coop-level ] bi ;
59 : configure-mouse ( mouse -- )
60 [ c_dfDIMouse2 set-data-format ]
61 [ MOUSE-BUFFER-SIZE set-buffer-size ]
62 [ set-coop-level ] tri ;
63 : configure-controller ( controller -- )
64 [ c_dfDIJoystick2 set-data-format ] [ set-coop-level ] bi ;
66 : find-keyboard ( -- )
67 GUID_SysKeyboard device-for-guid
68 [ configure-keyboard ]
69 [ +keyboard-device+ set-global ] bi
70 256 <byte-array> 256 <keys-array> keyboard-state boa
71 +keyboard-state+ set-global ;
74 GUID_SysMouse device-for-guid
75 [ configure-mouse ] [ +mouse-device+ set-global ] bi
76 0 0 0 0 8 f <array> mouse-state boa +mouse-state+ set-global
77 MOUSE-BUFFER-SIZE DIDEVICEOBJECTDATA <c-array> +mouse-buffer+ set-global ;
79 : device-info ( device -- DIDEVICEIMAGEINFOW )
81 DIDEVICEINSTANCEW heap-size >>dwSize
82 [ IDirectInputDevice8W::GetDeviceInfo check-ole32-error ] keep ; inline
83 : device-caps ( device -- DIDEVCAPS )
85 DIDEVCAPS heap-size >>dwSize
86 [ IDirectInputDevice8W::GetCapabilities check-ole32-error ] keep ; inline
88 : device-guid ( device -- guid )
89 device-info guidInstance>> ; inline
91 : device-attached? ( device -- ? )
92 +dinput+ get swap device-guid
93 IDirectInput8W::GetDeviceStatus S_OK = ;
95 : (find-device-axes-callback) ( lpddoi pvRef -- BOOL )
96 +controller-devices+ get-global at
98 { [ dup GUID_XAxis = ] [ drop 0.0 >>x ] }
99 { [ dup GUID_YAxis = ] [ drop 0.0 >>y ] }
100 { [ dup GUID_ZAxis = ] [ drop 0.0 >>z ] }
101 { [ dup GUID_RxAxis = ] [ drop 0.0 >>rx ] }
102 { [ dup GUID_RyAxis = ] [ drop 0.0 >>ry ] }
103 { [ dup GUID_RzAxis = ] [ drop 0.0 >>rz ] }
104 { [ dup GUID_Slider = ] [ drop 0.0 >>slider ] }
109 : find-device-axes-callback ( -- alien )
110 [ (find-device-axes-callback) ] LPDIENUMDEVICEOBJECTSCALLBACKW ;
112 : find-device-axes ( device controller-state -- controller-state )
113 swap [ +controller-devices+ get-global set-at ] 2keep
114 find-device-axes-callback over DIDFT_AXIS
115 IDirectInputDevice8W::EnumObjects check-ole32-error ;
117 : controller-state-template ( device -- controller-state )
120 [ dwButtons>> f <array> >>buttons ]
121 [ dwPOVs>> zero? f pov-neutral ? >>pov ] bi
124 : device-known? ( guid -- ? )
125 +controller-guids+ get-global key? ; inline
127 : (add-controller) ( guid -- )
129 [ configure-controller ]
130 [ controller-state-template ]
131 [ dup device-guid clone +controller-guids+ get-global set-at ]
132 [ +controller-devices+ get-global set-at ]
135 : add-controller ( guid -- )
136 dup device-known? [ drop ] [ (add-controller) ] if ;
138 : remove-controller ( device -- )
139 [ +controller-devices+ get-global delete-at ]
140 [ device-guid +controller-guids+ get-global delete-at ]
141 [ com-release ] tri ;
143 : (find-controller-callback) ( lpddi pvRef -- BOOL )
144 drop guidInstance>> add-controller
147 : find-controller-callback ( -- alien )
148 [ (find-controller-callback) ] LPDIENUMDEVICESCALLBACKW ;
150 : find-controllers ( -- )
151 +dinput+ get-global DI8DEVCLASS_GAMECTRL find-controller-callback
152 f DIEDFL_ATTACHEDONLY IDirectInput8W::EnumDevices check-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-global keys
161 [ device-attached? ] reject
162 [ remove-controller ] each ;
164 : ?device-interface ( dbt-broadcast-hdr -- ? )
165 dup dbch_devicetype>> DBT_DEVTYP_DEVICEINTERFACE =
166 [ >c-ptr DEV_BROADCAST_DEVICEW memory>struct ]
167 [ drop f ] if ; inline
169 : device-arrived ( dbt-broadcast-hdr -- )
170 ?device-interface [ find-controllers ] when ; inline
172 : device-removed ( dbt-broadcast-hdr -- )
173 ?device-interface [ find-and-remove-detached-devices ] when ; inline
175 : <DEV_BROADCAST_HDR> ( wParam -- struct )
176 <alien> DEV_BROADCAST_HDR memory>struct ;
178 : handle-wm-devicechange ( hWnd uMsg wParam lParam -- )
180 { [ dup DBT_DEVICEARRIVAL = ] [ drop <DEV_BROADCAST_HDR> device-arrived ] }
181 { [ dup DBT_DEVICEREMOVECOMPLETE = ] [ drop <DEV_BROADCAST_HDR> device-removed ] }
185 TUPLE: window-rect < rect window-loc ;
186 : <zero-window-rect> ( -- window-rect )
192 : (device-notification-filter) ( -- DEV_BROADCAST_DEVICEW )
193 DEV_BROADCAST_DEVICEW new
194 DEV_BROADCAST_DEVICEW heap-size >>dbcc_size
195 DBT_DEVTYP_DEVICEINTERFACE >>dbcc_devicetype ;
197 : create-device-change-window ( -- )
198 <zero-window-rect> WS_OVERLAPPEDWINDOW 0 create-window
200 (device-notification-filter)
201 DEVICE_NOTIFY_WINDOW_HANDLE DEVICE_NOTIFY_ALL_INTERFACE_CLASSES bitor
202 RegisterDeviceNotification
203 +device-change-handle+ set-global
205 [ +device-change-window+ set-global ] bi ;
207 : close-device-change-window ( -- )
208 +device-change-handle+ [ UnregisterDeviceNotification drop f ] change-global
209 +device-change-window+ [ DestroyWindow win32-error=0/f f ] change-global ;
211 : add-wm-devicechange ( -- )
212 [ 4dup handle-wm-devicechange DefWindowProc ]
213 WM_DEVICECHANGE add-wm-handler ;
215 : remove-wm-devicechange ( -- )
216 WM_DEVICECHANGE wm-handlers get-global delete-at ;
218 : release-controllers ( -- )
219 +controller-devices+ [ [ drop com-release ] assoc-each f ] change-global
220 f +controller-guids+ set-global ;
222 : release-keyboard ( -- )
223 +keyboard-device+ [ com-release f ] change-global
224 f +keyboard-state+ set-global ;
226 : release-mouse ( -- )
227 +mouse-device+ [ com-release f ] change-global
228 f +mouse-state+ set-global ;
230 M: dinput-game-input-backend (open-game-input)
232 create-device-change-window
236 add-wm-devicechange ;
238 M: dinput-game-input-backend (close-game-input)
239 remove-wm-devicechange
243 close-device-change-window
246 M: dinput-game-input-backend (reset-game-input)
249 +dinput+ +keyboard-device+ +keyboard-state+
250 +controller-devices+ +controller-guids+
251 +device-change-window+ +device-change-handle+
255 M: dinput-game-input-backend get-controllers
256 +controller-devices+ get-global
257 [ drop controller boa ] { } assoc>map ;
259 M: dinput-game-input-backend product-string
260 handle>> device-info tszProductName>>
261 alien>native-string ;
263 M: dinput-game-input-backend product-id
264 handle>> device-info guidProduct>> ;
265 M: dinput-game-input-backend instance-id
266 handle>> device-guid ;
268 :: with-acquisition ( device acquired-quot succeeded-quot failed-quot -- result/f )
269 device { [ ] [ IDirectInputDevice8W::Acquire succeeded? ] } 1&& [
270 device acquired-quot call
272 ] failed-quot if ; inline
276 pov-up pov-up-right pov-right pov-down-right
277 pov-down pov-down-left pov-left pov-up-left
280 : >axis ( long -- float )
281 32767 - 32767.0 /f ; inline
282 : >slider ( long -- float )
284 : >pov ( long -- symbol )
285 dup 0xFFFF bitand 0xFFFF =
287 [ 2750 + 4500 /i pov-values nth ] if ; inline
289 : (fill-if) ( controller-state DIJOYSTATE2 ? quot -- )
290 [ drop ] compose [ 2drop ] if ; inline
292 : fill-controller-state ( controller-state DIJOYSTATE2 -- controller-state )
294 [ over x>> [ lX>> >axis >>x ] (fill-if) ]
295 [ over y>> [ lY>> >axis >>y ] (fill-if) ]
296 [ over z>> [ lZ>> >axis >>z ] (fill-if) ]
297 [ over rx>> [ lRx>> >axis >>rx ] (fill-if) ]
298 [ over ry>> [ lRy>> >axis >>ry ] (fill-if) ]
299 [ over rz>> [ lRz>> >axis >>rz ] (fill-if) ]
300 [ over slider>> [ rglSlider>> first >slider >>slider ] (fill-if) ]
301 [ over pov>> [ rgdwPOV>> first >pov >>pov ] (fill-if) ]
302 [ rgbButtons>> over buttons>> length <keys-array> >>buttons ]
305 : read-device-buffer ( device buffer count -- buffer count' )
306 [ DIDEVICEOBJECTDATA heap-size ] 2dip uint <ref>
307 [ 0 IDirectInputDevice8W::GetDeviceData check-ole32-error ] 2keep uint deref ;
309 : (fill-mouse-state) ( state DIDEVICEOBJECTDATA -- state )
310 [ dwData>> 32 >signed ] [ dwOfs>> ] bi {
311 { DIMOFS_X [ [ + ] curry change-dx ] }
312 { DIMOFS_Y [ [ + ] curry change-dy ] }
313 { DIMOFS_Z [ [ + ] curry change-scroll-dy ] }
314 [ [ c-bool> ] [ DIMOFS_BUTTON0 - ] bi* rot [ buttons>> set-nth ] keep ]
317 : fill-mouse-state ( buffer count -- state )
318 <iota> [ +mouse-state+ get-global ] 2dip swap [ nth (fill-mouse-state) ] curry each ;
320 : get-device-state ( device DIJOYSTATE2 -- )
321 [ dup IDirectInputDevice8W::Poll check-ole32-error ] dip
323 IDirectInputDevice8W::GetDeviceState check-ole32-error ;
325 : (read-controller) ( handle template -- state )
326 swap [ DIJOYSTATE2 new [ get-device-state ] keep ]
327 [ fill-controller-state ] [ drop f ] with-acquisition ;
329 M: dinput-game-input-backend read-controller
330 handle>> dup +controller-devices+ get-global at
331 [ (read-controller) ] [ drop f ] if* ;
333 M: dinput-game-input-backend calibrate-controller
334 handle>> f 0 IDirectInputDevice8W::RunControlPanel check-ole32-error ;
336 M: dinput-game-input-backend read-keyboard
337 +keyboard-device+ get-global
338 [ +keyboard-state+ get-global [ keys>> underlying>> get-device-state ] keep ]
339 [ ] [ f ] with-acquisition ;
341 M: dinput-game-input-backend read-mouse
342 +mouse-device+ get-global [ +mouse-buffer+ get-global MOUSE-BUFFER-SIZE read-device-buffer ]
343 [ fill-mouse-state ] [ f ] with-acquisition ;
345 M: dinput-game-input-backend reset-mouse
346 +mouse-device+ get-global [ f MOUSE-BUFFER-SIZE read-device-buffer ]
347 [ 2drop ] [ ] with-acquisition
348 +mouse-state+ get-global