When thread shuts down, instead of holding and releasing a module ref.
This keeps the thread alive until the module is unloaded, instead of keeping track of live IDirectInput instances.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: winmm patches are identical to previous version, I just refactored the dinput internal thread startup and shutdown instead. It's still lazily started but simply keeps running until the module is unloaded instead of holding a module reference.
dlls/dinput/dinput_main.c | 121 ++++++++++++----------------------- dlls/dinput/dinput_private.h | 3 - 2 files changed, 42 insertions(+), 82 deletions(-)
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index 55d566afa4a..cab8886f9db 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -78,9 +78,18 @@ HINSTANCE DINPUT_instance;
static HWND di_em_win;
-static BOOL check_hook_thread(void); +static HANDLE dinput_thread; +static DWORD dinput_thread_id; + static CRITICAL_SECTION dinput_hook_crit; -static struct list direct_input_list = LIST_INIT( direct_input_list ); +static CRITICAL_SECTION_DEBUG dinput_critsect_debug = +{ + 0, 0, &dinput_hook_crit, + { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") } +}; +static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 }; + static struct list acquired_mouse_list = LIST_INIT( acquired_mouse_list ); static struct list acquired_rawmouse_list = LIST_INIT( acquired_rawmouse_list ); static struct list acquired_keyboard_list = LIST_INIT( acquired_keyboard_list ); @@ -453,18 +462,7 @@ static HRESULT initialize_directinput_instance(IDirectInputImpl *This, DWORD dwV
list_init( &This->device_players );
- /* Add self to the list of the IDirectInputs */ - EnterCriticalSection( &dinput_hook_crit ); - list_add_head( &direct_input_list, &This->entry ); - LeaveCriticalSection( &dinput_hook_crit ); - This->initialized = TRUE; - - if (!check_hook_thread()) - { - uninitialize_directinput_instance( This ); - return DIERR_GENERIC; - } }
return DI_OK; @@ -475,17 +473,11 @@ static void uninitialize_directinput_instance(IDirectInputImpl *This) if (This->initialized) { struct DevicePlayer *device_player, *device_player2; - /* Remove self from the list of the IDirectInputs */ - EnterCriticalSection( &dinput_hook_crit ); - list_remove( &This->entry ); - LeaveCriticalSection( &dinput_hook_crit );
LIST_FOR_EACH_ENTRY_SAFE( device_player, device_player2, &This->device_players, struct DevicePlayer, entry ) free( device_player );
- check_hook_thread(); - This->initialized = FALSE; } } @@ -1262,13 +1254,13 @@ static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam return CallNextHookEx( 0, code, wparam, lparam ); }
-static DWORD WINAPI hook_thread_proc(void *param) +static DWORD WINAPI dinput_thread_proc( void *params ) { + HANDLE events[128], start_event = params; static HHOOK kbd_hook, mouse_hook; struct dinput_device *impl, *next; SIZE_T events_count = 0; HANDLE finished_event; - HANDLE events[128]; HRESULT hr; DWORD ret; MSG msg; @@ -1277,7 +1269,7 @@ static DWORD WINAPI hook_thread_proc(void *param)
/* Force creation of the message queue */ PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); - SetEvent(param); + SetEvent( start_event );
while ((ret = MsgWaitForMultipleObjectsEx( events_count, events, INFINITE, QS_ALLINPUT, 0 )) <= events_count) { @@ -1354,61 +1346,36 @@ static DWORD WINAPI hook_thread_proc(void *param) done: DestroyWindow( di_em_win ); di_em_win = NULL; - - FreeLibraryAndExitThread(DINPUT_instance, 0); + return 0; }
-static DWORD hook_thread_id; -static HANDLE hook_thread_event; - -static CRITICAL_SECTION_DEBUG dinput_critsect_debug = +static BOOL WINAPI dinput_thread_start_once( INIT_ONCE *once, void *param, void **context ) { - 0, 0, &dinput_hook_crit, - { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") } -}; -static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 }; + HANDLE start_event;
-static BOOL check_hook_thread(void) + start_event = CreateEventW( NULL, FALSE, FALSE, NULL ); + if (!start_event) ERR( "failed to create start event, error %u\n", GetLastError() ); + + dinput_thread = CreateThread( NULL, 0, dinput_thread_proc, start_event, 0, &dinput_thread_id ); + if (!dinput_thread) ERR( "failed to create internal thread, error %u\n", GetLastError() ); + + WaitForSingleObject( start_event, INFINITE ); + CloseHandle( start_event ); + + return TRUE; +} + +static void dinput_thread_start(void) { - static HANDLE hook_thread; - HMODULE module; - HANDLE wait_handle = NULL; + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + InitOnceExecuteOnce( &init_once, dinput_thread_start_once, NULL, NULL ); +}
- EnterCriticalSection(&dinput_hook_crit); - - TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list)); - if (!list_empty(&direct_input_list) && !hook_thread) - { - GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const WCHAR*)DINPUT_instance, &module); - hook_thread_event = CreateEventW(NULL, FALSE, FALSE, NULL); - hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0, &hook_thread_id); - } - else if (list_empty(&direct_input_list) && hook_thread) - { - DWORD tid = hook_thread_id; - - if (hook_thread_event) /* if thread is not started yet */ - { - WaitForSingleObject(hook_thread_event, INFINITE); - CloseHandle(hook_thread_event); - hook_thread_event = NULL; - } - - hook_thread_id = 0; - PostThreadMessageW(tid, WM_USER+0x10, 0, 0); - wait_handle = hook_thread; - hook_thread = NULL; - } - - LeaveCriticalSection(&dinput_hook_crit); - - if (wait_handle) - { - WaitForSingleObject(wait_handle, INFINITE); - CloseHandle(wait_handle); - } - return hook_thread_id != 0; +static void dinput_thread_stop(void) +{ + PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 0, 0 ); + WaitForSingleObject( dinput_thread, INFINITE ); + CloseHandle( dinput_thread ); }
void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) @@ -1418,6 +1385,8 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); HANDLE hook_change_finished_event = NULL;
+ dinput_thread_start(); + EnterCriticalSection(&dinput_hook_crit);
if (impl->dwCoopLevel & DISCL_FOREGROUND) @@ -1437,13 +1406,6 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) callwndproc_hook = NULL; }
- if (hook_thread_event) /* if thread is not started yet */ - { - WaitForSingleObject(hook_thread_event, INFINITE); - CloseHandle(hook_thread_event); - hook_thread_event = NULL; - } - if (impl->use_raw_input) { if (acquired) @@ -1470,7 +1432,7 @@ void check_dinput_hooks( IDirectInputDevice8W *iface, BOOL acquired ) }
hook_change_finished_event = CreateEventW( NULL, FALSE, FALSE, NULL ); - PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, (LPARAM)hook_change_finished_event ); + PostThreadMessageW( dinput_thread_id, WM_USER + 0x10, 1, (LPARAM)hook_change_finished_event );
LeaveCriticalSection(&dinput_hook_crit);
@@ -1505,6 +1467,7 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved) break; case DLL_PROCESS_DETACH: if (reserved) break; + dinput_thread_stop(); unregister_di_em_win_class(); DeleteCriticalSection(&dinput_hook_crit); break; diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index c25fe6320ca..4b36a69c0e1 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -40,10 +40,7 @@ struct IDirectInputImpl IDirectInputJoyConfig8 IDirectInputJoyConfig8_iface;
LONG ref; - BOOL initialized; - struct list entry; /* entry into list of all IDirectInputs */ - DWORD evsequence; /* unique sequence number for events */ DWORD dwVersion; /* direct input version number */ struct list device_players; /* device instance guid to player name */
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winmm/joystick.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/dlls/winmm/joystick.c b/dlls/winmm/joystick.c index 604b0d7c0ba..666b0e6c871 100644 --- a/dlls/winmm/joystick.c +++ b/dlls/winmm/joystick.c @@ -263,20 +263,26 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo) /************************************************************************** * joyGetPos [WINMM.@] */ -MMRESULT WINAPI joyGetPos(UINT wID, LPJOYINFO lpInfo) +MMRESULT WINAPI joyGetPos( UINT id, JOYINFO *info ) { - TRACE("(%d, %p);\n", wID, lpInfo); + JOYINFOEX infoex = + { + .dwSize = sizeof(JOYINFOEX), + .dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS, + }; + MMRESULT res;
- if (!lpInfo) return MMSYSERR_INVALPARAM; - if (wID >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + TRACE( "id %u, info %p.\n", id, info );
- lpInfo->wXpos = 0; - lpInfo->wYpos = 0; - lpInfo->wZpos = 0; - lpInfo->wButtons = 0; + if (!info) return MMSYSERR_INVALPARAM; + if ((res = joyGetPosEx( id, &infoex ))) return res;
- return SendDriverMessage( joysticks[wID].hDriver, JDD_GETPOS, (LPARAM)lpInfo, 0 ); + info->wXpos = infoex.dwXpos; + info->wYpos = infoex.dwYpos; + info->wZpos = infoex.dwZpos; + info->wButtons = infoex.dwButtons; + + return JOYERR_NOERROR; }
/**************************************************************************
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winmm/joystick.c | 202 ++++++++++++++++++++---------------------- 1 file changed, 98 insertions(+), 104 deletions(-)
diff --git a/dlls/winmm/joystick.c b/dlls/winmm/joystick.c index 666b0e6c871..842b521a586 100644 --- a/dlls/winmm/joystick.c +++ b/dlls/winmm/joystick.c @@ -44,12 +44,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(winmm); #define JOY_PERIOD_MAX (1000) /* max Capture time period */
typedef struct tagWINE_JOYSTICK { - JOYINFO ji; - HWND hCapture; - UINT wTimer; - DWORD threshold; - BOOL bChanged; - HDRVR hDriver; + JOYINFO info; + HWND capture; + UINT timer; + DWORD threshold; + BOOL changed; + HDRVR driver; } WINE_JOYSTICK;
static WINE_JOYSTICK joysticks[16]; @@ -68,11 +68,11 @@ static BOOL JOY_LoadDriver(DWORD dwJoyID) static BOOL winejoystick_missing = FALSE;
if (dwJoyID >= ARRAY_SIZE(joysticks) || winejoystick_missing) return FALSE; - if (joysticks[dwJoyID].hDriver) return TRUE; + if (joysticks[dwJoyID].driver) return TRUE;
- joysticks[dwJoyID].hDriver = OpenDriverA( "winejoystick.drv", 0, dwJoyID ); + joysticks[dwJoyID].driver = OpenDriverA( "winejoystick.drv", 0, dwJoyID );
- if (!joysticks[dwJoyID].hDriver) + if (!joysticks[dwJoyID].driver) { WARN("OpenDriverA("winejoystick.drv") failed\n");
@@ -80,56 +80,50 @@ static BOOL JOY_LoadDriver(DWORD dwJoyID) winejoystick_missing = TRUE; }
- return (joysticks[dwJoyID].hDriver != 0); + return (joysticks[dwJoyID].driver != 0); }
-/************************************************************************** - * JOY_Timer [internal] - */ -static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT_PTR wTimer, DWORD dwTime) +static void CALLBACK joystick_timer( HWND hwnd, UINT msg, UINT_PTR timer, DWORD time ) { - int i; - WINE_JOYSTICK* joy; - MMRESULT res; - JOYINFO ji; - LONG pos; - unsigned buttonChange; + MMRESULT res; + JOYINFO info; + WORD change; + LONG pos; + int i;
for (i = 0; i < ARRAY_SIZE(joysticks); i++) { - joy = &joysticks[i]; + if (joysticks[i].capture != hwnd) continue; + if ((res = joyGetPos( i, &info ))) + { + WARN( "joyGetPos failed: %08x\n", res ); + continue; + }
- if (joy->hCapture != hWnd) continue; + pos = MAKELONG( info.wXpos, info.wYpos );
- res = joyGetPos(i, &ji); - if (res != JOYERR_NOERROR) { - WARN("joyGetPos failed: %08x\n", res); - continue; - } - - pos = MAKELONG(ji.wXpos, ji.wYpos); - - if (!joy->bChanged || - !compare_uint(joy->ji.wXpos, ji.wXpos, joy->threshold) || - !compare_uint(joy->ji.wYpos, ji.wYpos, joy->threshold)) { - SendMessageA(joy->hCapture, MM_JOY1MOVE + i, ji.wButtons, pos); - joy->ji.wXpos = ji.wXpos; - joy->ji.wYpos = ji.wYpos; - } - if (!joy->bChanged || - !compare_uint(joy->ji.wZpos, ji.wZpos, joy->threshold)) { - SendMessageA(joy->hCapture, MM_JOY1ZMOVE + i, ji.wButtons, pos); - joy->ji.wZpos = ji.wZpos; - } - if ((buttonChange = joy->ji.wButtons ^ ji.wButtons) != 0) { - if (ji.wButtons & buttonChange) - SendMessageA(joy->hCapture, MM_JOY1BUTTONDOWN + i, - (buttonChange << 8) | (ji.wButtons & buttonChange), pos); - if (joy->ji.wButtons & buttonChange) - SendMessageA(joy->hCapture, MM_JOY1BUTTONUP + i, - (buttonChange << 8) | (joy->ji.wButtons & buttonChange), pos); - joy->ji.wButtons = ji.wButtons; - } + if (!joysticks[i].changed || + !compare_uint( joysticks[i].info.wXpos, info.wXpos, joysticks[i].threshold ) || + !compare_uint( joysticks[i].info.wYpos, info.wYpos, joysticks[i].threshold )) + { + SendMessageA( hwnd, MM_JOY1MOVE + i, info.wButtons, pos ); + joysticks[i].info.wXpos = info.wXpos; + joysticks[i].info.wYpos = info.wYpos; + } + if (!joysticks[i].changed || + !compare_uint( joysticks[i].info.wZpos, info.wZpos, joysticks[i].threshold )) + { + SendMessageA( hwnd, MM_JOY1ZMOVE + i, info.wButtons, pos ); + joysticks[i].info.wZpos = info.wZpos; + } + if ((change = joysticks[i].info.wButtons ^ info.wButtons) != 0) + { + if (info.wButtons & change) + SendMessageA( hwnd, MM_JOY1BUTTONDOWN + i, (change << 8) | (info.wButtons & change), pos ); + if (joysticks[i].info.wButtons & change) + SendMessageA( hwnd, MM_JOY1BUTTONUP + i, (change << 8) | (joysticks[i].info.wButtons & change), pos ); + joysticks[i].info.wButtons = info.wButtons; + } } }
@@ -138,11 +132,8 @@ static void CALLBACK JOY_Timer(HWND hWnd, UINT wMsg, UINT_PTR wTimer, DWORD dwTi */ MMRESULT WINAPI joyConfigChanged(DWORD flags) { - FIXME("(%x) - stub\n", flags); - - if (flags) - return JOYERR_PARMS; - + FIXME( "flags %#x stub!\n", flags ); + if (flags) return JOYERR_PARMS; return JOYERR_NOERROR; }
@@ -174,7 +165,7 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW( UINT_PTR id, JOYCAPSW *caps, U caps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */ caps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */
- return SendDriverMessage( joysticks[id].hDriver, JDD_GETDEVCAPS, (LPARAM)caps, size ); + return SendDriverMessage( joysticks[id].driver, JDD_GETDEVCAPS, (LPARAM)caps, size ); }
/************************************************************************** @@ -237,27 +228,27 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA( UINT_PTR id, JOYCAPSA *caps, U /************************************************************************** * joyGetPosEx [WINMM.@] */ -MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx(UINT wID, LPJOYINFOEX lpInfo) +MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx( UINT id, JOYINFOEX *info ) { - TRACE("(%d, %p);\n", wID, lpInfo); + TRACE( "id %u, info %p.\n", id, info );
- if (!lpInfo) return MMSYSERR_INVALPARAM; - if (wID >= ARRAY_SIZE(joysticks) || lpInfo->dwSize < sizeof(JOYINFOEX)) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + if (!info) return MMSYSERR_INVALPARAM; + if (id >= ARRAY_SIZE(joysticks) || info->dwSize < sizeof(JOYINFOEX)) return JOYERR_PARMS; + if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
- lpInfo->dwXpos = 0; - lpInfo->dwYpos = 0; - lpInfo->dwZpos = 0; - lpInfo->dwRpos = 0; - lpInfo->dwUpos = 0; - lpInfo->dwVpos = 0; - lpInfo->dwButtons = 0; - lpInfo->dwButtonNumber = 0; - lpInfo->dwPOV = 0; - lpInfo->dwReserved1 = 0; - lpInfo->dwReserved2 = 0; + info->dwXpos = 0; + info->dwYpos = 0; + info->dwZpos = 0; + info->dwRpos = 0; + info->dwUpos = 0; + info->dwVpos = 0; + info->dwButtons = 0; + info->dwButtonNumber = 0; + info->dwPOV = 0; + info->dwReserved1 = 0; + info->dwReserved2 = 0;
- return SendDriverMessage( joysticks[wID].hDriver, JDD_GETPOSEX, (LPARAM)lpInfo, 0 ); + return SendDriverMessage( joysticks[id].driver, JDD_GETPOSEX, (LPARAM)info, 0 ); }
/************************************************************************** @@ -288,33 +279,34 @@ MMRESULT WINAPI joyGetPos( UINT id, JOYINFO *info ) /************************************************************************** * joyGetThreshold [WINMM.@] */ -MMRESULT WINAPI joyGetThreshold(UINT wID, LPUINT lpThreshold) +MMRESULT WINAPI joyGetThreshold( UINT id, UINT *threshold ) { - TRACE("(%04X, %p);\n", wID, lpThreshold); + TRACE( "id %u, threshold %p.\n", id, threshold );
- if (wID >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; + if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS;
- *lpThreshold = joysticks[wID].threshold; + *threshold = joysticks[id].threshold; return JOYERR_NOERROR; }
/************************************************************************** * joyReleaseCapture [WINMM.@] */ -MMRESULT WINAPI joyReleaseCapture(UINT wID) +MMRESULT WINAPI joyReleaseCapture( UINT id ) { - TRACE("(%04X);\n", wID); + TRACE( "id %u.\n", id );
- if (wID >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; - if (joysticks[wID].hCapture) - { - KillTimer( joysticks[wID].hCapture, joysticks[wID].wTimer ); - joysticks[wID].hCapture = 0; - joysticks[wID].wTimer = 0; - } - else + if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; + if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER; + + if (!joysticks[id].capture) TRACE("Joystick is not captured, ignoring request.\n"); + else + { + KillTimer( joysticks[id].capture, joysticks[id].timer ); + joysticks[id].capture = 0; + joysticks[id].timer = 0; + }
return JOYERR_NOERROR; } @@ -322,21 +314,23 @@ MMRESULT WINAPI joyReleaseCapture(UINT wID) /************************************************************************** * joySetCapture [WINMM.@] */ -MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged) +MMRESULT WINAPI joySetCapture( HWND hwnd, UINT id, UINT period, BOOL changed ) { - TRACE("(%p, %04X, %d, %d);\n", hWnd, wID, wPeriod, bChanged); + TRACE( "hwnd %p, id %u, period %u, changed %u.\n", hwnd, id, period, changed );
- if (wID >= ARRAY_SIZE(joysticks) || hWnd == 0) return JOYERR_PARMS; - if (wPeriod<JOY_PERIOD_MIN) wPeriod = JOY_PERIOD_MIN; - else if(wPeriod>JOY_PERIOD_MAX) wPeriod = JOY_PERIOD_MAX; - if (!JOY_LoadDriver(wID)) return MMSYSERR_NODRIVER; + if (id >= ARRAY_SIZE(joysticks) || hwnd == 0) return JOYERR_PARMS; + if (period < JOY_PERIOD_MIN) period = JOY_PERIOD_MIN; + else if (period > JOY_PERIOD_MAX) period = JOY_PERIOD_MAX; + if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
- if (joysticks[wID].hCapture || !IsWindow( hWnd )) return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ - if (joyGetPos( wID, &joysticks[wID].ji ) != JOYERR_NOERROR) return JOYERR_UNPLUGGED; - if ((joysticks[wID].wTimer = SetTimer( hWnd, 0, wPeriod, JOY_Timer )) == 0) return JOYERR_NOCANDO; + if (joysticks[id].capture || !IsWindow( hwnd )) + return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ + if (joyGetPos( id, &joysticks[id].info ) != JOYERR_NOERROR) return JOYERR_UNPLUGGED; + if ((joysticks[id].timer = SetTimer( hwnd, 0, period, joystick_timer )) == 0) + return JOYERR_NOCANDO;
- joysticks[wID].hCapture = hWnd; - joysticks[wID].bChanged = bChanged; + joysticks[id].capture = hwnd; + joysticks[id].changed = changed;
return JOYERR_NOERROR; } @@ -344,13 +338,13 @@ MMRESULT WINAPI joySetCapture(HWND hWnd, UINT wID, UINT wPeriod, BOOL bChanged) /************************************************************************** * joySetThreshold [WINMM.@] */ -MMRESULT WINAPI joySetThreshold(UINT wID, UINT wThreshold) +MMRESULT WINAPI joySetThreshold( UINT id, UINT threshold ) { - TRACE("(%04X, %d);\n", wID, wThreshold); + TRACE( "id %u, threshold %u.\n", id, threshold );
- if (wID >= ARRAY_SIZE(joysticks) || wThreshold > 65535) return MMSYSERR_INVALPARAM; + if (id >= ARRAY_SIZE(joysticks) || threshold > 65535) return MMSYSERR_INVALPARAM;
- joysticks[wID].threshold = wThreshold; + joysticks[id].threshold = threshold;
return JOYERR_NOERROR; }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/winmm/joystick.c | 46 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-)
diff --git a/dlls/winmm/joystick.c b/dlls/winmm/joystick.c index 842b521a586..20a69e8119d 100644 --- a/dlls/winmm/joystick.c +++ b/dlls/winmm/joystick.c @@ -40,6 +40,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(winmm);
+static CRITICAL_SECTION joystick_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &joystick_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": joystick_cs") } +}; +static CRITICAL_SECTION joystick_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + #define JOY_PERIOD_MIN (10) /* min Capture time period */ #define JOY_PERIOD_MAX (1000) /* max Capture time period */
@@ -91,6 +100,8 @@ static void CALLBACK joystick_timer( HWND hwnd, UINT msg, UINT_PTR timer, DWORD LONG pos; int i;
+ EnterCriticalSection( &joystick_cs ); + for (i = 0; i < ARRAY_SIZE(joysticks); i++) { if (joysticks[i].capture != hwnd) continue; @@ -125,6 +136,8 @@ static void CALLBACK joystick_timer( HWND hwnd, UINT msg, UINT_PTR timer, DWORD joysticks[i].info.wButtons = info.wButtons; } } + + LeaveCriticalSection( &joystick_cs ); }
/************************************************************************** @@ -285,7 +298,10 @@ MMRESULT WINAPI joyGetThreshold( UINT id, UINT *threshold )
if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS;
+ EnterCriticalSection( &joystick_cs ); *threshold = joysticks[id].threshold; + LeaveCriticalSection( &joystick_cs ); + return JOYERR_NOERROR; }
@@ -299,6 +315,8 @@ MMRESULT WINAPI joyReleaseCapture( UINT id ) if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
+ EnterCriticalSection( &joystick_cs ); + if (!joysticks[id].capture) TRACE("Joystick is not captured, ignoring request.\n"); else @@ -308,6 +326,8 @@ MMRESULT WINAPI joyReleaseCapture( UINT id ) joysticks[id].timer = 0; }
+ LeaveCriticalSection( &joystick_cs ); + return JOYERR_NOERROR; }
@@ -316,6 +336,8 @@ MMRESULT WINAPI joyReleaseCapture( UINT id ) */ MMRESULT WINAPI joySetCapture( HWND hwnd, UINT id, UINT period, BOOL changed ) { + MMRESULT res = JOYERR_NOERROR; + TRACE( "hwnd %p, id %u, period %u, changed %u.\n", hwnd, id, period, changed );
if (id >= ARRAY_SIZE(joysticks) || hwnd == 0) return JOYERR_PARMS; @@ -323,16 +345,22 @@ MMRESULT WINAPI joySetCapture( HWND hwnd, UINT id, UINT period, BOOL changed ) else if (period > JOY_PERIOD_MAX) period = JOY_PERIOD_MAX; if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
+ EnterCriticalSection( &joystick_cs ); + if (joysticks[id].capture || !IsWindow( hwnd )) - return JOYERR_NOCANDO; /* FIXME: what should be returned ? */ - if (joyGetPos( id, &joysticks[id].info ) != JOYERR_NOERROR) return JOYERR_UNPLUGGED; - if ((joysticks[id].timer = SetTimer( hwnd, 0, period, joystick_timer )) == 0) - return JOYERR_NOCANDO; + res = JOYERR_NOCANDO; /* FIXME: what should be returned ? */ + else if (joyGetPos( id, &joysticks[id].info ) != JOYERR_NOERROR) + res = JOYERR_UNPLUGGED; + else if ((joysticks[id].timer = SetTimer( hwnd, 0, period, joystick_timer )) == 0) + res = JOYERR_NOCANDO; + else + { + joysticks[id].capture = hwnd; + joysticks[id].changed = changed; + }
- joysticks[id].capture = hwnd; - joysticks[id].changed = changed; - - return JOYERR_NOERROR; + LeaveCriticalSection( &joystick_cs ); + return res; }
/************************************************************************** @@ -344,7 +372,9 @@ MMRESULT WINAPI joySetThreshold( UINT id, UINT threshold )
if (id >= ARRAY_SIZE(joysticks) || threshold > 65535) return MMSYSERR_INVALPARAM;
+ EnterCriticalSection( &joystick_cs ); joysticks[id].threshold = threshold; + LeaveCriticalSection( &joystick_cs );
return JOYERR_NOERROR; }
Based on a patch from Zebediah Figura zfigura@codeweavers.com.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput8/tests/hid.c | 51 ------ dlls/winmm/Makefile.in | 2 +- dlls/winmm/joystick.c | 355 +++++++++++++++++++++++++++++++++------ dlls/winmm/winemm.h | 3 + dlls/winmm/winmm.c | 2 + 5 files changed, 308 insertions(+), 105 deletions(-)
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 31703601b6b..35d72409af5 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -9756,10 +9756,6 @@ static void test_winmm_joystick(void) ok( ret == 16, "joyGetNumDevs returned %u\n", ret );
ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); - /* FIXME: Marvin somehow manages to get a device, ignore it */ - if (!strcmp( winetest_platform, "wine") && ret == 0 && - !wcscmp( caps.szPname, L"QEMU Virtio Tablet" )) - return; ok( ret == JOYERR_PARMS, "joyGetDevCapsW returned %u\n", ret );
memset( &caps, 0xcd, sizeof(caps) ); @@ -9803,7 +9799,6 @@ static void test_winmm_joystick(void) ret = joyGetPosEx( 0, &infoex ); /* first call for an index sometimes fail */ if (ret == JOYERR_PARMS) ret = joyGetPosEx( 0, &infoex ); - todo_wine ok( ret == 0, "joyGetPosEx returned %u\n", ret );
ret = joyGetDevCapsW( 1, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); @@ -9811,43 +9806,29 @@ static void test_winmm_joystick(void)
memset( &caps, 0xcd, sizeof(caps) ); ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(caps) ); - todo_wine ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); - todo_wine check_member( caps, expect_caps, "%#x", wMid ); - todo_wine check_member( caps, expect_caps, "%#x", wPid ); todo_wine check_member_wstr( caps, expect_caps, szPname ); check_member( caps, expect_caps, "%#x", wXmin ); - todo_wine check_member( caps, expect_caps, "%#x", wXmax ); check_member( caps, expect_caps, "%#x", wYmin ); - todo_wine check_member( caps, expect_caps, "%#x", wYmax ); check_member( caps, expect_caps, "%#x", wZmin ); - todo_wine check_member( caps, expect_caps, "%#x", wZmax ); - todo_wine check_member( caps, expect_caps, "%#x", wNumButtons ); check_member( caps, expect_caps, "%#x", wPeriodMin ); check_member( caps, expect_caps, "%#x", wPeriodMax ); check_member( caps, expect_caps, "%#x", wRmin ); - todo_wine check_member( caps, expect_caps, "%#x", wRmax ); check_member( caps, expect_caps, "%#x", wUmin ); - todo_wine check_member( caps, expect_caps, "%#x", wUmax ); check_member( caps, expect_caps, "%#x", wVmin ); - todo_wine check_member( caps, expect_caps, "%#x", wVmax ); - todo_wine check_member( caps, expect_caps, "%#x", wCaps ); - todo_wine check_member( caps, expect_caps, "%#x", wMaxAxes ); - todo_wine check_member( caps, expect_caps, "%#x", wNumAxes ); - todo_wine check_member( caps, expect_caps, "%#x", wMaxButtons ); check_member_wstr( caps, expect_caps, szRegKey ); check_member_wstr( caps, expect_caps, szOEMVxD ); @@ -9856,7 +9837,6 @@ static void test_winmm_joystick(void) check_member_guid( caps, expect_caps, NameGuid );
ret = joyGetDevCapsW( 0, (JOYCAPSW *)&caps, sizeof(JOYCAPSW) ); - todo_wine ok( ret == 0, "joyGetDevCapsW returned %u\n", ret ); ret = joyGetDevCapsW( 0, NULL, sizeof(JOYCAPSW) ); ok( ret == MMSYSERR_INVALPARAM, "joyGetDevCapsW returned %u\n", ret ); @@ -9878,29 +9858,19 @@ static void test_winmm_joystick(void) infoex.dwSize = sizeof(JOYINFOEX); infoex.dwFlags = JOY_RETURNALL; ret = joyGetPosEx( 0, &infoex ); - todo_wine ok( ret == 0, "joyGetPosEx returned %u\n", ret ); check_member( infoex, expect_infoex[0], "%#x", dwSize ); check_member( infoex, expect_infoex[0], "%#x", dwFlags ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwXpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwYpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwZpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwRpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwUpos ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwVpos ); check_member( infoex, expect_infoex[0], "%#x", dwButtons ); check_member( infoex, expect_infoex[0], "%#x", dwButtonNumber ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwPOV ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwReserved1 ); - todo_wine check_member( infoex, expect_infoex[0], "%#x", dwReserved2 );
infoex.dwSize = sizeof(JOYINFOEX) - 4; @@ -9913,13 +9883,9 @@ static void test_winmm_joystick(void) ok( ret == JOYERR_PARMS, "joyGetPos returned %u\n", ret ); memset( &info, 0xcd, sizeof(info) ); ret = joyGetPos( 0, &info ); - todo_wine ok( ret == 0, "joyGetPos returned %u\n", ret ); - todo_wine check_member( info, expect_info, "%#x", wXpos ); - todo_wine check_member( info, expect_info, "%#x", wYpos ); - todo_wine check_member( info, expect_info, "%#x", wZpos ); check_member( info, expect_info, "%#x", wButtons );
@@ -9953,24 +9919,16 @@ static void test_winmm_joystick(void) infoex.dwSize = sizeof(JOYINFOEX); infoex.dwFlags = JOY_RETURNALL; ret = joyGetPosEx( 0, &infoex ); - todo_wine ok( ret == 0, "joyGetPosEx returned %u\n", ret ); check_member( infoex, expect_infoex[1], "%#x", dwSize ); check_member( infoex, expect_infoex[1], "%#x", dwFlags ); check_member( infoex, expect_infoex[1], "%#x", dwXpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwYpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwZpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwRpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwUpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwVpos ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwButtons ); - todo_wine check_member( infoex, expect_infoex[1], "%#x", dwButtonNumber ); check_member( infoex, expect_infoex[1], "%#x", dwPOV );
@@ -9983,26 +9941,17 @@ static void test_winmm_joystick(void) infoex.dwSize = sizeof(JOYINFOEX); infoex.dwFlags = JOY_RETURNALL; ret = joyGetPosEx( 0, &infoex ); - todo_wine ok( ret == 0, "joyGetPosEx returned %u\n", ret ); check_member( infoex, expect_infoex[2], "%#x", dwSize ); check_member( infoex, expect_infoex[2], "%#x", dwFlags ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwXpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwYpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwZpos ); check_member( infoex, expect_infoex[2], "%#x", dwRpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwUpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwVpos ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwButtons ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwButtonNumber ); - todo_wine check_member( infoex, expect_infoex[2], "%#x", dwPOV );
ret = IDirectInputDevice8_Release( device ); diff --git a/dlls/winmm/Makefile.in b/dlls/winmm/Makefile.in index 3036526c14e..5439ae21678 100644 --- a/dlls/winmm/Makefile.in +++ b/dlls/winmm/Makefile.in @@ -1,7 +1,7 @@ EXTRADEFS = -D_WINMM_ MODULE = winmm.dll IMPORTLIB = winmm -IMPORTS = uuid user32 advapi32 ole32 msacm32 +IMPORTS = uuid user32 advapi32 ole32 msacm32 dinput8
C_SRCS = \ driver.c \ diff --git a/dlls/winmm/joystick.c b/dlls/winmm/joystick.c index 20a69e8119d..5f5683e3e35 100644 --- a/dlls/winmm/joystick.c +++ b/dlls/winmm/joystick.c @@ -1,10 +1,11 @@ -/* -*- tab-width: 8; c-basic-offset: 4 -*- */ /* * joystick functions * * Copyright 1997 Andreas Mohr - * 2000 Wolfgang Schwotzer - * Eric Pouech + * Copyright 2000 Wolfgang Schwotzer + * Copyright 2000 Eric Pouech + * Copyright 2020 Zebediah Figura for CodeWeavers + * Copyright 2021 Rémi Bernon for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +23,7 @@ */
#include <stdarg.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -30,11 +32,11 @@ #include "windef.h" #include "winbase.h" #include "mmsystem.h" -#include "wingdi.h" -#include "winuser.h" -#include "winnls.h"
-#include "mmddk.h" +#include "initguid.h" +#include "dinput.h" + +#include "winemm.h"
#include "wine/debug.h"
@@ -49,19 +51,185 @@ static CRITICAL_SECTION_DEBUG critsect_debug = }; static CRITICAL_SECTION joystick_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
+struct joystick_state +{ + LONG x; + LONG y; + LONG z; + LONG u; + LONG v; + LONG r; + LONG pov; + BYTE buttons[32]; +}; + +static const DIOBJECTDATAFORMAT object_formats[] = +{ + { &GUID_XAxis, offsetof(struct joystick_state, x), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, + { &GUID_YAxis, offsetof(struct joystick_state, y), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, + { &GUID_ZAxis, offsetof(struct joystick_state, z), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, + { &GUID_RzAxis, offsetof(struct joystick_state, r), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, + { &GUID_Slider, offsetof(struct joystick_state, u), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, + { &GUID_RxAxis, offsetof(struct joystick_state, v), DIDFT_OPTIONAL|DIDFT_AXIS|DIDFT_ANYINSTANCE, DIDOI_ASPECTPOSITION }, + { &GUID_POV, offsetof(struct joystick_state, pov), DIDFT_OPTIONAL|DIDFT_POV|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[0]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[1]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[2]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[3]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[4]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[5]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[6]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[7]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[8]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[9]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[10]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[11]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[12]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[13]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[14]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[15]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[16]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[17]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[18]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[19]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[20]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[21]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[22]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[23]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[24]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[25]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[26]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[27]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[28]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[29]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[30]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, + { NULL, offsetof(struct joystick_state, buttons[31]), DIDFT_OPTIONAL|DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, +}; + +static const DIDATAFORMAT data_format = +{ + .dwSize = sizeof(DIDATAFORMAT), + .dwObjSize = sizeof(DIOBJECTDATAFORMAT), + .dwFlags = DIDF_ABSAXIS, + .dwDataSize = sizeof(struct joystick_state), + .dwNumObjs = ARRAY_SIZE(object_formats), + .rgodf = (DIOBJECTDATAFORMAT *)object_formats, +}; + #define JOY_PERIOD_MIN (10) /* min Capture time period */ #define JOY_PERIOD_MAX (1000) /* max Capture time period */
-typedef struct tagWINE_JOYSTICK { +struct joystick +{ + DIDEVICEINSTANCEW instance; + IDirectInputDevice8W *device; + struct joystick_state state; + HANDLE event; + JOYINFO info; HWND capture; UINT timer; DWORD threshold; BOOL changed; - HDRVR driver; -} WINE_JOYSTICK; + ULONG last_check; +};
-static WINE_JOYSTICK joysticks[16]; +static DIDEVICEINSTANCEW instances[16]; +static struct joystick joysticks[16]; +static IDirectInput8W *dinput; + +static BOOL CALLBACK enum_instances( const DIDEVICEINSTANCEW *instance, void *context ) +{ + ULONG index = *(ULONG *)context; + BYTE type = instance->dwDevType; + + if (type == DI8DEVTYPE_MOUSE) return DIENUM_CONTINUE; + if (type == DI8DEVTYPE_KEYBOARD) return DIENUM_CONTINUE; + + instances[index++] = *instance; + if (index >= ARRAY_SIZE(instances)) return DIENUM_STOP; + *(ULONG *)context = index; + return DIENUM_CONTINUE; +} + +void joystick_load( HINSTANCE instance ) +{ + HRESULT hr = DirectInput8Create( instance, DIRECTINPUT_VERSION, &IID_IDirectInput8W, + (void **)&dinput, NULL ); + if (FAILED(hr)) WARN( "could not create dinput instance, hr %#x\n", hr ); +} + +void joystick_unload() +{ + int i; + + if (!dinput) return; + + for (i = 0; i < ARRAY_SIZE(joysticks); i++) + { + if (!joysticks[i].device) continue; + IDirectInputDevice8_Release( joysticks[i].device ); + CloseHandle( joysticks[i].event ); + } + + IDirectInput8_Release( dinput ); +} + +static void find_joysticks(void) +{ + IDirectInputDevice8W *device; + HANDLE event; + DWORD index; + HRESULT hr; + + if (!dinput) return; + + index = 0; + IDirectInput8_EnumDevices( dinput, DI8DEVCLASS_ALL, enum_instances, &index, DIEDFL_ATTACHEDONLY ); + TRACE( "found %u device instances\n", index ); + + while (index--) + { + if (!memcmp( &joysticks[index].instance, &instances[index], sizeof(DIDEVICEINSTANCEW) )) + continue; + + if (joysticks[index].device) + { + IDirectInputDevice8_Release( joysticks[index].device ); + CloseHandle( joysticks[index].event ); + } + + if (!(event = CreateEventW( NULL, FALSE, FALSE, NULL ))) + WARN( "could not event for device, error %u\n", GetLastError() ); + else if (FAILED(hr = IDirectInput8_CreateDevice( dinput, &instances[index].guidInstance, &device, NULL ))) + WARN( "could not create device %s instance, hr %#x\n", + debugstr_guid( &instances[index].guidInstance ), hr ); + else if (FAILED(hr = IDirectInputDevice8_SetEventNotification( device, event ))) + WARN( "SetEventNotification device %p hr %#x\n", device, hr ); + else if (FAILED(hr = IDirectInputDevice8_SetCooperativeLevel( device, NULL, DISCL_NONEXCLUSIVE|DISCL_BACKGROUND ))) + WARN( "SetCooperativeLevel device %p hr %#x\n", device, hr ); + else if (FAILED(hr = IDirectInputDevice8_SetDataFormat( device, &data_format ))) + WARN( "SetDataFormat device %p hr %#x\n", device, hr ); + else if (FAILED(hr = IDirectInputDevice8_Acquire( device ))) + WARN( "Acquire device %p hr %#x\n", device, hr ); + else + { + TRACE( "opened device %p event %p\n", device, event ); + + memset( &joysticks[index], 0, sizeof(struct joystick) ); + joysticks[index].instance = instances[index]; + joysticks[index].device = device; + joysticks[index].event = event; + continue; + } + + CloseHandle( event ); + if (device) IDirectInputDevice8_Release( device ); + memmove( joysticks + index, joysticks + index + 1, + (ARRAY_SIZE(joysticks) - index - 1) * sizeof(struct joystick) ); + memset( &joysticks[ARRAY_SIZE(joysticks) - 1], 0, sizeof(struct joystick) ); + } +}
static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) { @@ -69,29 +237,6 @@ static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) return diff <= max_diff; }
-/************************************************************************** - * JOY_LoadDriver [internal] - */ -static BOOL JOY_LoadDriver(DWORD dwJoyID) -{ - static BOOL winejoystick_missing = FALSE; - - if (dwJoyID >= ARRAY_SIZE(joysticks) || winejoystick_missing) return FALSE; - if (joysticks[dwJoyID].driver) return TRUE; - - joysticks[dwJoyID].driver = OpenDriverA( "winejoystick.drv", 0, dwJoyID ); - - if (!joysticks[dwJoyID].driver) - { - WARN("OpenDriverA("winejoystick.drv") failed\n"); - - /* The default driver is missing, don't attempt to load it again */ - winejoystick_missing = TRUE; - } - - return (joysticks[dwJoyID].driver != 0); -} - static void CALLBACK joystick_timer( HWND hwnd, UINT msg, UINT_PTR timer, DWORD time ) { MMRESULT res; @@ -163,6 +308,22 @@ UINT WINAPI DECLSPEC_HOTPATCH joyGetNumDevs(void) */ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW( UINT_PTR id, JOYCAPSW *caps, UINT size ) { + DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)}; + DIDEVCAPS dicaps = {.dwSize = sizeof(DIDEVCAPS)}; + DIPROPDWORD diprop = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + MMRESULT res = JOYERR_NOERROR; + IDirectInputDevice8W *device; + ULONG ticks = GetTickCount(); + HRESULT hr; + TRACE( "id %d, caps %p, size %u.\n", (int)id, caps, size );
if (!caps) return MMSYSERR_INVALPARAM; @@ -173,12 +334,67 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsW( UINT_PTR id, JOYCAPSW *caps, U if (id == ~(UINT_PTR)0) return JOYERR_NOERROR;
if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; - if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
- caps->wPeriodMin = JOY_PERIOD_MIN; /* FIXME */ - caps->wPeriodMax = JOY_PERIOD_MAX; /* FIXME (same as MS Joystick Driver) */ + EnterCriticalSection( &joystick_cs );
- return SendDriverMessage( joysticks[id].driver, JDD_GETDEVCAPS, (LPARAM)caps, size ); + if (!(device = joysticks[id].device) && (ticks - joysticks[id].last_check) >= 2000) + { + joysticks[id].last_check = ticks; + find_joysticks(); + } + + if (!(device = joysticks[id].device)) res = JOYERR_PARMS; + else if (FAILED(hr = IDirectInputDevice8_GetCapabilities( device, &dicaps ))) + { + WARN( "GetCapabilities device %p returned %#x\n", device, hr ); + res = JOYERR_PARMS; + } + else + { + hr = IDirectInputDevice8_GetProperty( device, DIPROP_VIDPID, &diprop.diph ); + if (FAILED(hr)) WARN( "GetProperty device %p returned %#x\n", device, hr ); + else + { + caps->wMid = LOWORD(diprop.dwData); + caps->wPid = HIWORD(diprop.dwData); + } + + wcscpy( caps->szPname, L"Wine joystick driver" ); + caps->wXmin = 0; + caps->wXmax = 0xffff; + caps->wYmin = 0; + caps->wYmax = 0xffff; + caps->wZmin = 0; + caps->wZmax = 0xffff; + caps->wNumButtons = dicaps.dwButtons; + caps->wPeriodMin = JOY_PERIOD_MIN; + caps->wPeriodMax = JOY_PERIOD_MAX; + caps->wRmin = 0; + caps->wRmax = 0xffff; + caps->wUmin = 0; + caps->wUmax = 0xffff; + caps->wVmin = 0; + caps->wVmax = 0xffff; + caps->wCaps = 0; + caps->wMaxAxes = 6; + caps->wNumAxes = min( dicaps.dwAxes, caps->wMaxAxes ); + caps->wMaxButtons = 32; + + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, z), DIPH_BYOFFSET ); + if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASZ; + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, r), DIPH_BYOFFSET ); + if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASR; + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, u), DIPH_BYOFFSET ); + if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASU; + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, v), DIPH_BYOFFSET ); + if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASV; + hr = IDirectInputDevice8_GetObjectInfo( device, &instance, offsetof(struct joystick_state, pov), DIPH_BYOFFSET ); + if (SUCCEEDED(hr)) caps->wCaps |= JOYCAPS_HASPOV|JOYCAPS_POV4DIR; + } + + LeaveCriticalSection( &joystick_cs ); + + return res; }
/************************************************************************** @@ -243,25 +459,60 @@ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetDevCapsA( UINT_PTR id, JOYCAPSA *caps, U */ MMRESULT WINAPI DECLSPEC_HOTPATCH joyGetPosEx( UINT id, JOYINFOEX *info ) { + DWORD i, ticks = GetTickCount(); + MMRESULT res = JOYERR_NOERROR; + IDirectInputDevice8W *device; + struct joystick_state state; + HRESULT hr; + TRACE( "id %u, info %p.\n", id, info );
if (!info) return MMSYSERR_INVALPARAM; if (id >= ARRAY_SIZE(joysticks) || info->dwSize < sizeof(JOYINFOEX)) return JOYERR_PARMS; - if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
- info->dwXpos = 0; - info->dwYpos = 0; - info->dwZpos = 0; - info->dwRpos = 0; - info->dwUpos = 0; - info->dwVpos = 0; - info->dwButtons = 0; - info->dwButtonNumber = 0; - info->dwPOV = 0; - info->dwReserved1 = 0; - info->dwReserved2 = 0; + EnterCriticalSection( &joystick_cs );
- return SendDriverMessage( joysticks[id].driver, JDD_GETPOSEX, (LPARAM)info, 0 ); + if (!(device = joysticks[id].device) && (ticks - joysticks[id].last_check) >= 2000) + { + joysticks[id].last_check = ticks; + find_joysticks(); + } + + if (!(device = joysticks[id].device)) + res = JOYERR_PARMS; + else if (FAILED(hr = IDirectInputDevice8_GetDeviceState( device, sizeof(struct joystick_state), &state ))) + { + WARN( "GetDeviceState device %p returned %#x\n", device, hr ); + res = JOYERR_PARMS; + } + else + { + if (info->dwFlags & JOY_RETURNX) info->dwXpos = state.x; + if (info->dwFlags & JOY_RETURNY) info->dwYpos = state.y; + if (info->dwFlags & JOY_RETURNZ) info->dwZpos = state.z; + if (info->dwFlags & JOY_RETURNR) info->dwRpos = state.r; + if (info->dwFlags & JOY_RETURNU) info->dwUpos = state.u; + if (info->dwFlags & JOY_RETURNV) info->dwVpos = state.v; + if (info->dwFlags & JOY_RETURNPOV) + { + if (state.pov == ~0) info->dwPOV = 0xffff; + else info->dwPOV = state.pov; + } + if (info->dwFlags & JOY_RETURNBUTTONS) + { + info->dwButtonNumber = info->dwButtons = 0; + for (i = 0; i < ARRAY_SIZE(state.buttons); ++i) + { + if (!state.buttons[i]) continue; + info->dwButtonNumber++; + info->dwButtons |= 1 << i; + } + } + } + + LeaveCriticalSection( &joystick_cs ); + + return res; }
/************************************************************************** @@ -313,7 +564,6 @@ MMRESULT WINAPI joyReleaseCapture( UINT id ) TRACE( "id %u.\n", id );
if (id >= ARRAY_SIZE(joysticks)) return JOYERR_PARMS; - if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
EnterCriticalSection( &joystick_cs );
@@ -343,7 +593,6 @@ MMRESULT WINAPI joySetCapture( HWND hwnd, UINT id, UINT period, BOOL changed ) if (id >= ARRAY_SIZE(joysticks) || hwnd == 0) return JOYERR_PARMS; if (period < JOY_PERIOD_MIN) period = JOY_PERIOD_MIN; else if (period > JOY_PERIOD_MAX) period = JOY_PERIOD_MAX; - if (!JOY_LoadDriver( id )) return MMSYSERR_NODRIVER;
EnterCriticalSection( &joystick_cs );
diff --git a/dlls/winmm/winemm.h b/dlls/winmm/winemm.h index d7bab0f531d..3459c2a85ef 100644 --- a/dlls/winmm/winemm.h +++ b/dlls/winmm/winemm.h @@ -153,6 +153,9 @@ MMRESULT WINMM_CheckCallback(DWORD_PTR dwCallback, DWORD fdwOpen, BOOL mixer) DE
void WINMM_DeleteWaveform(void) DECLSPEC_HIDDEN;
+void joystick_load( HMODULE instance ) DECLSPEC_HIDDEN; +void joystick_unload( void ) DECLSPEC_HIDDEN; + /* Global variables */ extern CRITICAL_SECTION WINMM_cs DECLSPEC_HIDDEN; extern HINSTANCE hWinMM32Instance DECLSPEC_HIDDEN; diff --git a/dlls/winmm/winmm.c b/dlls/winmm/winmm.c index eea29ea61e5..aab8bfb51a9 100644 --- a/dlls/winmm/winmm.c +++ b/dlls/winmm/winmm.c @@ -145,11 +145,13 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID fImpLoad) if (!WINMM_CreateIData(hInstDLL)) return FALSE;
+ joystick_load( hInstDLL ); break; case DLL_PROCESS_DETACH: if(fImpLoad) break;
+ joystick_unload(); MCI_SendCommand(MCI_ALL_DEVICE_ID, MCI_CLOSE, MCI_WAIT, 0L); MMDRV_Exit(); DRIVER_UnloadAll();
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- configure.ac | 2 - dlls/winejoystick.drv/Makefile.in | 10 - dlls/winejoystick.drv/joystick.c | 52 -- dlls/winejoystick.drv/joystick.h | 34 - dlls/winejoystick.drv/joystick_linux.c | 458 ---------- dlls/winejoystick.drv/joystick_osx.c | 935 -------------------- dlls/winejoystick.drv/winejoystick.drv.spec | 1 - tools/winapi/win32.api | 13 - 8 files changed, 1505 deletions(-) delete mode 100644 dlls/winejoystick.drv/Makefile.in delete mode 100644 dlls/winejoystick.drv/joystick.c delete mode 100644 dlls/winejoystick.drv/joystick.h delete mode 100644 dlls/winejoystick.drv/joystick_linux.c delete mode 100644 dlls/winejoystick.drv/joystick_osx.c delete mode 100644 dlls/winejoystick.drv/winejoystick.drv.spec
diff --git a/configure.ac b/configure.ac index d509cdae49c..55543c128cd 100644 --- a/configure.ac +++ b/configure.ac @@ -866,7 +866,6 @@ esac enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-no} enable_wineandroid_drv=${enable_wineandroid_drv:-no} enable_winemac_drv=${enable_winemac_drv:-no} -test "$ac_cv_header_linux_joystick_h" = "yes" -o "$ac_cv_header_IOKit_hid_IOHIDLib_h" = "yes" || enable_winejoystick_drv=${enable_winejoystick_drv:-no}
dnl Check for cross compiler to build test programs AC_SUBST(CROSSTARGET) @@ -3409,7 +3408,6 @@ WINE_CONFIG_MAKEFILE(dlls/winecrt0) WINE_CONFIG_MAKEFILE(dlls/wined3d) WINE_CONFIG_MAKEFILE(dlls/winegstreamer) WINE_CONFIG_MAKEFILE(dlls/winehid.sys) -WINE_CONFIG_MAKEFILE(dlls/winejoystick.drv) WINE_CONFIG_MAKEFILE(dlls/winemac.drv) WINE_CONFIG_MAKEFILE(dlls/winemapi) WINE_CONFIG_MAKEFILE(dlls/wineoss.drv) diff --git a/dlls/winejoystick.drv/Makefile.in b/dlls/winejoystick.drv/Makefile.in deleted file mode 100644 index 52564855994..00000000000 --- a/dlls/winejoystick.drv/Makefile.in +++ /dev/null @@ -1,10 +0,0 @@ -MODULE = winejoystick.drv -IMPORTS = winmm user32 -EXTRALIBS = $(IOKIT_LIBS) - -EXTRADLLFLAGS = -mcygwin - -C_SRCS = \ - joystick.c \ - joystick_linux.c \ - joystick_osx.c diff --git a/dlls/winejoystick.drv/joystick.c b/dlls/winejoystick.drv/joystick.c deleted file mode 100644 index 3e140b91175..00000000000 --- a/dlls/winejoystick.drv/joystick.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * WinMM joystick driver common code - * - * Copyright 1997 Andreas Mohr - * Copyright 2000 Wolfgang Schwotzer - * Copyright 2002 David Hagood - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "joystick.h" - - -/************************************************************************** - * DriverProc (JOYSTICK.@) - */ -LRESULT CALLBACK JSTCK_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg, LPARAM dwParam1, LPARAM dwParam2) -{ - switch(wMsg) { - case DRV_LOAD: return 1; - case DRV_FREE: return 1; - case DRV_OPEN: return driver_open((LPSTR)dwParam1, dwParam2); - case DRV_CLOSE: return driver_close(dwDevID); - case DRV_ENABLE: return 1; - case DRV_DISABLE: return 1; - case DRV_QUERYCONFIGURE: return 1; - case DRV_CONFIGURE: MessageBoxA(0, "JoyStick MultiMedia Driver !", "JoyStick Driver", MB_OK); return 1; - case DRV_INSTALL: return DRVCNF_RESTART; - case DRV_REMOVE: return DRVCNF_RESTART; - - case JDD_GETNUMDEVS: return 1; - case JDD_GETDEVCAPS: return driver_joyGetDevCaps(dwDevID, (LPJOYCAPSW)dwParam1, dwParam2); - case JDD_GETPOS: return driver_joyGetPos(dwDevID, (LPJOYINFO)dwParam1); - case JDD_SETCALIBRATION: - case JDD_CONFIGCHANGED: return JOYERR_NOCANDO; - case JDD_GETPOSEX: return driver_joyGetPosEx(dwDevID, (LPJOYINFOEX)dwParam1); - default: - return DefDriverProc(dwDevID, hDriv, wMsg, dwParam1, dwParam2); - } -} diff --git a/dlls/winejoystick.drv/joystick.h b/dlls/winejoystick.drv/joystick.h deleted file mode 100644 index 1ec1edb8133..00000000000 --- a/dlls/winejoystick.drv/joystick.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * WinMM joystick driver header - * - * Copyright 2015 Ken Thomases for CodeWeavers Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - - -#include <stdarg.h> - -#include "windef.h" -#include "winbase.h" -#include "mmddk.h" -#include "winuser.h" - - -LRESULT driver_open(LPSTR str, DWORD index) DECLSPEC_HIDDEN; -LRESULT driver_close(DWORD_PTR device_id) DECLSPEC_HIDDEN; -LRESULT driver_joyGetDevCaps(DWORD_PTR device_id, JOYCAPSW* caps, DWORD size) DECLSPEC_HIDDEN; -LRESULT driver_joyGetPosEx(DWORD_PTR device_id, JOYINFOEX* info) DECLSPEC_HIDDEN; -LRESULT driver_joyGetPos(DWORD_PTR device_id, JOYINFO* info) DECLSPEC_HIDDEN; diff --git a/dlls/winejoystick.drv/joystick_linux.c b/dlls/winejoystick.drv/joystick_linux.c deleted file mode 100644 index 50f06bc7331..00000000000 --- a/dlls/winejoystick.drv/joystick_linux.c +++ /dev/null @@ -1,458 +0,0 @@ -/* - * joystick functions - * - * Copyright 1997 Andreas Mohr - * Copyright 2000 Wolfgang Schwotzer - * Copyright 2002 David Hagood - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * NOTES: - * - * - nearly all joystick functions can be regarded as obsolete, - * as Linux (2.1.x) now supports extended joysticks with a completely - * new joystick driver interface - * New driver's documentation says: - * "For backward compatibility the old interface is still included, - * but will be dropped in the future." - * Thus we should implement the new interface and at most keep the old - * routines for backward compatibility. - * - better support of enhanced joysticks (Linux 2.2 interface is available) - * - support more joystick drivers (like the XInput extension) - * - should load joystick DLL as any other driver (instead of hardcoding) - * the driver's name, and load it as any low lever driver. - */ - -#include "config.h" - -#ifdef HAVE_LINUX_22_JOYSTICK_API - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#ifdef HAVE_LINUX_IOCTL_H -#include <linux/ioctl.h> -#endif -#include <linux/joystick.h> -#ifdef SW_MAX -#undef SW_MAX -#endif -#define JOYDEV_NEW "/dev/input/js%d" -#define JOYDEV_OLD "/dev/js%d" -#include <errno.h> - -#include "joystick.h" - -#include "wingdi.h" -#include "winnls.h" -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(joystick); - -#define MAXJOYSTICK (JOYSTICKID2 + 30) - -typedef struct tagWINE_JSTCK { - int joyIntf; - BOOL in_use; - /* Some extra info we need to make this actually work under the - Linux 2.2 event api. - First of all, we cannot keep closing and reopening the device file - - that blows away the state of the stick device, and we lose events. So, we - need to open the low-level device once, and close it when we are done. - - Secondly, the event API only gives us what's changed. However, Windows apps - want the whole state every time, so we have to cache the data. - */ - - int dev; /* Linux level device file descriptor */ - int x; - int y; - int z; - int r; - int u; - int v; - int pov_x; - int pov_y; - int buttons; - char axesMap[ABS_MAX + 1]; -} WINE_JSTCK; - -static WINE_JSTCK JSTCK_Data[MAXJOYSTICK]; - -/************************************************************************** - * JSTCK_drvGet [internal] - */ -static WINE_JSTCK *JSTCK_drvGet(DWORD_PTR dwDevID) -{ - int p; - - if ((dwDevID - (DWORD_PTR)JSTCK_Data) % sizeof(JSTCK_Data[0]) != 0) - return NULL; - p = (dwDevID - (DWORD_PTR)JSTCK_Data) / sizeof(JSTCK_Data[0]); - if (p < 0 || p >= MAXJOYSTICK || !((WINE_JSTCK*)dwDevID)->in_use) - return NULL; - - return (WINE_JSTCK*)dwDevID; -} - -/************************************************************************** - * driver_open - */ -LRESULT driver_open(LPSTR str, DWORD dwIntf) -{ - if (dwIntf >= MAXJOYSTICK || JSTCK_Data[dwIntf].in_use) - return 0; - - JSTCK_Data[dwIntf].joyIntf = dwIntf; - JSTCK_Data[dwIntf].dev = -1; - JSTCK_Data[dwIntf].in_use = TRUE; - return (LRESULT)&JSTCK_Data[dwIntf]; -} - -/************************************************************************** - * driver_close - */ -LRESULT driver_close(DWORD_PTR dwDevID) -{ - WINE_JSTCK* jstck = JSTCK_drvGet(dwDevID); - - if (jstck == NULL) - return 0; - jstck->in_use = FALSE; - if (jstck->dev > 0) - { - close(jstck->dev); - jstck->dev = 0; - } - return 1; -} - -struct js_status -{ - int buttons; - int x; - int y; -}; - -/************************************************************************** - * JSTCK_OpenDevice [internal] - */ -static int JSTCK_OpenDevice(WINE_JSTCK* jstick) -{ - char buf[20]; - int flags, fd, found_ix, i; - static DWORD last_attempt; - DWORD now; - - if (jstick->dev > 0) - return jstick->dev; - - now = GetTickCount(); - if (now - last_attempt < 2000) - return -1; - last_attempt = now; - - flags = O_RDONLY | O_NONBLOCK; - - /* The first joystick may not be at /dev/input/js0, find the correct - * first or second device. For example the driver for XBOX 360 wireless - * receiver creates entries starting at 20. - */ - for (found_ix = i = 0; i < MAXJOYSTICK; i++) { - sprintf(buf, JOYDEV_NEW, i); - if ((fd = open(buf, flags)) < 0) { - sprintf(buf, JOYDEV_OLD, i); - if ((fd = open(buf, flags)) < 0) - continue; - } - - if (found_ix++ == jstick->joyIntf) - { - TRACE("Found joystick[%d] at %s\n", jstick->joyIntf, buf); - jstick->dev = fd; - last_attempt = 0; - break; - } - - close(fd); - } - - if (jstick->dev > 0) - ioctl(jstick->dev, JSIOCGAXMAP, jstick->axesMap); - - return jstick->dev; -} - - -/************************************************************************** - * JoyGetDevCaps [MMSYSTEM.102] - */ -LRESULT driver_joyGetDevCaps(DWORD_PTR dwDevID, LPJOYCAPSW lpCaps, DWORD dwSize) -{ - WINE_JSTCK* jstck; - int dev; - char nrOfAxes; - char nrOfButtons; - char identString[MAXPNAMELEN]; - int i; - int driverVersion; - - if ((jstck = JSTCK_drvGet(dwDevID)) == NULL) - return MMSYSERR_NODRIVER; - - if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS; - ioctl(dev, JSIOCGAXES, &nrOfAxes); - ioctl(dev, JSIOCGBUTTONS, &nrOfButtons); - ioctl(dev, JSIOCGVERSION, &driverVersion); - ioctl(dev, JSIOCGNAME(sizeof(identString)), identString); - TRACE("Driver: 0x%06x, Name: %s, #Axes: %d, #Buttons: %d\n", - driverVersion, identString, nrOfAxes, nrOfButtons); - lpCaps->wMid = MM_MICROSOFT; - lpCaps->wPid = MM_PC_JOYSTICK; - MultiByteToWideChar(CP_UNIXCP, 0, identString, -1, lpCaps->szPname, MAXPNAMELEN); - lpCaps->szPname[MAXPNAMELEN-1] = '\0'; - lpCaps->wXmin = 0; - lpCaps->wXmax = 0xFFFF; - lpCaps->wYmin = 0; - lpCaps->wYmax = 0xFFFF; - lpCaps->wZmin = 0; - lpCaps->wZmax = (nrOfAxes >= 3) ? 0xFFFF : 0; -#ifdef BODGE_THE_HAT - /* Half-Life won't allow you to map an axis event to things like - "next weapon" and "use". Linux reports the hat on my stick as - axis U and V. So, IFF BODGE_THE_HAT is defined, lie through our - teeth and say we have 32 buttons, and we will map the axes to - the high buttons. Really, perhaps this should be a registry entry, - or even a parameter to the Linux joystick driver (which would completely - remove the need for this.) - */ - lpCaps->wNumButtons = 32; -#else - lpCaps->wNumButtons = nrOfButtons; -#endif - if (dwSize == sizeof(JOYCAPSW)) { - /* complete 95 structure */ - lpCaps->wRmin = 0; - lpCaps->wRmax = 0xFFFF; - lpCaps->wUmin = 0; - lpCaps->wUmax = 0xFFFF; - lpCaps->wVmin = 0; - lpCaps->wVmax = 0xFFFF; - lpCaps->wMaxAxes = 6; /* same as MS Joystick Driver */ - lpCaps->wNumAxes = 0; /* nr of axes in use */ - lpCaps->wMaxButtons = 32; /* same as MS Joystick Driver */ - lpCaps->szRegKey[0] = 0; - lpCaps->szOEMVxD[0] = 0; - lpCaps->wCaps = 0; - for (i = 0; i < nrOfAxes; i++) { - switch (jstck->axesMap[i]) { - case 0: /* X */ - case 1: /* Y */ - case 8: /* Wheel */ - case 9: /* Gas */ - lpCaps->wNumAxes++; - break; - case 2: /* Z */ - case 6: /* Throttle */ - case 10: /* Brake */ - lpCaps->wNumAxes++; - lpCaps->wCaps |= JOYCAPS_HASZ; - break; - case 5: /* Rz */ - case 7: /* Rudder */ - lpCaps->wNumAxes++; - lpCaps->wCaps |= JOYCAPS_HASR; - break; - case 3: /* Rx */ - lpCaps->wNumAxes++; - lpCaps->wCaps |= JOYCAPS_HASU; - break; - case 4: /* Ry */ - lpCaps->wNumAxes++; - lpCaps->wCaps |= JOYCAPS_HASV; - break; - case 16: /* Hat 0 X */ - case 17: /* Hat 0 Y */ - lpCaps->wCaps |= JOYCAPS_HASPOV | JOYCAPS_POV4DIR; - /* TODO: JOYCAPS_POVCTS handling */ - break; - default: - WARN("Unknown axis %hhu(%u). Skipped.\n", jstck->axesMap[i], i); - } - } - } - - return JOYERR_NOERROR; -} - -/************************************************************************** - * driver_joyGetPos - */ -LRESULT driver_joyGetPosEx(DWORD_PTR dwDevID, LPJOYINFOEX lpInfo) -{ - WINE_JSTCK* jstck; - int dev; - struct js_event ev; - - if ((jstck = JSTCK_drvGet(dwDevID)) == NULL) - return MMSYSERR_NODRIVER; - - if ((dev = JSTCK_OpenDevice(jstck)) < 0) return JOYERR_PARMS; - - while ((read(dev, &ev, sizeof(struct js_event))) > 0) { - if (ev.type == (JS_EVENT_AXIS)) { - switch (jstck->axesMap[ev.number]) { - case 0: /* X */ - case 8: /* Wheel */ - jstck->x = ev.value; - break; - case 1: /* Y */ - case 9: /* Gas */ - jstck->y = ev.value; - break; - case 2: /* Z */ - case 6: /* Throttle */ - case 10: /* Brake */ - jstck->z = ev.value; - break; - case 5: /* Rz */ - case 7: /* Rudder */ - jstck->r = ev.value; - break; - case 3: /* Rx */ - jstck->u = ev.value; - break; - case 4: /* Ry */ - jstck->v = ev.value; - break; - case 16: /* Hat 0 X */ - jstck->pov_x = ev.value; - break; - case 17: /* Hat 0 Y */ - jstck->pov_y = ev.value; - break; - default: - FIXME("Unknown joystick event '%d'\n", ev.number); - } - } else if (ev.type == (JS_EVENT_BUTTON)) { - if (ev.value) { - jstck->buttons |= (1 << ev.number); - /* FIXME: what to do for this field when - * multiple buttons are depressed ? - */ - if (lpInfo->dwFlags & JOY_RETURNBUTTONS) - lpInfo->dwButtonNumber = ev.number + 1; - } - else - jstck->buttons &= ~(1 << ev.number); - } - } - /* EAGAIN is returned when the queue is empty */ - if (errno != EAGAIN) { - /* FIXME: error should not be ignored */ - ERR("Error while reading joystick state (%s)\n", strerror(errno)); - } - /* Now, copy the cached values into Window's structure... */ - if (lpInfo->dwFlags & JOY_RETURNBUTTONS) - lpInfo->dwButtons = jstck->buttons; - if (lpInfo->dwFlags & JOY_RETURNX) - lpInfo->dwXpos = jstck->x + 32767; - if (lpInfo->dwFlags & JOY_RETURNY) - lpInfo->dwYpos = jstck->y + 32767; - if (lpInfo->dwFlags & JOY_RETURNZ) - lpInfo->dwZpos = jstck->z + 32767; - if (lpInfo->dwFlags & JOY_RETURNR) - lpInfo->dwRpos = jstck->r + 32767; -# ifdef BODGE_THE_HAT - else if (lpInfo->dwFlags & JOY_RETURNBUTTONS) - { - if (jstck->r > 0) - lpInfo->dwButtons |= 1<<7; - else if (jstck->r < 0) - lpInfo->dwButtons |= 1<<8; - } -# endif - if (lpInfo->dwFlags & JOY_RETURNU) - lpInfo->dwUpos = jstck->u + 32767; -# ifdef BODGE_THE_HAT - else if (lpInfo->dwFlags & JOY_RETURNBUTTONS) - { - if (jstck->u > 0) - lpInfo->dwButtons |= 1<<9; - else if (jstck->u < 0) - lpInfo->dwButtons |= 1<<10; - } -# endif - if (lpInfo->dwFlags & JOY_RETURNV) - lpInfo->dwVpos = jstck->v + 32767; - if (lpInfo->dwFlags & JOY_RETURNPOV) { - if (jstck->pov_y > 0) { - if (jstck->pov_x < 0) - lpInfo->dwPOV = 22500; /* SW */ - else if (jstck->pov_x > 0) - lpInfo->dwPOV = 13500; /* SE */ - else - lpInfo->dwPOV = 18000; /* S, JOY_POVBACKWARD */ - } else if (jstck->pov_y < 0) { - if (jstck->pov_x < 0) - lpInfo->dwPOV = 31500; /* NW */ - else if (jstck->pov_x > 0) - lpInfo->dwPOV = 4500; /* NE */ - else - lpInfo->dwPOV = 0; /* N, JOY_POVFORWARD */ - } else if (jstck->pov_x < 0) - lpInfo->dwPOV = 27000; /* W, JOY_POVLEFT */ - else if (jstck->pov_x > 0) - lpInfo->dwPOV = 9000; /* E, JOY_POVRIGHT */ - else - lpInfo->dwPOV = JOY_POVCENTERED; /* Center */ - } - - TRACE("x: %d, y: %d, z: %d, r: %d, u: %d, v: %d, buttons: 0x%04x, flags: 0x%04x (fd %d)\n", - lpInfo->dwXpos, lpInfo->dwYpos, lpInfo->dwZpos, - lpInfo->dwRpos, lpInfo->dwUpos, lpInfo->dwVpos, - lpInfo->dwButtons, lpInfo->dwFlags, dev - ); - - return JOYERR_NOERROR; -} - -/************************************************************************** - * driver_joyGetPos - */ -LRESULT driver_joyGetPos(DWORD_PTR dwDevID, LPJOYINFO lpInfo) -{ - JOYINFOEX ji; - LONG ret; - - memset(&ji, 0, sizeof(ji)); - - ji.dwSize = sizeof(ji); - ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS; - ret = driver_joyGetPosEx(dwDevID, &ji); - if (ret == JOYERR_NOERROR) { - lpInfo->wXpos = ji.dwXpos; - lpInfo->wYpos = ji.dwYpos; - lpInfo->wZpos = ji.dwZpos; - lpInfo->wButtons = ji.dwButtons; - } - - return ret; -} - -#endif /* HAVE_LINUX_JOYSTICK_H */ diff --git a/dlls/winejoystick.drv/joystick_osx.c b/dlls/winejoystick.drv/joystick_osx.c deleted file mode 100644 index 6f53477937f..00000000000 --- a/dlls/winejoystick.drv/joystick_osx.c +++ /dev/null @@ -1,935 +0,0 @@ -/* - * WinMM joystick driver OS X implementation - * - * Copyright 1997 Andreas Mohr - * Copyright 1998 Marcus Meissner - * Copyright 1998,1999 Lionel Ulmer - * Copyright 2000 Wolfgang Schwotzer - * Copyright 2000-2001 TransGaming Technologies Inc. - * Copyright 2002 David Hagood - * Copyright 2009 CodeWeavers, Aric Stewart - * Copyright 2015 Ken Thomases for CodeWeavers Inc. - * Copyright 2016 David Lawrie - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#if defined(HAVE_IOKIT_HID_IOHIDLIB_H) - -#define DWORD UInt32 -#define LPDWORD UInt32* -#define LONG SInt32 -#define LPLONG SInt32* -#define E_PENDING __carbon_E_PENDING -#define ULONG __carbon_ULONG -#define E_INVALIDARG __carbon_E_INVALIDARG -#define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY -#define E_HANDLE __carbon_E_HANDLE -#define E_ACCESSDENIED __carbon_E_ACCESSDENIED -#define E_UNEXPECTED __carbon_E_UNEXPECTED -#define E_FAIL __carbon_E_FAIL -#define E_ABORT __carbon_E_ABORT -#define E_POINTER __carbon_E_POINTER -#define E_NOINTERFACE __carbon_E_NOINTERFACE -#define E_NOTIMPL __carbon_E_NOTIMPL -#define S_FALSE __carbon_S_FALSE -#define S_OK __carbon_S_OK -#define HRESULT_FACILITY __carbon_HRESULT_FACILITY -#define IS_ERROR __carbon_IS_ERROR -#define FAILED __carbon_FAILED -#define SUCCEEDED __carbon_SUCCEEDED -#define MAKE_HRESULT __carbon_MAKE_HRESULT -#define HRESULT __carbon_HRESULT -#define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE -#include <IOKit/IOKitLib.h> -#include <IOKit/hid/IOHIDLib.h> -#undef ULONG -#undef E_INVALIDARG -#undef E_OUTOFMEMORY -#undef E_HANDLE -#undef E_ACCESSDENIED -#undef E_UNEXPECTED -#undef E_FAIL -#undef E_ABORT -#undef E_POINTER -#undef E_NOINTERFACE -#undef E_NOTIMPL -#undef S_FALSE -#undef S_OK -#undef HRESULT_FACILITY -#undef IS_ERROR -#undef FAILED -#undef SUCCEEDED -#undef MAKE_HRESULT -#undef HRESULT -#undef STDMETHODCALLTYPE -#undef DWORD -#undef LPDWORD -#undef LONG -#undef LPLONG -#undef E_PENDING - -#include "joystick.h" - -#include "wine/debug.h" - - -WINE_DEFAULT_DEBUG_CHANNEL(joystick); - - -#define MAXJOYSTICK (JOYSTICKID2 + 30) - - -enum { - AXIS_X, /* Winmm X */ - AXIS_Y, /* Winmm Y */ - AXIS_Z, /* Winmm Z */ - AXIS_RX, /* Winmm V */ - AXIS_RY, /* Winmm U */ - AXIS_RZ, /* Winmm R */ - NUM_AXES -}; - -struct axis { - IOHIDElementRef element; - CFIndex min_value, max_value; -}; - -typedef struct { - BOOL in_use; - IOHIDElementRef element; - struct axis axes[NUM_AXES]; - CFMutableArrayRef buttons; - IOHIDElementRef hatswitch; -} joystick_t; - - -static joystick_t joysticks[MAXJOYSTICK]; -static CFMutableArrayRef device_main_elements = NULL; - -static long get_device_property_long(IOHIDDeviceRef device, CFStringRef key) -{ - CFTypeRef ref; - long result = 0; - - if (device) - { - assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device)); - - ref = IOHIDDeviceGetProperty(device, key); - - if (ref && CFNumberGetTypeID() == CFGetTypeID(ref)) - CFNumberGetValue((CFNumberRef)ref, kCFNumberLongType, &result); - } - - return result; -} - -static CFStringRef copy_device_name(IOHIDDeviceRef device) -{ - CFStringRef name; - - if (device) - { - CFTypeRef ref_name; - - assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device)); - - ref_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - - if (ref_name && CFStringGetTypeID() == CFGetTypeID(ref_name)) - name = CFStringCreateCopy(kCFAllocatorDefault, ref_name); - else - { - long vendID, prodID; - - vendID = get_device_property_long(device, CFSTR(kIOHIDVendorIDKey)); - prodID = get_device_property_long(device, CFSTR(kIOHIDProductIDKey)); - name = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("0x%04lx 0x%04lx"), vendID, prodID); - } - } - else - { - ERR("NULL device\n"); - name = CFStringCreateCopy(kCFAllocatorDefault, CFSTR("")); - } - - return name; -} - -static long get_device_location_ID(IOHIDDeviceRef device) -{ - return get_device_property_long(device, CFSTR(kIOHIDLocationIDKey)); -} - -static const char* debugstr_cf(CFTypeRef t) -{ - CFStringRef s; - const char* ret; - - if (!t) return "(null)"; - - if (CFGetTypeID(t) == CFStringGetTypeID()) - s = t; - else - s = CFCopyDescription(t); - ret = CFStringGetCStringPtr(s, kCFStringEncodingUTF8); - if (ret) ret = debugstr_a(ret); - if (!ret) - { - const UniChar* u = CFStringGetCharactersPtr(s); - if (u) - ret = debugstr_wn((const WCHAR*)u, CFStringGetLength(s)); - } - if (!ret) - { - UniChar buf[200]; - int len = min(CFStringGetLength(s), ARRAY_SIZE(buf)); - CFStringGetCharacters(s, CFRangeMake(0, len), buf); - ret = debugstr_wn(buf, len); - } - if (s != t) CFRelease(s); - return ret; -} - -static const char* debugstr_device(IOHIDDeviceRef device) -{ - return wine_dbg_sprintf("<IOHIDDevice %p product %s IOHIDLocationID %lu>", device, - debugstr_cf(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))), - get_device_location_ID(device)); -} - -static const char* debugstr_element(IOHIDElementRef element) -{ - return wine_dbg_sprintf("<IOHIDElement %p type %d usage %u/%u device %p>", element, - IOHIDElementGetType(element), IOHIDElementGetUsagePage(element), - IOHIDElementGetUsage(element), IOHIDElementGetDevice(element)); -} - -static int axis_for_usage_GD(int usage) -{ - switch (usage) - { - case kHIDUsage_GD_X: return AXIS_X; - case kHIDUsage_GD_Y: return AXIS_Y; - case kHIDUsage_GD_Z: return AXIS_Z; - case kHIDUsage_GD_Rx: return AXIS_RX; - case kHIDUsage_GD_Ry: return AXIS_RY; - case kHIDUsage_GD_Rz: return AXIS_RZ; - } - - return -1; -} - -static int axis_for_usage_Sim(int usage) -{ - switch (usage) - { - case kHIDUsage_Sim_Rudder: return AXIS_RZ; - case kHIDUsage_Sim_Throttle: return AXIS_Z; - case kHIDUsage_Sim_Steering: return AXIS_X; - case kHIDUsage_Sim_Accelerator: return AXIS_Y; - case kHIDUsage_Sim_Brake: return AXIS_RZ; - } - - return -1; -} - -/************************************************************************** - * joystick_from_id - */ -static joystick_t* joystick_from_id(DWORD_PTR device_id) -{ - int index; - - if ((device_id - (DWORD_PTR)joysticks) % sizeof(joysticks[0]) != 0) - return NULL; - index = (device_id - (DWORD_PTR)joysticks) / sizeof(joysticks[0]); - if (index < 0 || index >= MAXJOYSTICK || !((joystick_t*)device_id)->in_use) - return NULL; - - return (joystick_t*)device_id; -} - -/************************************************************************** - * create_osx_device_match - */ -static CFDictionaryRef create_osx_device_match(int usage) -{ - CFDictionaryRef result = NULL; - int number; - CFStringRef keys[] = { CFSTR(kIOHIDDeviceUsagePageKey), CFSTR(kIOHIDDeviceUsageKey) }; - CFNumberRef values[2]; - int i; - - TRACE("usage %d\n", usage); - - number = kHIDPage_GenericDesktop; - values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &number); - values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage); - - if (values[0] && values[1]) - { - result = CFDictionaryCreate(NULL, (const void**)keys, (const void**)values, ARRAY_SIZE(values), - &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - if (!result) - ERR("CFDictionaryCreate failed.\n"); - } - else - ERR("CFNumberCreate failed.\n"); - - for (i = 0; i < ARRAY_SIZE(values); i++) - if (values[i]) CFRelease(values[i]); - - return result; -} - -/************************************************************************** - * find_top_level - */ -static CFIndex find_top_level(IOHIDDeviceRef hid_device, CFMutableArrayRef main_elements) -{ - CFArrayRef elements; - CFIndex total = 0; - - TRACE("hid_device %s\n", debugstr_device(hid_device)); - - if (!hid_device) - return 0; - - elements = IOHIDDeviceCopyMatchingElements(hid_device, NULL, 0); - - if (elements) - { - CFIndex i, count = CFArrayGetCount(elements); - for (i = 0; i < count; i++) - { - IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i); - int type = IOHIDElementGetType(element); - - TRACE("element %s\n", debugstr_element(element)); - - /* Check for top-level gaming device collections */ - if (type == kIOHIDElementTypeCollection && IOHIDElementGetParent(element) == 0) - { - int usage_page = IOHIDElementGetUsagePage(element); - int usage = IOHIDElementGetUsage(element); - - if (usage_page == kHIDPage_GenericDesktop && - (usage == kHIDUsage_GD_Joystick || usage == kHIDUsage_GD_GamePad || usage == kHIDUsage_GD_MultiAxisController)) - { - CFArrayAppendValue(main_elements, element); - total++; - } - } - } - CFRelease(elements); - } - - TRACE("-> total %d\n", (int)total); - return total; -} -/************************************************************************** - * device_name_comparator - * - * Virtual joysticks may not have a kIOHIDLocationIDKey and will default to location ID of 0, this orders virtual joysticks by their name - */ -static CFComparisonResult device_name_comparator(IOHIDDeviceRef device1, IOHIDDeviceRef device2) -{ - CFStringRef name1 = copy_device_name(device1), name2 = copy_device_name(device2); - CFComparisonResult result = CFStringCompare(name1, name2, (kCFCompareForcedOrdering | kCFCompareNumerically)); - CFRelease(name1); - CFRelease(name2); - return result; -} - -/************************************************************************** - * device_location_name_comparator - * - * Helper to sort device array first by location ID, since location IDs are consistent across boots & launches, then by product name - */ -static CFComparisonResult device_location_name_comparator(const void *val1, const void *val2, void *context) -{ - IOHIDDeviceRef device1 = (IOHIDDeviceRef)val1, device2 = (IOHIDDeviceRef)val2; - long loc1 = get_device_location_ID(device1), loc2 = get_device_location_ID(device2); - - if (loc1 < loc2) - return kCFCompareLessThan; - else if (loc1 > loc2) - return kCFCompareGreaterThan; - return device_name_comparator(device1, device2); -} - -/************************************************************************** - * copy_set_to_array - * - * Helper to copy the CFSet to a CFArray - */ -static void copy_set_to_array(const void *value, void *context) -{ - CFArrayAppendValue(context, value); -} - -/************************************************************************** - * find_osx_devices - */ -static int find_osx_devices(void) -{ - IOHIDManagerRef hid_manager; - int usages[] = { kHIDUsage_GD_Joystick, kHIDUsage_GD_GamePad, kHIDUsage_GD_MultiAxisController }; - int i; - CFDictionaryRef matching_dicts[ARRAY_SIZE(usages)]; - CFArrayRef matching; - CFSetRef devset; - - TRACE("()\n"); - - hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, 0L); - if (IOHIDManagerOpen(hid_manager, 0) != kIOReturnSuccess) - { - ERR("Couldn't open IOHIDManager.\n"); - CFRelease(hid_manager); - return 0; - } - - for (i = 0; i < ARRAY_SIZE(matching_dicts); i++) - { - matching_dicts[i] = create_osx_device_match(usages[i]); - if (!matching_dicts[i]) - { - while (i > 0) - CFRelease(matching_dicts[--i]); - goto fail; - } - } - - matching = CFArrayCreate(NULL, (const void**)matching_dicts, ARRAY_SIZE(matching_dicts), - &kCFTypeArrayCallBacks); - - for (i = 0; i < ARRAY_SIZE(matching_dicts); i++) - CFRelease(matching_dicts[i]); - - IOHIDManagerSetDeviceMatchingMultiple(hid_manager, matching); - CFRelease(matching); - devset = IOHIDManagerCopyDevices(hid_manager); - if (devset) - { - CFIndex num_devices, num_main_elements; - CFMutableArrayRef devices; - - num_devices = CFSetGetCount(devset); - devices = CFArrayCreateMutable(kCFAllocatorDefault, num_devices, &kCFTypeArrayCallBacks); - CFSetApplyFunction(devset, copy_set_to_array, (void *)devices); - CFArraySortValues(devices, CFRangeMake(0, num_devices), device_location_name_comparator, NULL); - - CFRelease(devset); - if (!devices) - goto fail; - - device_main_elements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - if (!device_main_elements) - { - CFRelease(devices); - goto fail; - } - - num_main_elements = 0; - for (i = 0; i < num_devices; i++) - { - IOHIDDeviceRef hid_device = (IOHIDDeviceRef)CFArrayGetValueAtIndex(devices, i); - TRACE("hid_device %s\n", debugstr_device(hid_device)); - num_main_elements += find_top_level(hid_device, device_main_elements); - } - - CFRelease(devices); - - TRACE("found %i device(s), %i collection(s)\n",(int)num_devices,(int)num_main_elements); - return (int)num_main_elements; - } - -fail: - IOHIDManagerClose(hid_manager, 0); - CFRelease(hid_manager); - return 0; -} - -/************************************************************************** - * collect_joystick_elements - */ -static void collect_joystick_elements(joystick_t* joystick, IOHIDElementRef collection) -{ - CFIndex i, count; - CFArrayRef children = IOHIDElementGetChildren(collection); - - TRACE("collection %s\n", debugstr_element(collection)); - - count = CFArrayGetCount(children); - for (i = 0; i < count; i++) - { - IOHIDElementRef child; - int type; - uint32_t usage_page; - - child = (IOHIDElementRef)CFArrayGetValueAtIndex(children, i); - TRACE("child %s\n", debugstr_element(child)); - type = IOHIDElementGetType(child); - usage_page = IOHIDElementGetUsagePage(child); - - switch (type) - { - case kIOHIDElementTypeCollection: - collect_joystick_elements(joystick, child); - break; - case kIOHIDElementTypeInput_Button: - { - TRACE("kIOHIDElementTypeInput_Button usage_page %d\n", usage_page); - - /* avoid strange elements found on the 360 controller */ - if (usage_page == kHIDPage_Button) - CFArrayAppendValue(joystick->buttons, child); - break; - } - case kIOHIDElementTypeInput_Axis: - case kIOHIDElementTypeInput_Misc: - { - uint32_t usage = IOHIDElementGetUsage( child ); - switch (usage_page) - { - case kHIDPage_GenericDesktop: - { - switch(usage) - { - case kHIDUsage_GD_Hatswitch: - { - TRACE("kIOHIDElementTypeInput_Axis/Misc / kHIDUsage_GD_Hatswitch\n"); - if (joystick->hatswitch) - TRACE(" ignoring additional hatswitch\n"); - else - joystick->hatswitch = (IOHIDElementRef)CFRetain(child); - break; - } - case kHIDUsage_GD_X: - case kHIDUsage_GD_Y: - case kHIDUsage_GD_Z: - case kHIDUsage_GD_Rx: - case kHIDUsage_GD_Ry: - case kHIDUsage_GD_Rz: - { - int axis = axis_for_usage_GD(usage); - TRACE("kIOHIDElementTypeInput_Axis/Misc / kHIDUsage_GD_<axis> (%d) axis %d\n", usage, axis); - if (axis < 0 || joystick->axes[axis].element) - TRACE(" ignoring\n"); - else - { - joystick->axes[axis].element = (IOHIDElementRef)CFRetain(child); - joystick->axes[axis].min_value = IOHIDElementGetLogicalMin(child); - joystick->axes[axis].max_value = IOHIDElementGetLogicalMax(child); - } - break; - } - case kHIDUsage_GD_Slider: - case kHIDUsage_GD_Dial: - case kHIDUsage_GD_Wheel: - { - /* if one axis is taken, fall to the next until axes are filled */ - int possible_axes[3] = {AXIS_Z,AXIS_RY,AXIS_RX}; - int axis = 0; - while(axis < 3 && joystick->axes[possible_axes[axis]].element) - axis++; - if (axis == 3) - TRACE("kIOHIDElementTypeInput_Axis/Misc / kHIDUsage_GD_<axis> (%d)\n ignoring\n", usage); - else - { - TRACE("kIOHIDElementTypeInput_Axis/Misc / kHIDUsage_GD_<axis> (%d) axis %d\n", usage, possible_axes[axis]); - joystick->axes[possible_axes[axis]].element = (IOHIDElementRef)CFRetain(child); - joystick->axes[possible_axes[axis]].min_value = IOHIDElementGetLogicalMin(child); - joystick->axes[possible_axes[axis]].max_value = IOHIDElementGetLogicalMax(child); - } - break; - } - default: - FIXME("kIOHIDElementTypeInput_Axis/Misc / Unhandled GD Page usage %d\n", usage); - break; - } - break; - } - case kHIDPage_Simulation: - { - switch(usage) - { - case kHIDUsage_Sim_Rudder: - case kHIDUsage_Sim_Throttle: - case kHIDUsage_Sim_Steering: - case kHIDUsage_Sim_Accelerator: - case kHIDUsage_Sim_Brake: - { - int axis = axis_for_usage_Sim(usage); - TRACE("kIOHIDElementTypeInput_Axis/Misc / kHIDUsage_Sim_<axis> (%d) axis %d\n", usage, axis); - if (axis < 0 || joystick->axes[axis].element) - TRACE(" ignoring\n"); - else - { - joystick->axes[axis].element = (IOHIDElementRef)CFRetain(child); - joystick->axes[axis].min_value = IOHIDElementGetLogicalMin(child); - joystick->axes[axis].max_value = IOHIDElementGetLogicalMax(child); - } - break; - } - default: - FIXME("kIOHIDElementTypeInput_Axis/Misc / Unhandled Sim Page usage %d\n", usage); - break; - } - break; - } - default: - FIXME("kIOHIDElementTypeInput_Axis/Misc / Unhandled Usage Page %d\n", usage_page); - break; - } - break; - } - case kIOHIDElementTypeFeature: - /* Describes input and output elements not intended for consumption by the end user. Ignoring. */ - break; - default: - FIXME("Unhandled type %i\n",type); - break; - } - } -} - -/************************************************************************** - * button_usage_comparator - */ -static CFComparisonResult button_usage_comparator(const void *val1, const void *val2, void *context) -{ - IOHIDElementRef element1 = (IOHIDElementRef)val1, element2 = (IOHIDElementRef)val2; - int usage1 = IOHIDElementGetUsage(element1), usage2 = IOHIDElementGetUsage(element2); - - if (usage1 < usage2) - return kCFCompareLessThan; - if (usage1 > usage2) - return kCFCompareGreaterThan; - return kCFCompareEqualTo; -} - -/************************************************************************** - * driver_open - */ -LRESULT driver_open(LPSTR str, DWORD index) -{ - if (index >= MAXJOYSTICK || joysticks[index].in_use) - return 0; - - joysticks[index].in_use = TRUE; - return (LRESULT)&joysticks[index]; -} - -/************************************************************************** - * driver_close - */ -LRESULT driver_close(DWORD_PTR device_id) -{ - joystick_t* joystick = joystick_from_id(device_id); - int i; - - if (joystick == NULL) - return 0; - - CFRelease(joystick->element); - for (i = 0; i < NUM_AXES; i++) - { - if (joystick->axes[i].element) - CFRelease(joystick->axes[i].element); - } - if (joystick->buttons) - CFRelease(joystick->buttons); - if (joystick->hatswitch) - CFRelease(joystick->hatswitch); - - memset(joystick, 0, sizeof(*joystick)); - return 1; -} - -/************************************************************************** - * open_joystick - */ -static BOOL open_joystick(joystick_t* joystick) -{ - CFIndex index; - CFRange range; - - if (joystick->element) - return TRUE; - - if (!device_main_elements) - { - find_osx_devices(); - if (!device_main_elements) - return FALSE; - } - - index = joystick - joysticks; - if (index >= CFArrayGetCount(device_main_elements)) - return FALSE; - - joystick->element = (IOHIDElementRef)CFArrayGetValueAtIndex(device_main_elements, index); - joystick->buttons = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - collect_joystick_elements(joystick, joystick->element); - - /* Sort buttons into correct order */ - range.location = 0; - range.length = CFArrayGetCount(joystick->buttons); - CFArraySortValues(joystick->buttons, range, button_usage_comparator, NULL); - if (range.length > 32) - { - /* Delete any buttons beyond the first 32 */ - range.location = 32; - range.length -= 32; - CFArrayReplaceValues(joystick->buttons, range, NULL, 0); - } - - return TRUE; -} - - -/************************************************************************** - * driver_joyGetDevCaps - */ -LRESULT driver_joyGetDevCaps(DWORD_PTR device_id, JOYCAPSW* caps, DWORD size) -{ - joystick_t* joystick; - IOHIDDeviceRef device; - - if ((joystick = joystick_from_id(device_id)) == NULL) - return MMSYSERR_NODRIVER; - - if (!open_joystick(joystick)) - return JOYERR_PARMS; - - caps->szPname[0] = 0; - - device = IOHIDElementGetDevice(joystick->element); - if (device) - { - CFStringRef product_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)); - if (product_name) - { - CFRange range; - - range.location = 0; - range.length = min(MAXPNAMELEN - 1, CFStringGetLength(product_name)); - CFStringGetCharacters(product_name, range, (UniChar*)caps->szPname); - caps->szPname[range.length] = 0; - } - } - - caps->wMid = MM_MICROSOFT; - caps->wPid = MM_PC_JOYSTICK; - caps->wXmin = 0; - caps->wXmax = 0xFFFF; - caps->wYmin = 0; - caps->wYmax = 0xFFFF; - caps->wZmin = 0; - caps->wZmax = joystick->axes[AXIS_Z].element ? 0xFFFF : 0; - caps->wNumButtons = CFArrayGetCount(joystick->buttons); - if (size == sizeof(JOYCAPSW)) - { - int i; - - /* complete 95 structure */ - caps->wRmin = 0; - caps->wRmax = 0xFFFF; - caps->wUmin = 0; - caps->wUmax = 0xFFFF; - caps->wVmin = 0; - caps->wVmax = 0xFFFF; - caps->wMaxAxes = 6; /* same as MS Joystick Driver */ - caps->wNumAxes = 0; - caps->wMaxButtons = 32; /* same as MS Joystick Driver */ - caps->szRegKey[0] = 0; - caps->szOEMVxD[0] = 0; - caps->wCaps = 0; - - for (i = 0; i < NUM_AXES; i++) - { - if (joystick->axes[i].element) - { - caps->wNumAxes++; - switch (i) - { - case AXIS_Z: caps->wCaps |= JOYCAPS_HASZ; break; - case AXIS_RX: caps->wCaps |= JOYCAPS_HASV; break; - case AXIS_RY: caps->wCaps |= JOYCAPS_HASU; break; - case AXIS_RZ: caps->wCaps |= JOYCAPS_HASR; break; - } - } - } - - if (joystick->hatswitch) - caps->wCaps |= JOYCAPS_HASPOV | JOYCAPS_POV4DIR; - } - - TRACE("name %s buttons %u axes %d caps 0x%08x\n", debugstr_w(caps->szPname), caps->wNumButtons, caps->wNumAxes, caps->wCaps); - - return JOYERR_NOERROR; -} - -/* - * Helper to get the value from an element - */ -static LRESULT driver_getElementValue(IOHIDDeviceRef device, IOHIDElementRef element, IOHIDValueRef *pValueRef) -{ - IOReturn ret; - ret = IOHIDDeviceGetValue(device, element, pValueRef); - switch (ret) - { - case kIOReturnSuccess: - return JOYERR_NOERROR; - case kIOReturnNotAttached: - return JOYERR_UNPLUGGED; - default: - ERR("IOHIDDeviceGetValue returned 0x%x\n",ret); - return JOYERR_NOCANDO; - } -} - -/************************************************************************** - * driver_joyGetPosEx - */ -LRESULT driver_joyGetPosEx(DWORD_PTR device_id, JOYINFOEX* info) -{ - static const struct { - DWORD flag; - off_t offset; - } axis_map[NUM_AXES] = { - { JOY_RETURNX, FIELD_OFFSET(JOYINFOEX, dwXpos) }, - { JOY_RETURNY, FIELD_OFFSET(JOYINFOEX, dwYpos) }, - { JOY_RETURNZ, FIELD_OFFSET(JOYINFOEX, dwZpos) }, - { JOY_RETURNV, FIELD_OFFSET(JOYINFOEX, dwVpos) }, - { JOY_RETURNU, FIELD_OFFSET(JOYINFOEX, dwUpos) }, - { JOY_RETURNR, FIELD_OFFSET(JOYINFOEX, dwRpos) }, - }; - - joystick_t* joystick; - IOHIDDeviceRef device; - CFIndex i, count; - IOHIDValueRef valueRef; - long value; - LRESULT rc; - - if ((joystick = joystick_from_id(device_id)) == NULL) - return MMSYSERR_NODRIVER; - - if (!open_joystick(joystick)) - return JOYERR_PARMS; - - device = IOHIDElementGetDevice(joystick->element); - - if (info->dwFlags & JOY_RETURNBUTTONS) - { - info->dwButtons = 0; - info->dwButtonNumber = 0; - - count = CFArrayGetCount(joystick->buttons); - for (i = 0; i < count; i++) - { - IOHIDElementRef button = (IOHIDElementRef)CFArrayGetValueAtIndex(joystick->buttons, i); - rc = driver_getElementValue(device, button, &valueRef); - if (rc != JOYERR_NOERROR) - return rc; - value = IOHIDValueGetIntegerValue(valueRef); - if (value) - { - info->dwButtons |= 1 << i; - info->dwButtonNumber++; - } - } - } - - for (i = 0; i < NUM_AXES; i++) - { - if (info->dwFlags & axis_map[i].flag) - { - DWORD* field = (DWORD*)((char*)info + axis_map[i].offset); - if (joystick->axes[i].element) - { - rc = driver_getElementValue(device, joystick->axes[i].element, &valueRef); - if (rc != JOYERR_NOERROR) - return rc; - value = IOHIDValueGetIntegerValue(valueRef) - joystick->axes[i].min_value; - *field = MulDiv(value, 0xFFFF, joystick->axes[i].max_value - joystick->axes[i].min_value); - } - else - { - *field = 0; - info->dwFlags &= ~axis_map[i].flag; - } - } - } - - if (info->dwFlags & JOY_RETURNPOV) - { - if (joystick->hatswitch) - { - rc = driver_getElementValue(device, joystick->hatswitch, &valueRef); - if (rc != JOYERR_NOERROR) - return rc; - value = IOHIDValueGetIntegerValue(valueRef); - if (value >= 8) - info->dwPOV = JOY_POVCENTERED; - else - info->dwPOV = value * 4500; - } - else - { - info->dwPOV = JOY_POVCENTERED; - info->dwFlags &= ~JOY_RETURNPOV; - } - } - - TRACE("x: %d, y: %d, z: %d, r: %d, u: %d, v: %d, buttons: 0x%04x, pov %d, flags: 0x%04x\n", - info->dwXpos, info->dwYpos, info->dwZpos, info->dwRpos, info->dwUpos, info->dwVpos, info->dwButtons, info->dwPOV, info->dwFlags); - - return JOYERR_NOERROR; -} - -/************************************************************************** - * driver_joyGetPos - */ -LRESULT driver_joyGetPos(DWORD_PTR device_id, JOYINFO* info) -{ - JOYINFOEX ji; - LONG ret; - - memset(&ji, 0, sizeof(ji)); - - ji.dwSize = sizeof(ji); - ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS; - ret = driver_joyGetPosEx(device_id, &ji); - if (ret == JOYERR_NOERROR) - { - info->wXpos = ji.dwXpos; - info->wYpos = ji.dwYpos; - info->wZpos = ji.dwZpos; - info->wButtons = ji.dwButtons; - } - - return ret; -} - -#endif /* HAVE_IOKIT_HID_IOHIDLIB_H */ diff --git a/dlls/winejoystick.drv/winejoystick.drv.spec b/dlls/winejoystick.drv/winejoystick.drv.spec deleted file mode 100644 index 29932efde7c..00000000000 --- a/dlls/winejoystick.drv/winejoystick.drv.spec +++ /dev/null @@ -1 +0,0 @@ -@ stdcall -private DriverProc(long long long long long) JSTCK_DriverProc diff --git a/tools/winapi/win32.api b/tools/winapi/win32.api index d9b77dbce39..5f3dd85cc93 100644 --- a/tools/winapi/win32.api +++ b/tools/winapi/win32.api @@ -5615,19 +5615,6 @@ IUnknown * IWineD3D * IWineD3DClipper *
-%%winejoystick.drv - -%long - -HDRVR -LPARAM -LRESULT -UINT - -%long --pointer - -DWORD_PTR - %%l3codeca.acm
%long
This leads to a regression, see https://bugs.winehq.org/show_bug.cgi?id=52314
Not sure how that ever worked, since AFAIK shutting down the thread inside dll detach should always cause a deadlock.
On Freitag, 10. Dezember 2021 09:44:44 CET Rémi Bernon wrote:
When thread shuts down, instead of holding and releasing a module ref.
This keeps the thread alive until the module is unloaded, instead of keeping track of live IDirectInput instances.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
On 1/3/22 01:14, Fabian Maurer wrote:
This leads to a regression, see https://bugs.winehq.org/show_bug.cgi?id=52314
Not sure how that ever worked, since AFAIK shutting down the thread inside dll detach should always cause a deadlock.
On Freitag, 10. Dezember 2021 09:44:44 CET Rémi Bernon wrote:
When thread shuts down, instead of holding and releasing a module ref.
This keeps the thread alive until the module is unloaded, instead of keeping track of live IDirectInput instances.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
Yes, I intended to send some patches to fix it. It works in most cases when the DLL is unloaded on process shutdown (where LdrShutdownThread does nothing), but not when the DLL is manually unloaded.
As we're doing the same thing in XInput, it may cause the same thing there, although I haven't seen any report about it yet.
However, it'll be much more difficult to fix it here as there's no device creation / acquire mechanism, and no way to tell exactly when the thread can safely exit.