2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-12-03 22:55:27 +00:00
Copyright ( C ) 2012 Robert Beckebans
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "../sys_session_local.h"
# include "win_local.h"
# define DINPUT_BUFFERSIZE 256
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DIRECT INPUT KEYBOARD CONTROL
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool IN_StartupKeyboard ( )
{
HRESULT hr ;
bool bExclusive ;
bool bForeground ;
bool bImmediate ;
bool bDisableWindowsKey ;
DWORD dwCoopFlags ;
if ( ! win32 . g_pdi )
{
common - > Printf ( " keyboard: DirectInput has not been started \n " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
if ( win32 . g_pKeyboard )
{
2012-11-26 18:58:24 +00:00
win32 . g_pKeyboard - > Release ( ) ;
win32 . g_pKeyboard = NULL ;
}
2012-11-28 15:47:07 +00:00
// Detrimine where the buffer would like to be allocated
bExclusive = false ;
bForeground = true ;
bImmediate = false ;
bDisableWindowsKey = true ;
if ( bExclusive )
dwCoopFlags = DISCL_EXCLUSIVE ;
else
dwCoopFlags = DISCL_NONEXCLUSIVE ;
if ( bForeground )
dwCoopFlags | = DISCL_FOREGROUND ;
else
dwCoopFlags | = DISCL_BACKGROUND ;
// Disabling the windows key is only allowed only if we are in foreground nonexclusive
if ( bDisableWindowsKey & & ! bExclusive & & bForeground )
dwCoopFlags | = DISCL_NOWINKEY ;
// Obtain an interface to the system keyboard device.
if ( FAILED ( hr = win32 . g_pdi - > CreateDevice ( GUID_SysKeyboard , & win32 . g_pKeyboard , NULL ) ) )
{
common - > Printf ( " keyboard: couldn't find a keyboard device \n " ) ;
return false ;
}
// Set the data format to "keyboard format" - a predefined data format
//
// A data format specifies which controls on a device we
// are interested in, and how they should be reported.
//
// This tells DirectInput that we will be passing an array
// of 256 bytes to IDirectInputDevice::GetDeviceState.
if ( FAILED ( hr = win32 . g_pKeyboard - > SetDataFormat ( & c_dfDIKeyboard ) ) )
return false ;
// Set the cooperativity level to let DirectInput know how
// this device should interact with the system and with other
// DirectInput applications.
hr = win32 . g_pKeyboard - > SetCooperativeLevel ( win32 . hWnd , dwCoopFlags ) ;
if ( hr = = DIERR_UNSUPPORTED & & ! bForeground & & bExclusive )
{
common - > Printf ( " keyboard: SetCooperativeLevel() returned DIERR_UNSUPPORTED. \n For security reasons, background exclusive keyboard access is not allowed. \n " ) ;
return false ;
}
if ( FAILED ( hr ) )
{
return false ;
}
if ( ! bImmediate )
{
// IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
//
// DirectInput uses unbuffered I/O (buffer size = 0) by default.
// If you want to read buffered data, you need to set a nonzero
// buffer size.
//
// Set the buffer size to DINPUT_BUFFERSIZE (defined above) elements.
//
// The buffer size is a DWORD property associated with the device.
DIPROPDWORD dipdw ;
dipdw . diph . dwSize = sizeof ( DIPROPDWORD ) ;
dipdw . diph . dwHeaderSize = sizeof ( DIPROPHEADER ) ;
dipdw . diph . dwObj = 0 ;
dipdw . diph . dwHow = DIPH_DEVICE ;
dipdw . dwData = DINPUT_BUFFERSIZE ; // Arbitary buffer size
if ( FAILED ( hr = win32 . g_pKeyboard - > SetProperty ( DIPROP_BUFFERSIZE , & dipdw . diph ) ) )
return false ;
}
// Acquire the newly created device
win32 . g_pKeyboard - > Acquire ( ) ;
common - > Printf ( " keyboard: DirectInput initialized. \n " ) ;
return true ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
IN_DeactivateKeyboard
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void IN_DeactivateKeyboard ( )
{
if ( ! win32 . g_pKeyboard )
{
2012-11-26 18:58:24 +00:00
return ;
}
win32 . g_pKeyboard - > Unacquire ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DIRECT INPUT MOUSE CONTROL
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = =
IN_InitDirectInput
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void IN_InitDirectInput ( )
{
HRESULT hr ;
2012-11-26 18:58:24 +00:00
common - > Printf ( " Initializing DirectInput... \n " ) ;
2012-11-28 15:47:07 +00:00
if ( win32 . g_pdi ! = NULL )
{
2012-11-26 18:58:24 +00:00
win32 . g_pdi - > Release ( ) ; // if the previous window was destroyed we need to do this
win32 . g_pdi = NULL ;
}
2012-11-28 15:47:07 +00:00
// Register with the DirectInput subsystem and get a pointer
// to a IDirectInput interface we can use.
// Create the base DirectInput object
if ( FAILED ( hr = DirectInput8Create ( GetModuleHandle ( NULL ) , DIRECTINPUT_VERSION , IID_IDirectInput8 , ( void * * ) & win32 . g_pdi , NULL ) ) )
{
common - > Printf ( " DirectInputCreate failed \n " ) ;
}
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
IN_InitDIMouse
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool IN_InitDIMouse ( )
{
HRESULT hr ;
if ( win32 . g_pdi = = NULL )
{
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// obtain an interface to the system mouse device.
2012-11-28 15:47:07 +00:00
hr = win32 . g_pdi - > CreateDevice ( GUID_SysMouse , & win32 . g_pMouse , NULL ) ;
if ( FAILED ( hr ) )
{
common - > Printf ( " mouse: Couldn't open DI mouse device \n " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
// Set the data format to "mouse format" - a predefined data format
//
// A data format specifies which controls on a device we
// are interested in, and how they should be reported.
//
// This tells DirectInput that we will be passing a
// DIMOUSESTATE2 structure to IDirectInputDevice::GetDeviceState.
if ( FAILED ( hr = win32 . g_pMouse - > SetDataFormat ( & c_dfDIMouse2 ) ) )
{
common - > Printf ( " mouse: Couldn't set DI mouse format \n " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the cooperativity level.
2012-11-28 15:47:07 +00:00
hr = win32 . g_pMouse - > SetCooperativeLevel ( win32 . hWnd , DISCL_EXCLUSIVE | DISCL_FOREGROUND ) ;
if ( FAILED ( hr ) )
{
common - > Printf ( " mouse: Couldn't set DI coop level \n " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
// IMPORTANT STEP TO USE BUFFERED DEVICE DATA!
//
// DirectInput uses unbuffered I/O (buffer size = 0) by default.
// If you want to read buffered data, you need to set a nonzero
// buffer size.
//
// Set the buffer size to SAMPLE_BUFFER_SIZE (defined above) elements.
//
// The buffer size is a DWORD property associated with the device.
DIPROPDWORD dipdw ;
dipdw . diph . dwSize = sizeof ( DIPROPDWORD ) ;
dipdw . diph . dwHeaderSize = sizeof ( DIPROPHEADER ) ;
dipdw . diph . dwObj = 0 ;
dipdw . diph . dwHow = DIPH_DEVICE ;
dipdw . dwData = DINPUT_BUFFERSIZE ; // Arbitary buffer size
if ( FAILED ( hr = win32 . g_pMouse - > SetProperty ( DIPROP_BUFFERSIZE , & dipdw . diph ) ) )
{
common - > Printf ( " mouse: Couldn't set DI buffersize \n " ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
IN_ActivateMouse ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear any pending samples
int mouseEvents [ MAX_MOUSE_EVENTS ] [ 2 ] ;
Sys_PollMouseInputEvents ( mouseEvents ) ;
2012-11-28 15:47:07 +00:00
common - > Printf ( " mouse: DirectInput initialized. \n " ) ;
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
IN_ActivateMouse
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void IN_ActivateMouse ( )
{
2012-11-26 18:58:24 +00:00
int i ;
HRESULT hr ;
2012-11-28 15:47:07 +00:00
if ( ! win32 . in_mouse . GetBool ( ) | | win32 . mouseGrabbed | | ! win32 . g_pMouse )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
win32 . mouseGrabbed = true ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 10 ; i + + )
{
if ( : : ShowCursor ( false ) < 0 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we may fail to reacquire if the window has been recreated
hr = win32 . g_pMouse - > Acquire ( ) ;
2012-11-28 15:47:07 +00:00
if ( FAILED ( hr ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set the cooperativity level.
2012-11-28 15:47:07 +00:00
hr = win32 . g_pMouse - > SetCooperativeLevel ( win32 . hWnd , DISCL_EXCLUSIVE | DISCL_FOREGROUND ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
IN_DeactivateMouse
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void IN_DeactivateMouse ( )
{
2012-11-26 18:58:24 +00:00
int i ;
2012-11-28 15:47:07 +00:00
if ( ! win32 . g_pMouse | | ! win32 . mouseGrabbed )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
win32 . g_pMouse - > Unacquire ( ) ;
2012-11-28 15:47:07 +00:00
for ( i = 0 ; i < 10 ; i + + )
{
if ( : : ShowCursor ( true ) > = 0 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
win32 . mouseGrabbed = false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
IN_DeactivateMouseIfWindowed
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void IN_DeactivateMouseIfWindowed ( )
{
if ( ! win32 . cdsFullscreen )
{
2012-11-26 18:58:24 +00:00
IN_DeactivateMouse ( ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
MOUSE CONTROL
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = =
Sys_ShutdownInput
= = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void Sys_ShutdownInput ( )
{
2012-11-26 18:58:24 +00:00
IN_DeactivateMouse ( ) ;
IN_DeactivateKeyboard ( ) ;
2012-11-28 15:47:07 +00:00
if ( win32 . g_pKeyboard )
{
2012-11-26 18:58:24 +00:00
win32 . g_pKeyboard - > Release ( ) ;
win32 . g_pKeyboard = NULL ;
}
2012-11-28 15:47:07 +00:00
if ( win32 . g_pMouse )
{
2012-11-26 18:58:24 +00:00
win32 . g_pMouse - > Release ( ) ;
win32 . g_pMouse = NULL ;
}
2012-11-28 15:47:07 +00:00
if ( win32 . g_pdi )
{
2012-11-26 18:58:24 +00:00
win32 . g_pdi - > Release ( ) ;
win32 . g_pdi = NULL ;
}
}
/*
= = = = = = = = = = =
Sys_InitInput
= = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void Sys_InitInput ( )
{
common - > Printf ( " \n ------- Input Initialization ------- \n " ) ;
2012-11-26 18:58:24 +00:00
IN_InitDirectInput ( ) ;
2012-11-28 15:47:07 +00:00
if ( win32 . in_mouse . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
IN_InitDIMouse ( ) ;
// don't grab the mouse on initialization
Sys_GrabMouseCursor ( false ) ;
2012-11-28 15:47:07 +00:00
}
else
{
common - > Printf ( " Mouse control not active. \n " ) ;
2012-11-26 18:58:24 +00:00
}
IN_StartupKeyboard ( ) ;
2012-11-28 15:47:07 +00:00
common - > Printf ( " ------------------------------------ \n " ) ;
2012-11-26 18:58:24 +00:00
win32 . in_mouse . ClearModified ( ) ;
}
/*
= = = = = = = = = = = = = = = = = =
IN_Frame
Called every frame , even if not generating commands
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void IN_Frame ( )
{
2012-11-26 18:58:24 +00:00
bool shouldGrab = true ;
2012-11-28 15:47:07 +00:00
if ( ! win32 . in_mouse . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
shouldGrab = false ;
}
// if fullscreen, we always want the mouse
2012-11-28 15:47:07 +00:00
if ( ! win32 . cdsFullscreen )
{
if ( win32 . mouseReleased )
{
2012-11-26 18:58:24 +00:00
shouldGrab = false ;
}
2012-11-28 15:47:07 +00:00
if ( win32 . movingWindow )
{
2012-11-26 18:58:24 +00:00
shouldGrab = false ;
}
2012-11-28 15:47:07 +00:00
if ( ! win32 . activeApp )
{
2012-11-26 18:58:24 +00:00
shouldGrab = false ;
}
}
2012-11-28 15:47:07 +00:00
if ( shouldGrab ! = win32 . mouseGrabbed )
{
if ( usercmdGen ! = NULL )
{
2012-11-26 18:58:24 +00:00
usercmdGen - > Clear ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( win32 . mouseGrabbed )
{
2012-11-26 18:58:24 +00:00
IN_DeactivateMouse ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
IN_ActivateMouse ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
#if 0 // if we can't reacquire, try reinitializing
2012-11-28 15:47:07 +00:00
if ( ! IN_InitDIMouse ( ) )
{
2012-11-26 18:58:24 +00:00
win32 . in_mouse . SetBool ( false ) ;
return ;
}
# endif
}
}
}
2012-11-28 15:47:07 +00:00
void Sys_GrabMouseCursor ( bool grabIt )
{
2012-11-26 18:58:24 +00:00
win32 . mouseReleased = ! grabIt ;
2012-11-28 15:47:07 +00:00
if ( ! grabIt )
{
2012-11-26 18:58:24 +00:00
// release it right now
IN_Frame ( ) ;
}
}
//=====================================================================================
2012-11-28 15:47:07 +00:00
static DIDEVICEOBJECTDATA polled_didod [ DINPUT_BUFFERSIZE ] ; // Receives buffered data
2012-11-26 18:58:24 +00:00
static int diFetch ;
static byte toggleFetch [ 2 ] [ 256 ] ;
# if 1
// I tried doing the full-state get to address a keyboard problem on one system,
// but it didn't make any difference
/*
= = = = = = = = = = = = = = = = = = = =
Sys_PollKeyboardInputEvents
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int Sys_PollKeyboardInputEvents ( )
{
DWORD dwElements ;
HRESULT hr ;
if ( win32 . g_pKeyboard = = NULL )
{
return 0 ;
}
dwElements = DINPUT_BUFFERSIZE ;
hr = win32 . g_pKeyboard - > GetDeviceData ( sizeof ( DIDEVICEOBJECTDATA ) ,
polled_didod , & dwElements , 0 ) ;
if ( hr ! = DI_OK )
{
// We got an error or we got DI_BUFFEROVERFLOW.
//
// Either way, it means that continuous contact with the
// device has been lost, either due to an external
// interruption, or because the buffer overflowed
// and some events were lost.
hr = win32 . g_pKeyboard - > Acquire ( ) ;
2012-11-26 18:58:24 +00:00
// nuke the garbage
2012-11-28 15:47:07 +00:00
if ( ! FAILED ( hr ) )
{
2012-11-26 18:58:24 +00:00
//Bug 951: The following command really clears the garbage input.
//The original will still process keys in the buffer and was causing
//some problems.
2012-11-28 15:47:07 +00:00
win32 . g_pKeyboard - > GetDeviceData ( sizeof ( DIDEVICEOBJECTDATA ) , NULL , & dwElements , 0 ) ;
2012-11-26 18:58:24 +00:00
dwElements = 0 ;
}
2012-11-28 15:47:07 +00:00
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( FAILED ( hr ) )
{
return 0 ;
}
2012-11-26 18:58:24 +00:00
return dwElements ;
}
# else
/*
= = = = = = = = = = = = = = = = = = = =
Sys_PollKeyboardInputEvents
Fake events by getting the entire device state
and checking transitions
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int Sys_PollKeyboardInputEvents ( )
{
HRESULT hr ;
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( win32 . g_pKeyboard = = NULL )
{
return 0 ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
hr = win32 . g_pKeyboard - > GetDeviceState ( sizeof ( toggleFetch [ diFetch ] ) , toggleFetch [ diFetch ] ) ;
2012-11-28 15:47:07 +00:00
if ( hr ! = DI_OK )
{
// We got an error or we got DI_BUFFEROVERFLOW.
//
// Either way, it means that continuous contact with the
// device has been lost, either due to an external
// interruption, or because the buffer overflowed
// and some events were lost.
hr = win32 . g_pKeyboard - > Acquire ( ) ;
2012-11-26 18:58:24 +00:00
// nuke the garbage
2012-11-28 15:47:07 +00:00
if ( ! FAILED ( hr ) )
{
2012-11-26 18:58:24 +00:00
hr = win32 . g_pKeyboard - > GetDeviceState ( sizeof ( toggleFetch [ diFetch ] ) , toggleFetch [ diFetch ] ) ;
}
2012-11-28 15:47:07 +00:00
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
}
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( FAILED ( hr ) )
{
return 0 ;
2012-11-26 18:58:24 +00:00
}
// build faked events
int numChanges = 0 ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 256 ; i + + )
{
if ( toggleFetch [ 0 ] [ i ] ! = toggleFetch [ 1 ] [ i ] )
{
2012-11-26 18:58:24 +00:00
polled_didod [ numChanges ] . dwOfs = i ;
polled_didod [ numChanges ] . dwData = toggleFetch [ diFetch ] [ i ] ? 0x80 : 0 ;
numChanges + + ;
}
}
diFetch ^ = 1 ;
return numChanges ;
}
# endif
/*
= = = = = = = = = = = = = = = = = = = =
Sys_PollKeyboardInputEvents
= = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int Sys_ReturnKeyboardInputEvent ( const int n , int & ch , bool & state )
{
2012-11-26 18:58:24 +00:00
ch = polled_didod [ n ] . dwOfs ;
state = ( polled_didod [ n ] . dwData & 0x80 ) = = 0x80 ;
2012-11-28 15:47:07 +00:00
if ( ch = = K_PRINTSCREEN | | ch = = K_LCTRL | | ch = = K_LALT | | ch = = K_RCTRL | | ch = = K_RALT )
{
2012-11-26 18:58:24 +00:00
// for windows, add a keydown event for print screen here, since
// windows doesn't send keydown events to the WndProc for this key.
// ctrl and alt are handled here to get around windows sending ctrl and
// alt messages when the right-alt is pressed on non-US 102 keyboards.
Sys_QueEvent ( SE_KEY , ch , state , 0 , NULL , 0 ) ;
}
return ch ;
}
2012-11-28 15:47:07 +00:00
void Sys_EndKeyboardInputEvents ( )
{
2012-11-26 18:58:24 +00:00
}
//=====================================================================================
2012-11-28 15:47:07 +00:00
int Sys_PollMouseInputEvents ( int mouseEvents [ MAX_MOUSE_EVENTS ] [ 2 ] )
{
2012-11-26 18:58:24 +00:00
DWORD dwElements ;
HRESULT hr ;
2012-11-28 15:47:07 +00:00
if ( ! win32 . g_pMouse | | ! win32 . mouseGrabbed )
{
2012-11-26 18:58:24 +00:00
return 0 ;
}
2012-11-28 15:47:07 +00:00
dwElements = DINPUT_BUFFERSIZE ;
hr = win32 . g_pMouse - > GetDeviceData ( sizeof ( DIDEVICEOBJECTDATA ) , polled_didod , & dwElements , 0 ) ;
if ( hr ! = DI_OK )
{
hr = win32 . g_pMouse - > Acquire ( ) ;
2012-11-26 18:58:24 +00:00
// clear the garbage
2012-11-28 15:47:07 +00:00
if ( ! FAILED ( hr ) )
{
win32 . g_pMouse - > GetDeviceData ( sizeof ( DIDEVICEOBJECTDATA ) , polled_didod , & dwElements , 0 ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
if ( FAILED ( hr ) )
{
return 0 ;
}
if ( dwElements > MAX_MOUSE_EVENTS )
{
2012-11-26 18:58:24 +00:00
dwElements = MAX_MOUSE_EVENTS ;
}
2012-11-28 15:47:07 +00:00
for ( DWORD i = 0 ; i < dwElements ; i + + )
{
2012-11-26 18:58:24 +00:00
mouseEvents [ i ] [ 0 ] = M_INVALID ;
mouseEvents [ i ] [ 1 ] = 0 ;
2012-11-28 15:47:07 +00:00
if ( polled_didod [ i ] . dwOfs > = DIMOFS_BUTTON0 & & polled_didod [ i ] . dwOfs < = DIMOFS_BUTTON7 )
{
2012-11-26 18:58:24 +00:00
const int mouseButton = ( polled_didod [ i ] . dwOfs - DIMOFS_BUTTON0 ) ;
2012-11-28 15:47:07 +00:00
const bool mouseDown = ( polled_didod [ i ] . dwData & 0x80 ) = = 0x80 ;
2012-11-26 18:58:24 +00:00
mouseEvents [ i ] [ 0 ] = M_ACTION1 + mouseButton ;
mouseEvents [ i ] [ 1 ] = mouseDown ;
Sys_QueEvent ( SE_KEY , K_MOUSE1 + mouseButton , mouseDown , 0 , NULL , 0 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-12-03 22:55:27 +00:00
// RB: replaced switch enum for MinGW
int diaction = polled_didod [ i ] . dwOfs ;
2012-12-04 11:11:14 +00:00
2012-12-03 22:55:27 +00:00
if ( diaction = = DIMOFS_X )
{
mouseEvents [ i ] [ 0 ] = M_DELTAX ;
mouseEvents [ i ] [ 1 ] = polled_didod [ i ] . dwData ;
Sys_QueEvent ( SE_MOUSE , polled_didod [ i ] . dwData , 0 , 0 , NULL , 0 ) ;
}
else if ( diaction = = DIMOFS_Y )
{
mouseEvents [ i ] [ 0 ] = M_DELTAY ;
mouseEvents [ i ] [ 1 ] = polled_didod [ i ] . dwData ;
Sys_QueEvent ( SE_MOUSE , 0 , polled_didod [ i ] . dwData , 0 , NULL , 0 ) ;
}
else if ( diaction = = DIMOFS_Z )
2012-11-28 15:47:07 +00:00
{
2012-12-03 22:55:27 +00:00
mouseEvents [ i ] [ 0 ] = M_DELTAZ ;
mouseEvents [ i ] [ 1 ] = ( int ) polled_didod [ i ] . dwData / WHEEL_DELTA ;
{
const int value = ( int ) polled_didod [ i ] . dwData / WHEEL_DELTA ;
const int key = value < 0 ? K_MWHEELDOWN : K_MWHEELUP ;
const int iterations = abs ( value ) ;
for ( int i = 0 ; i < iterations ; i + + )
2012-11-28 15:47:07 +00:00
{
2012-12-03 22:55:27 +00:00
Sys_QueEvent ( SE_KEY , key , true , 0 , NULL , 0 ) ;
Sys_QueEvent ( SE_KEY , key , false , 0 , NULL , 0 ) ;
2012-11-26 18:58:24 +00:00
}
2012-12-03 22:55:27 +00:00
}
2012-11-26 18:58:24 +00:00
}
2012-12-03 22:55:27 +00:00
// RB end
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return dwElements ;
}
//=====================================================================================
// Joystick Input Handling
//=====================================================================================
2012-11-28 15:47:07 +00:00
void Sys_SetRumble ( int device , int low , int hi )
{
2012-11-26 18:58:24 +00:00
return win32 . g_Joystick . SetRumble ( device , low , hi ) ;
}
2012-11-28 15:47:07 +00:00
int Sys_PollJoystickInputEvents ( int deviceNum )
{
2012-11-26 18:58:24 +00:00
return win32 . g_Joystick . PollInputEvents ( deviceNum ) ;
}
2012-11-28 15:47:07 +00:00
int Sys_ReturnJoystickInputEvent ( const int n , int & action , int & value )
{
2012-11-26 18:58:24 +00:00
return win32 . g_Joystick . ReturnInputEvent ( n , action , value ) ;
}
2012-11-28 15:47:07 +00:00
void Sys_EndJoystickInputEvents ( )
{
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
JoystickSamplingThread
= = = = = = = = = = = = = = = = = = = = = = = =
*/
static int threadTimeDeltas [ 256 ] ;
static int threadPacket [ 256 ] ;
static int threadCount ;
2012-11-28 15:47:07 +00:00
void JoystickSamplingThread ( void * data )
{
2012-11-26 18:58:24 +00:00
static int prevTime = 0 ;
static uint64 nextCheck [ MAX_JOYSTICKS ] = { 0 } ;
const uint64 waitTime = 5000000 ; // poll every 5 seconds to see if a controller was connected
2012-11-28 15:47:07 +00:00
while ( 1 )
{
2012-11-26 18:58:24 +00:00
// hopefully we see close to 4000 usec each loop
int now = Sys_Microseconds ( ) ;
int delta ;
2012-11-28 15:47:07 +00:00
if ( prevTime = = 0 )
{
2012-11-26 18:58:24 +00:00
delta = 4000 ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
delta = now - prevTime ;
}
prevTime = now ;
2012-11-28 15:47:07 +00:00
threadTimeDeltas [ threadCount & 255 ] = delta ;
2012-11-26 18:58:24 +00:00
threadCount + + ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
{
XINPUT_STATE joyData [ MAX_JOYSTICKS ] ;
bool validData [ MAX_JOYSTICKS ] ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_JOYSTICKS ; i + + )
{
if ( now > = nextCheck [ i ] )
{
2012-11-26 18:58:24 +00:00
// XInputGetState might block... for a _really_ long time..
validData [ i ] = XInputGetState ( i , & joyData [ i ] ) = = ERROR_SUCCESS ;
2012-11-28 15:47:07 +00:00
// allow an immediate data poll if the input device is connected else
2012-11-26 18:58:24 +00:00
// wait for some time to see if another device was reconnected.
2012-11-28 15:47:07 +00:00
// Checking input state infrequently for newly connected devices prevents
2012-11-26 18:58:24 +00:00
// severe slowdowns on PC, especially on WinXP64.
2012-11-28 15:47:07 +00:00
if ( validData [ i ] )
{
2012-11-26 18:58:24 +00:00
nextCheck [ i ] = 0 ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
nextCheck [ i ] = now + waitTime ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// do this short amount of processing inside a critical section
idScopedCriticalSection cs ( win32 . g_Joystick . mutexXis ) ;
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < MAX_JOYSTICKS ; i + + )
{
controllerState_t * cs = & win32 . g_Joystick . controllers [ i ] ;
if ( ! validData [ i ] )
{
2012-11-26 18:58:24 +00:00
cs - > valid = false ;
continue ;
}
cs - > valid = true ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
XINPUT_STATE & current = joyData [ i ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
cs - > current = current ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Switch from using cs->current to current to reduce chance of Load-Hit-Store on consoles
2012-11-28 15:47:07 +00:00
threadPacket [ threadCount & 255 ] = current . dwPacketNumber ;
2012-11-26 18:58:24 +00:00
#if 0
2012-11-28 15:47:07 +00:00
if ( xis . dwPacketNumber = = oldXis [ inputDeviceNum ] . dwPacketNumber )
{
2012-11-26 18:58:24 +00:00
return numEvents ;
}
# endif
cs - > buttonBits | = current . Gamepad . wButtons ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// we want this to be processed at least 250 times a second
WaitForSingleObject ( win32 . g_Joystick . timer , INFINITE ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : idJoystickWin32
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idJoystickWin32 : : idJoystickWin32 ( )
{
2012-11-26 18:58:24 +00:00
numEvents = 0 ;
memset ( & events , 0 , sizeof ( events ) ) ;
memset ( & controllers , 0 , sizeof ( controllers ) ) ;
memset ( buttonStates , 0 , sizeof ( buttonStates ) ) ;
memset ( joyAxis , 0 , sizeof ( joyAxis ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : Init
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idJoystickWin32 : : Init ( )
{
2012-11-26 18:58:24 +00:00
idJoystick : : Init ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// setup the timer that the high frequency thread will wait on
// to fire every 4 msec
timer = CreateWaitableTimer ( NULL , FALSE , " JoypadTimer " ) ;
LARGE_INTEGER dueTime ;
dueTime . QuadPart = - 1 ;
2012-11-28 15:47:07 +00:00
if ( ! SetWaitableTimer ( timer , & dueTime , 4 , NULL , NULL , FALSE ) )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " SetWaitableTimer for joystick failed " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// spawn the high frequency joystick reading thread
2012-11-28 15:47:07 +00:00
Sys_CreateThread ( ( xthread_t ) JoystickSamplingThread , NULL , THREAD_HIGHEST , " Joystick " , CORE_1A ) ;
2012-11-26 18:58:24 +00:00
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : SetRumble
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idJoystickWin32 : : SetRumble ( int inputDeviceNum , int rumbleLow , int rumbleHigh )
{
if ( inputDeviceNum < 0 | | inputDeviceNum > = MAX_JOYSTICKS )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
if ( ! controllers [ inputDeviceNum ] . valid )
{
2012-11-26 18:58:24 +00:00
return ;
}
XINPUT_VIBRATION vibration ;
vibration . wLeftMotorSpeed = idMath : : ClampInt ( 0 , 65535 , rumbleLow ) ;
vibration . wRightMotorSpeed = idMath : : ClampInt ( 0 , 65535 , rumbleHigh ) ;
DWORD err = XInputSetState ( inputDeviceNum , & vibration ) ;
2012-11-28 15:47:07 +00:00
if ( err ! = ERROR_SUCCESS )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " XInputSetState error: 0x%x " , err ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : PostInputEvent
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idJoystickWin32 : : PostInputEvent ( int inputDeviceNum , int event , int value , int range )
{
2012-11-26 18:58:24 +00:00
// These events are used for GUI button presses
2012-11-28 15:47:07 +00:00
if ( ( event > = J_ACTION1 ) & & ( event < = J_ACTION_MAX ) )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY1 + ( event - J_ACTION1 ) , value ! = 0 ) ;
2012-11-28 15:47:07 +00:00
}
else if ( event = = J_AXIS_LEFT_X )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_STICK1_LEFT , ( value < - range ) ) ;
PushButton ( inputDeviceNum , K_JOY_STICK1_RIGHT , ( value > range ) ) ;
2012-11-28 15:47:07 +00:00
}
else if ( event = = J_AXIS_LEFT_Y )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_STICK1_UP , ( value < - range ) ) ;
PushButton ( inputDeviceNum , K_JOY_STICK1_DOWN , ( value > range ) ) ;
2012-11-28 15:47:07 +00:00
}
else if ( event = = J_AXIS_RIGHT_X )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_STICK2_LEFT , ( value < - range ) ) ;
PushButton ( inputDeviceNum , K_JOY_STICK2_RIGHT , ( value > range ) ) ;
2012-11-28 15:47:07 +00:00
}
else if ( event = = J_AXIS_RIGHT_Y )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_STICK2_UP , ( value < - range ) ) ;
PushButton ( inputDeviceNum , K_JOY_STICK2_DOWN , ( value > range ) ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ( event > = J_DPAD_UP ) & & ( event < = J_DPAD_RIGHT ) )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_DPAD_UP + ( event - J_DPAD_UP ) , value ! = 0 ) ;
2012-11-28 15:47:07 +00:00
}
else if ( event = = J_AXIS_LEFT_TRIG )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_TRIGGER1 , ( value > range ) ) ;
2012-11-28 15:47:07 +00:00
}
else if ( event = = J_AXIS_RIGHT_TRIG )
{
2012-11-26 18:58:24 +00:00
PushButton ( inputDeviceNum , K_JOY_TRIGGER2 , ( value > range ) ) ;
}
2012-11-28 15:47:07 +00:00
if ( event > = J_AXIS_MIN & & event < = J_AXIS_MAX )
{
2012-11-26 18:58:24 +00:00
int axis = event - J_AXIS_MIN ;
int percent = ( value * 16 ) / range ;
2012-11-28 15:47:07 +00:00
if ( joyAxis [ inputDeviceNum ] [ axis ] ! = percent )
{
2012-11-26 18:58:24 +00:00
joyAxis [ inputDeviceNum ] [ axis ] = percent ;
Sys_QueEvent ( SE_JOYSTICK , axis , percent , 0 , NULL , inputDeviceNum ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// These events are used for actual game input
events [ numEvents ] . event = event ;
events [ numEvents ] . value = value ;
numEvents + + ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : PollInputEvents
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idJoystickWin32 : : PollInputEvents ( int inputDeviceNum )
{
2012-11-26 18:58:24 +00:00
numEvents = 0 ;
2012-11-28 15:47:07 +00:00
if ( ! win32 . activeApp )
{
2012-11-26 18:58:24 +00:00
return numEvents ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( inputDeviceNum < 4 ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if ( inputDeviceNum > in_joystick.GetInteger() ) {
// return numEvents;
// }
2012-11-28 15:47:07 +00:00
controllerState_t * cs = & controllers [ inputDeviceNum ] ;
2012-11-26 18:58:24 +00:00
// grab the current packet under a critical section
XINPUT_STATE xis ;
XINPUT_STATE old ;
int orBits ;
{
idScopedCriticalSection crit ( mutexXis ) ;
xis = cs - > current ;
old = cs - > previous ;
cs - > previous = xis ;
// fetch or'd button bits
orBits = cs - > buttonBits ;
cs - > buttonBits = 0 ;
}
#if 0
2012-11-28 15:47:07 +00:00
if ( XInputGetState ( inputDeviceNum , & xis ) ! = ERROR_SUCCESS )
{
2012-11-26 18:58:24 +00:00
return numEvents ;
}
# endif
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 32 ; i + + )
{
int bit = 1 < < i ;
if ( ( ( xis . Gamepad . wButtons | old . Gamepad . wButtons ) & bit ) = = 0
& & ( orBits & bit ) )
{
idLib : : Printf ( " Dropped button press on bit %i \n " , i ) ;
2012-11-26 18:58:24 +00:00
}
}
2012-11-28 15:47:07 +00:00
if ( session - > IsSystemUIShowing ( ) )
{
2012-11-26 18:58:24 +00:00
// memset xis so the current input does not get latched if the UI is showing
memset ( & xis , 0 , sizeof ( XINPUT_STATE ) ) ;
}
2012-11-28 15:47:07 +00:00
int joyRemap [ 16 ] =
{
2012-11-26 18:58:24 +00:00
J_DPAD_UP , J_DPAD_DOWN , // Up, Down
J_DPAD_LEFT , J_DPAD_RIGHT , // Left, Right
J_ACTION9 , J_ACTION10 , // Start, Back
J_ACTION7 , J_ACTION8 , // Left Stick Down, Right Stick Down
J_ACTION5 , J_ACTION6 , // Black, White (Left Shoulder, Right Shoulder)
0 , 0 , // Unused
J_ACTION1 , J_ACTION2 , // A, B
J_ACTION3 , J_ACTION4 , // X, Y
} ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Check the digital buttons
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < 16 ; i + + )
{
2012-11-26 18:58:24 +00:00
int mask = ( 1 < < i ) ;
2012-11-28 15:47:07 +00:00
if ( ( xis . Gamepad . wButtons & mask ) ! = ( old . Gamepad . wButtons & mask ) )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , joyRemap [ i ] , ( xis . Gamepad . wButtons & mask ) > 0 ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Check the triggers
2012-11-28 15:47:07 +00:00
if ( xis . Gamepad . bLeftTrigger ! = old . Gamepad . bLeftTrigger )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , J_AXIS_LEFT_TRIG , xis . Gamepad . bLeftTrigger * 128 ) ;
}
2012-11-28 15:47:07 +00:00
if ( xis . Gamepad . bRightTrigger ! = old . Gamepad . bRightTrigger )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , J_AXIS_RIGHT_TRIG , xis . Gamepad . bRightTrigger * 128 ) ;
}
2012-11-28 15:47:07 +00:00
if ( xis . Gamepad . sThumbLX ! = old . Gamepad . sThumbLX )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , J_AXIS_LEFT_X , xis . Gamepad . sThumbLX ) ;
}
2012-11-28 15:47:07 +00:00
if ( xis . Gamepad . sThumbLY ! = old . Gamepad . sThumbLY )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , J_AXIS_LEFT_Y , - xis . Gamepad . sThumbLY ) ;
}
2012-11-28 15:47:07 +00:00
if ( xis . Gamepad . sThumbRX ! = old . Gamepad . sThumbRX )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , J_AXIS_RIGHT_X , xis . Gamepad . sThumbRX ) ;
}
2012-11-28 15:47:07 +00:00
if ( xis . Gamepad . sThumbRY ! = old . Gamepad . sThumbRY )
{
2012-11-26 18:58:24 +00:00
PostInputEvent ( inputDeviceNum , J_AXIS_RIGHT_Y , - xis . Gamepad . sThumbRY ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return numEvents ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : ReturnInputEvent
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idJoystickWin32 : : ReturnInputEvent ( const int n , int & action , int & value )
{
if ( ( n < 0 ) | | ( n > = MAX_JOY_EVENT ) )
{
2012-11-26 18:58:24 +00:00
return 0 ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
action = events [ n ] . event ;
value = events [ n ] . value ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idJoystickWin32 : : PushButton
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idJoystickWin32 : : PushButton ( int inputDeviceNum , int key , bool value )
{
2012-11-26 18:58:24 +00:00
// So we don't keep sending the same SE_KEY message over and over again
2012-11-28 15:47:07 +00:00
if ( buttonStates [ inputDeviceNum ] [ key ] ! = value )
{
2012-11-26 18:58:24 +00:00
buttonStates [ inputDeviceNum ] [ key ] = value ;
Sys_QueEvent ( SE_KEY , key , value , 0 , NULL , inputDeviceNum ) ;
}
2012-12-02 21:37:32 +00:00
}