77using BizHawk . Common ;
88using BizHawk . Common . CollectionExtensions ;
99
10+ using Windows . Win32 ;
11+ using Windows . Win32 . Foundation ;
12+ using Windows . Win32 . UI . Input ;
13+ using Windows . Win32 . UI . Input . KeyboardAndMouse ;
14+ using Windows . Win32 . UI . WindowsAndMessaging ;
15+
1016using static BizHawk . Common . RawInputImports ;
11- using static BizHawk . Common . WmImports ;
17+ using static BizHawk . Common . WmImports1 ;
18+ using static Windows . Win32 . Win32Imports ;
1219
1320namespace BizHawk . Bizware . Input
1421{
1522 /// <summary>
1623 /// Note: Only 1 window per device class (e.g. keyboards) is actually allowed to use RAWINPUT (last one to call RegisterRawInputDevices)
1724 /// So only one instance can actually be used at the same time
1825 /// </summary>
19- internal sealed class RawKeyMouseInput : IKeyMouseInput
26+ internal sealed unsafe class RawKeyMouseInput : IKeyMouseInput
2027 {
2128 private const int WM_CLOSE = 0x0010 ;
2229 private const int WM_INPUT = 0x00FF ;
2330
24- private IntPtr RawInputWindow ;
31+ private HWND RawInputWindow ;
2532 private bool _handleAltKbLayouts ;
2633 private List < KeyEvent > _keyEvents = [ ] ;
2734 private ( int X , int Y ) _mouseDelta ;
@@ -33,27 +40,29 @@ internal sealed class RawKeyMouseInput : IKeyMouseInput
3340 private int RawInputBufferSize ;
3441 private readonly int RawInputBufferDataOffset ;
3542
36- private static readonly WNDPROC _wndProc = WndProc ;
37-
38- private static readonly Lazy < IntPtr > _rawInputWindowAtom = new ( ( ) =>
43+ private static unsafe readonly Lazy < PCWSTR > _rawInputWindowAtom = new ( ( ) =>
3944 {
40- var wc = default ( WNDCLASSW ) ;
41- wc . lpfnWndProc = _wndProc ;
42- wc . hInstance = LoaderApiImports . GetModuleHandleW ( null ) ;
43- wc . lpszClassName = "RawKeyMouseInputClass" ;
44-
45- var atom = RegisterClassW ( ref wc ) ;
46- if ( atom == IntPtr . Zero )
45+ WNDCLASSW wc = default ;
46+ wc . lpfnWndProc = WndProc ;
47+ wc . hInstance = GetModuleHandleW ( default ( PCWSTR ) ) ;
48+ var lpszClassNameStr = "RawKeyMouseInputClass" ;
49+ PCWSTR atom ;
50+ fixed ( char * lpszClassName = lpszClassNameStr )
51+ {
52+ wc . lpszClassName = lpszClassName ;
53+ atom = MAKEINTATOM ( RegisterClassW ( in wc ) ) ;
54+ }
55+ if ( atom . Value is null )
4756 {
4857 throw new InvalidOperationException ( "Failed to register RAWINPUT window class" ) ;
4958 }
5059
5160 return atom ;
5261 } ) ;
5362
54- private static unsafe IntPtr WndProc ( IntPtr hWnd , uint uMsg , IntPtr wParam , IntPtr lParam )
63+ private static LRESULT WndProc ( HWND hWnd , uint uMsg , WPARAM wParam , LPARAM lParam )
5564 {
56- var ud = GetWindowLongPtrW ( hWnd , GWLP_USERDATA ) ;
65+ var ud = GetWindowLongPtrW ( hWnd , WINDOW_LONG_PTR_INDEX . GWLP_USERDATA ) ;
5766 if ( ud == IntPtr . Zero )
5867 {
5968 return DefWindowProcW ( hWnd , uMsg , wParam , lParam ) ;
@@ -65,7 +74,7 @@ private static unsafe IntPtr WndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntP
6574 {
6675 if ( uMsg == WM_CLOSE )
6776 {
68- SetWindowLongPtrW ( hWnd , GWLP_USERDATA , IntPtr . Zero ) ;
77+ SetWindowLongPtrW ( hWnd , WINDOW_LONG_PTR_INDEX . GWLP_USERDATA , IntPtr . Zero ) ;
6978 handle = GCHandle . FromIntPtr ( ud ) ;
7079 rawKeyMouseInput = ( RawKeyMouseInput ) handle . Target ;
7180 Marshal . FreeCoTaskMem ( rawKeyMouseInput . RawInputBuffer ) ;
@@ -75,36 +84,48 @@ private static unsafe IntPtr WndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntP
7584 return DefWindowProcW ( hWnd , uMsg , wParam , lParam ) ;
7685 }
7786
78- if ( GetRawInputData ( lParam , RID . INPUT , IntPtr . Zero ,
79- out var size , sizeof ( RAWINPUTHEADER ) ) == - 1 )
87+ uint size = default ;
88+ if ( GetRawInputData (
89+ new ( lParam ) ,
90+ RAW_INPUT_DATA_COMMAND_FLAGS . RID_INPUT ,
91+ pData : default ,
92+ ref size ,
93+ cbSizeHeader : unchecked ( ( uint ) sizeof ( RAWINPUTHEADER ) ) )
94+ is uint . MaxValue /*-1*/ )
8095 {
8196 return DefWindowProcW ( hWnd , uMsg , wParam , lParam ) ;
8297 }
8398
8499 // don't think size should ever be this big, but just in case
100+ var allocOnHeap = size > 1024 ;
85101 // also, make sure to align the buffer to a pointer boundary
86- var buffer = size > 1024
87- ? new IntPtr [ ( size + sizeof ( IntPtr ) - 1 ) / sizeof ( IntPtr ) ]
88- : stackalloc IntPtr [ ( size + sizeof ( IntPtr ) - 1 ) / sizeof ( IntPtr ) ] ;
102+ var roundedSize = unchecked ( ( int ) ( size / sizeof ( IntPtr ) ) ) ;
103+ if ( ( size & 0b11U ) is not 0U ) roundedSize ++ ;
104+ var buffer = allocOnHeap ? new IntPtr [ roundedSize ] : stackalloc IntPtr [ roundedSize ] ;
89105
90106 handle = GCHandle . FromIntPtr ( ud ) ;
91107 rawKeyMouseInput = ( RawKeyMouseInput ) handle . Target ;
92108
93109 fixed ( IntPtr * p = buffer )
94110 {
95111 var input = ( RAWINPUT * ) p ;
96- if ( GetRawInputData ( lParam , RID . INPUT , input ,
97- ref size , sizeof ( RAWINPUTHEADER ) ) == - 1 )
112+ if ( GetRawInputData (
113+ new ( lParam ) ,
114+ RAW_INPUT_DATA_COMMAND_FLAGS . RID_INPUT ,
115+ pData : input ,
116+ ref size ,
117+ cbSizeHeader : unchecked ( ( uint ) sizeof ( RAWINPUTHEADER ) ) )
118+ is uint . MaxValue /*-1*/ )
98119 {
99120 return DefWindowProcW ( hWnd , uMsg , wParam , lParam ) ;
100121 }
101122
102- if ( input ->header . dwType == RAWINPUTHEADER . RIM_TYPE . KEYBOARD )
123+ if ( input ->header . dwType == RIM_TYPE . KEYBOARD )
103124 {
104125 rawKeyMouseInput . AddKeyInput ( & input ->data . keyboard ) ;
105126 }
106127
107- if ( input ->header . dwType == RAWINPUTHEADER . RIM_TYPE . MOUSE )
128+ if ( input ->header . dwType == RIM_TYPE . MOUSE )
108129 {
109130 rawKeyMouseInput . AddMouseInput ( & input ->data . mouse ) ;
110131 }
@@ -113,14 +134,14 @@ private static unsafe IntPtr WndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntP
113134 while ( true )
114135 {
115136 var rawInputBuffer = ( RAWINPUT * ) rawKeyMouseInput . RawInputBuffer ;
116- size = rawKeyMouseInput . RawInputBufferSize ;
117- var count = GetRawInputBuffer ( rawInputBuffer , ref size , sizeof ( RAWINPUTHEADER ) ) ;
137+ size = unchecked ( ( uint ) rawKeyMouseInput . RawInputBufferSize ) ;
138+ var count = GetRawInputBuffer ( rawInputBuffer , ref size , unchecked ( ( uint ) sizeof ( RAWINPUTHEADER ) ) ) ;
118139 if ( count == 0 )
119140 {
120141 break ;
121142 }
122143
123- if ( count == - 1 )
144+ if ( count is uint . MaxValue /*-1*/ )
124145 {
125146 // From testing, it appears this never actually occurs in practice
126147 // As GetRawInputBuffer will succeed as long as the buffer has room for at least 1 packet
@@ -136,15 +157,15 @@ private static unsafe IntPtr WndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntP
136157 break ;
137158 }
138159
139- for ( var i = 0u ; i < ( uint ) count ; i ++ )
160+ for ( var i = 0U ; i < count ; i ++ )
140161 {
141- if ( rawInputBuffer ->header . dwType == RAWINPUTHEADER . RIM_TYPE . KEYBOARD )
162+ if ( rawInputBuffer ->header . dwType == RIM_TYPE . KEYBOARD )
142163 {
143164 var keyboard = ( RAWKEYBOARD * ) ( ( byte * ) & rawInputBuffer ->data . keyboard + rawKeyMouseInput . RawInputBufferDataOffset ) ;
144165 rawKeyMouseInput . AddKeyInput ( keyboard ) ;
145166 }
146167
147- if ( rawInputBuffer ->header . dwType == RAWINPUTHEADER . RIM_TYPE . MOUSE )
168+ if ( rawInputBuffer ->header . dwType == RIM_TYPE . MOUSE )
148169 {
149170 var mouse = ( RAWMOUSE * ) ( ( byte * ) & rawInputBuffer ->data . mouse + rawKeyMouseInput . RawInputBufferDataOffset ) ;
150171 rawKeyMouseInput . AddMouseInput ( mouse ) ;
@@ -157,20 +178,20 @@ private static unsafe IntPtr WndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntP
157178 }
158179 }
159180
160- return IntPtr . Zero ;
181+ return default ;
161182 }
162183
163184 private unsafe void AddKeyInput ( RAWKEYBOARD * keyboard )
164185 {
165- if ( ( keyboard ->Flags & ~ ( RAWKEYBOARD . RI_KEY . E0 | RAWKEYBOARD . RI_KEY . BREAK ) ) == 0 )
186+ if ( ( keyboard ->Flags & ~ ( RI_KEY . E0 | RI_KEY . BREAK ) ) == 0 )
166187 {
167- var rawKey = ( RawKey ) ( keyboard ->MakeCode | ( ( keyboard ->Flags & RAWKEYBOARD . RI_KEY . E0 ) != 0 ? 0x80 : 0 ) ) ;
188+ var rawKey = ( RawKey ) ( keyboard ->MakeCode | ( ( keyboard ->Flags & RI_KEY . E0 ) != 0 ? 0x80 : 0 ) ) ;
168189
169190 // kind of a dumb hack, the Pause key is apparently special here
170191 // keyboards would send scancode 0x1D with an E1 prefix, followed by 0x45 (which is NumLock!)
171192 // this "NumLock" press will set the VKey to 255 (invalid VKey), so we can use that to know if this is actually a Pause press
172193 // (note that DIK_PAUSE is just 0x45 with an E0 prefix, although this is likely just a conversion DirectInput does internally)
173- if ( rawKey == RawKey . NUMLOCK && keyboard ->VKey == VirtualKey . VK_NONE )
194+ if ( rawKey is RawKey . NUMLOCK && ( VirtualKey ) keyboard ->VKey is VirtualKey . VK_NONE )
174195 {
175196 rawKey = RawKey . PAUSE ;
176197 }
@@ -182,62 +203,64 @@ private unsafe void AddKeyInput(RAWKEYBOARD* keyboard)
182203
183204 if ( KeyEnumMap . TryGetValue ( rawKey , out var key ) )
184205 {
185- _keyEvents . Add ( new ( key , ( keyboard ->Flags & RAWKEYBOARD . RI_KEY . BREAK ) == RAWKEYBOARD . RI_KEY . MAKE ) ) ;
206+ _keyEvents . Add ( new ( key , ( keyboard ->Flags & RI_KEY . BREAK ) == RI_KEY . MAKE ) ) ;
186207 }
187208 }
188209 }
189210
190211 private unsafe void AddMouseInput ( RAWMOUSE * mouse )
191212 {
192213 // raw input usually doesn't report absolute inputs, only in odd cases with e.g. touchscreen and rdp screen
193- if ( ( mouse ->usFlags & RAWMOUSE . MOUSE_FLAGS . MOVE_ABSOLUTE ) == RAWMOUSE . MOUSE_FLAGS . MOVE_ABSOLUTE )
214+ if ( ( mouse ->usFlags & MOUSE_STATE . MOUSE_MOVE_ABSOLUTE ) == MOUSE_STATE . MOUSE_MOVE_ABSOLUTE )
194215 {
195216 _mouseDelta . X += mouse ->lLastX - _lastMouseAbsPos . X ;
196217 _mouseDelta . Y += mouse ->lLastY - _lastMouseAbsPos . Y ;
197218 _lastMouseAbsPos = ( mouse ->lLastX , mouse ->lLastY ) ;
198219 }
199- else // ((mouse->usFlags & RAWMOUSE.MOUSE_FLAGS.MOVE_ABSOLUTE ) == RAWMOUSE.MOUSE_FLAGS.MOVE_RELATIVE )
220+ else // ((mouse->usFlags & MOUSE_STATE.MOUSE_MOVE_ABSOLUTE ) == MOUSE_STATE.MOUSE_MOVE_RELATIVE )
200221 {
201222 _mouseDelta . X += mouse ->lLastX ;
202223 _mouseDelta . Y += mouse ->lLastY ;
203224 }
204225 }
205226
206- private static IntPtr CreateRawInputWindow ( )
227+ private static unsafe HWND CreateRawInputWindow ( )
207228 {
208- const int WS_CHILD = 0x40000000 ;
209- var window = CreateWindowExW (
229+ var lpWindowNameStr = "RawKeyInput" ;
230+ HWND window ;
231+ fixed ( char * lpWindowName = lpWindowNameStr )
232+ {
233+ window = CreateWindowExW (
210234 dwExStyle : 0 ,
211235 lpClassName : _rawInputWindowAtom . Value ,
212- lpWindowName : "RawKeyInput" ,
213- dwStyle : WS_CHILD ,
236+ lpWindowName : lpWindowName ,
237+ dwStyle : WINDOW_STYLE . WS_CHILD ,
214238 X : 0 ,
215239 Y : 0 ,
216240 nWidth : 1 ,
217241 nHeight : 1 ,
218- hWndParent : HWND_MESSAGE ,
219- hMenu : IntPtr . Zero ,
220- hInstance : LoaderApiImports . GetModuleHandleW ( null ) ,
221- lpParam : IntPtr . Zero ) ;
222-
223- if ( window == IntPtr . Zero )
242+ hWndParent : HWND . HWND_MESSAGE ,
243+ hMenu : default ,
244+ hInstance : GetModuleHandleW ( default ( PCWSTR ) ) ,
245+ lpParam : default ) ;
246+ }
247+ if ( window . IsNull )
224248 {
225249 throw new InvalidOperationException ( "Failed to create RAWINPUT window" ) ;
226250 }
227251
228252 unsafe
229253 {
230- var rid = stackalloc RAWINPUTDEVICE [ 2 ] ;
231- rid [ 0 ] . usUsagePage = RAWINPUTDEVICE . HidUsagePage . GENERIC ;
232- rid [ 0 ] . usUsage = RAWINPUTDEVICE . HidUsageId . GENERIC_KEYBOARD ;
233- rid [ 0 ] . dwFlags = RAWINPUTDEVICE . RIDEV . INPUTSINK ;
254+ Span < RAWINPUTDEVICE > rid = stackalloc RAWINPUTDEVICE [ 2 ] ;
255+ rid [ 0 ] . usUsagePage = HidUsagePage . GENERIC ;
256+ rid [ 0 ] . usUsage = HidUsageId . GENERIC_KEYBOARD ;
257+ rid [ 0 ] . dwFlags = RAWINPUTDEVICE_FLAGS . RIDEV_INPUTSINK ;
234258 rid [ 0 ] . hwndTarget = window ;
235- rid [ 1 ] . usUsagePage = RAWINPUTDEVICE . HidUsagePage . GENERIC ;
236- rid [ 1 ] . usUsage = RAWINPUTDEVICE . HidUsageId . GENERIC_MOUSE ;
237- rid [ 1 ] . dwFlags = RAWINPUTDEVICE . RIDEV . INPUTSINK ;
259+ rid [ 1 ] . usUsagePage = HidUsagePage . GENERIC ;
260+ rid [ 1 ] . usUsage = HidUsageId . GENERIC_MOUSE ;
261+ rid [ 1 ] . dwFlags = RAWINPUTDEVICE_FLAGS . RIDEV_INPUTSINK ;
238262 rid [ 1 ] . hwndTarget = window ;
239-
240- if ( ! RegisterRawInputDevices ( rid , 2 , sizeof ( RAWINPUTDEVICE ) ) )
263+ if ( ! RegisterRawInputDevices ( rid , unchecked ( ( uint ) sizeof ( RAWINPUTDEVICE ) ) ) )
241264 {
242265 DestroyWindow ( window ) ;
243266 throw new InvalidOperationException ( "Failed to register RAWINPUTDEVICE" ) ;
@@ -280,11 +303,11 @@ public void Dispose()
280303 {
281304 lock ( _lockObj )
282305 {
283- if ( RawInputWindow != IntPtr . Zero )
306+ if ( ! RawInputWindow . IsNull )
284307 {
285308 // Can't use DestroyWindow, that's only allowed in the thread that created the window!
286- PostMessageW ( RawInputWindow , WM_CLOSE , IntPtr . Zero , IntPtr . Zero ) ;
287- RawInputWindow = IntPtr . Zero ;
309+ PostMessageW ( RawInputWindow , WM_CLOSE , default , default ) ;
310+ RawInputWindow = HWND . Null ;
288311 }
289312 else
290313 {
@@ -310,15 +333,20 @@ public IEnumerable<KeyEvent> UpdateKeyInputs(bool handleAltKbLayouts)
310333 {
311334 RawInputWindow = CreateRawInputWindow ( ) ;
312335 var handle = GCHandle . Alloc ( this , GCHandleType . Normal ) ;
313- SetWindowLongPtrW ( RawInputWindow , GWLP_USERDATA , GCHandle . ToIntPtr ( handle ) ) ;
336+ SetWindowLongPtrW ( RawInputWindow , WINDOW_LONG_PTR_INDEX . GWLP_USERDATA , GCHandle . ToIntPtr ( handle ) ) ;
314337 }
315338
316339 _handleAltKbLayouts = handleAltKbLayouts ;
317340
318- while ( PeekMessageW ( out var msg , RawInputWindow , 0 , 0 , PM_REMOVE ) )
341+ while ( PeekMessageW (
342+ out var msg ,
343+ RawInputWindow ,
344+ wMsgFilterMin : 0 ,
345+ wMsgFilterMax : 0 ,
346+ PEEK_MESSAGE_REMOVE_TYPE . PM_REMOVE ) )
319347 {
320- TranslateMessage ( ref msg ) ;
321- DispatchMessageW ( ref msg ) ;
348+ TranslateMessage ( in msg ) ;
349+ DispatchMessageW ( in msg ) ;
322350 }
323351
324352 var ret = _keyEvents ;
@@ -340,13 +368,13 @@ public IEnumerable<KeyEvent> UpdateKeyInputs(bool handleAltKbLayouts)
340368 {
341369 RawInputWindow = CreateRawInputWindow ( ) ;
342370 var handle = GCHandle . Alloc ( this , GCHandleType . Normal ) ;
343- SetWindowLongPtrW ( RawInputWindow , GWLP_USERDATA , GCHandle . ToIntPtr ( handle ) ) ;
371+ SetWindowLongPtrW ( RawInputWindow , WINDOW_LONG_PTR_INDEX . GWLP_USERDATA , GCHandle . ToIntPtr ( handle ) ) ;
344372 }
345373
346- while ( PeekMessageW ( out var msg , RawInputWindow , 0 , 0 , PM_REMOVE ) )
374+ while ( PeekMessageW ( out var msg , RawInputWindow , 0 , 0 , PEEK_MESSAGE_REMOVE_TYPE . PM_REMOVE ) )
347375 {
348- TranslateMessage ( ref msg ) ;
349- DispatchMessageW ( ref msg ) ;
376+ TranslateMessage ( in msg ) ;
377+ DispatchMessageW ( in msg ) ;
350378 }
351379
352380 var ret = _mouseDelta ;
@@ -395,8 +423,7 @@ private static RawKey MapToRealKeyViaScanCode(RawKey key)
395423 scanCode |= 0xE000 ;
396424 }
397425
398- const uint MAPVK_VSC_TO_VK_EX = 0x03 ;
399- var virtualKey = ( VirtualKey ) MapVirtualKeyW ( scanCode , MAPVK_VSC_TO_VK_EX ) ;
426+ var virtualKey = ( VirtualKey ) MapVirtualKeyW ( scanCode , MAP_VIRTUAL_KEY_TYPE . MAPVK_VSC_TO_VK_EX ) ;
400427 return VKeyToRawKeyMap . GetValueOrDefault ( virtualKey ) ;
401428 }
402429
0 commit comments