/* Copyright (C) 2003-2006 Andrey Nazarov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // // win_dinput.c - DirectInput 7 mouse driver // #include "win_local.h" #define DIRECTINPUT_VERSION 0x0700 #include #ifndef DIDFT_OPTIONAL #define DIDFT_OPTIONAL 0x80000000 #endif static HMODULE hDirectInput; typedef HRESULT (WINAPI *LPDIRECTINPUTCREATE)( HINSTANCE, DWORD, LPDIRECTINPUT *, LPUNKNOWN ); static LPDIRECTINPUTCREATE pDirectInputCreate; static qboolean di_active; // qfalse when not focus app static qboolean di_initialized; static LPDIRECTINPUT di; static LPDIRECTINPUTDEVICE di_mouse; static DIOBJECTDATAFORMAT mouseObjectDataFormat[] = { { &GUID_XAxis, DIMOFS_X, DIDFT_RELAXIS|DIDFT_ANYINSTANCE, 0 }, { &GUID_YAxis, DIMOFS_Y, DIDFT_RELAXIS|DIDFT_ANYINSTANCE, 0 }, { &GUID_ZAxis, DIMOFS_Z, DIDFT_RELAXIS|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 }, { NULL, DIMOFS_BUTTON0, DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, { NULL, DIMOFS_BUTTON1, DIDFT_BUTTON|DIDFT_ANYINSTANCE, 0 }, { NULL, DIMOFS_BUTTON2, DIDFT_BUTTON|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 }, { NULL, DIMOFS_BUTTON3, DIDFT_BUTTON|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 }, { NULL, DIMOFS_BUTTON4, DIDFT_BUTTON|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 }, { NULL, DIMOFS_BUTTON5, DIDFT_BUTTON|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 }, { NULL, DIMOFS_BUTTON6, DIDFT_BUTTON|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 }, { NULL, DIMOFS_BUTTON7, DIDFT_BUTTON|DIDFT_ANYINSTANCE|DIDFT_OPTIONAL, 0 } }; static DIDATAFORMAT mouseDataFormat = { sizeof( DIDATAFORMAT ), sizeof( DIOBJECTDATAFORMAT ), DIDF_RELAXIS, sizeof( DIMOUSESTATE2 ), sizeof( mouseObjectDataFormat ) / sizeof( mouseObjectDataFormat[0] ), mouseObjectDataFormat }; static DIPROPDWORD mouseBufferSize = { { sizeof( DIPROPDWORD ), sizeof( DIPROPHEADER ), 0, DIPH_DEVICE }, 32 }; #ifdef DEFINE_GUID #undef DEFINE_GUID #endif #define DEFINE_GUID( name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8 ) \ const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } DEFINE_GUID( GUID_SysMouse, 0x6F1D2B60, 0xD5A0, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 ); DEFINE_GUID( GUID_XAxis, 0xA36D02E0, 0xC9F3, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 ); DEFINE_GUID( GUID_YAxis, 0xA36D02E1, 0xC9F3, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 ); DEFINE_GUID( GUID_ZAxis, 0xA36D02E2, 0xC9F3, 0x11CF, 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00 ); /* =========== DI_SendMouseMoveEvents =========== */ void DI_SendMouseMoveEvents( void ) { DIDEVICEOBJECTDATA data[16]; LPDIDEVICEOBJECTDATA p, last; DIMOUSESTATE2 state; DWORD numElements, button; int value; HRESULT hr; if( !di_initialized ) { return; } if( !di_active ) { return; } do { numElements = 16; hr = IDirectInputDevice_GetDeviceData( di_mouse, sizeof( data[0] ), data, &numElements, 0 ); if( hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED ) { IDirectInputDevice_Acquire( di_mouse ); return; } if( FAILED( hr ) ) { Com_EPrintf( "GetDeviceData failed with error 0x%lX\n", hr ); return; } last = data + numElements; for( p = data; p != last; p++ ) { switch( p->dwOfs ) { case DIMOFS_BUTTON0: case DIMOFS_BUTTON1: case DIMOFS_BUTTON2: case DIMOFS_BUTTON3: case DIMOFS_BUTTON4: case DIMOFS_BUTTON5: case DIMOFS_BUTTON6: case DIMOFS_BUTTON7: button = p->dwOfs - DIMOFS_BUTTON0; if( p->dwData & 0x80 ) { Key_Event( K_MOUSE1 + button, qtrue, p->dwTimeStamp ); } else { Key_Event( K_MOUSE1 + button, qfalse, p->dwTimeStamp ); } break; case DIMOFS_Z: value = p->dwData; if( !value ) { break; } if( value > 0 ) { Key_Event( K_MWHEELUP, qtrue, p->dwTimeStamp ); Key_Event( K_MWHEELUP, qfalse, p->dwTimeStamp ); } else { Key_Event( K_MWHEELDOWN, qtrue, p->dwTimeStamp ); Key_Event( K_MWHEELDOWN, qfalse, p->dwTimeStamp ); } break; default: break; } } } while( hr == DI_BUFFEROVERFLOW ); hr = IDirectInputDevice_GetDeviceState( di_mouse, sizeof( state ), &state ); if( FAILED( hr ) ) { Com_EPrintf( "GetDeviceState failed with error 0x%lX\n", hr ); return; } if( state.lX || state.lY ) { CL_MouseEvent( state.lX, state.lY ); } } /* =========== DI_ShutdownMouse =========== */ static void DI_ShutdownMouse( void ) { Com_Printf( "Shutting down DirectInput\n" ); if( di_mouse ) { if( di_active ) { IDirectInputDevice_Unacquire( di_mouse ); } IDirectInputDevice_Release( di_mouse ); di_mouse = NULL; } if( di ) { IDirectInput_Release( di ); di = NULL; } di_active = qfalse; di_initialized = qfalse; } /* =========== DI_StartupMouse =========== */ static qboolean DI_InitMouse( void ) { HRESULT hr; if( !win.wnd ) { return qfalse; } Com_Printf( "Initializing DirectInput\n" ); if( !hDirectInput ) { hDirectInput = LoadLibrary( "dinput.dll" ); if( !hDirectInput ) { Com_EPrintf( "Failed to load dinput.dll\n" ); return qfalse; } pDirectInputCreate = ( LPDIRECTINPUTCREATE ) GetProcAddress( hDirectInput, "DirectInputCreateA" ); if( !pDirectInputCreate ) { Com_EPrintf( "Failed to obtain DirectInputCreate\n" ); goto fail; } } hr = pDirectInputCreate( hGlobalInstance, DIRECTINPUT_VERSION, &di, NULL ); if( FAILED( hr ) ) { Com_EPrintf( "DirectInputCreate failed with error 0x%lX\n", hr ); goto fail; } hr = IDirectInput_CreateDevice( di, &GUID_SysMouse, &di_mouse, NULL ); if( FAILED( hr ) ) { Com_EPrintf( "CreateDevice failed with error 0x%lX\n", hr ); goto fail; } hr = IDirectInputDevice_SetDataFormat( di_mouse, &mouseDataFormat ); if( FAILED( hr ) ) { Com_EPrintf( "SetDataFormat failed with error 0x%lX\n", hr ); goto fail; } hr = IDirectInputDevice_SetCooperativeLevel( di_mouse, win.wnd, DISCL_EXCLUSIVE|DISCL_FOREGROUND ); if( FAILED( hr ) ) { Com_EPrintf( "SetCooperativeLevel failed with error 0x%lX\n", hr ); goto fail; } hr = IDirectInputDevice_SetProperty( di_mouse, DIPROP_BUFFERSIZE, &mouseBufferSize.diph ); if( FAILED( hr ) ) { Com_EPrintf( "SetProperty failed with error 0x%lX\n", hr ); goto fail; } di_initialized = qtrue; return qtrue; fail: if( di_mouse ) { IDirectInputDevice_Release( di_mouse ); di_mouse = NULL; } if( di ) { IDirectInput_Release( di ); di = NULL; } return qfalse; } /* =========== DI_ActivateMouse Called when the main window gains or loses focus. The window may have been destroyed and recreated between a deactivate and an activate. =========== */ static void DI_ActivateMouse( qboolean active ) { HRESULT hr; if( !di_initialized ) { return; } if( di_active == active ) { return; } if( active ) { Com_DPrintf( "IDirectInputDevice_Acquire\n" ); hr = IDirectInputDevice_Acquire( di_mouse ); if( FAILED( hr ) ) { Com_EPrintf( "Failed to acquire mouse, error 0x%lX\n", hr ); } } else { Com_DPrintf( "IDirectInputDevice_Unacquire\n" ); hr = IDirectInputDevice_Unacquire( di_mouse ); if( FAILED( hr ) ) { Com_EPrintf( "Failed to unacquire mouse, error 0x%lX\n", hr ); } } di_active = active; } /* =================== DI_ClearMouseStates =================== */ static void DI_ClearMouseStates( void ) { } /* @@@@@@@@@@@@@@@@@@@ DI_FillAPI @@@@@@@@@@@@@@@@@@@ */ void DI_FillAPI( inputAPI_t *api ) { api->Init = DI_InitMouse; api->Shutdown = DI_ShutdownMouse; api->Activate = DI_ActivateMouse; api->Frame = DI_SendMouseMoveEvents; api->ClearStates = DI_ClearMouseStates; }