2019-11-03 17:19:29 +00:00
//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
//
// 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, see http://www.gnu.org/licenses/
//
//
//-----------------------------------------------------------------------------
# include "c_bind.h"
# include "d_event.h"
# include "d_gui.h"
2019-11-03 23:55:49 +00:00
# include "inputstate.h"
2019-11-03 17:19:29 +00:00
int eventhead ;
int eventtail ;
2019-11-03 23:53:55 +00:00
event_t events [ NUM_EVENTS ] ;
2019-11-03 17:19:29 +00:00
//==========================================================================
//
// G_Responder
// Process the event for the game
//
//==========================================================================
bool G_Responder ( event_t * ev )
{
#if 0
// any other key pops up menu if in demos
// [RH] But only if the key isn't bound to a "special" command
if ( gameaction = = ga_nothing & &
( demoplayback | | gamestate = = GS_DEMOSCREEN | | gamestate = = GS_TITLELEVEL ) )
{
const char * cmd = Bindings . GetBind ( ev - > data1 ) ;
if ( ev - > type = = EV_KeyDown )
{
if ( ! cmd | | (
strnicmp ( cmd , " menu_ " , 5 ) & &
stricmp ( cmd , " toggleconsole " ) & &
stricmp ( cmd , " sizeup " ) & &
stricmp ( cmd , " sizedown " ) & &
stricmp ( cmd , " togglemap " ) & &
stricmp ( cmd , " spynext " ) & &
stricmp ( cmd , " spyprev " ) & &
stricmp ( cmd , " chase " ) & &
stricmp ( cmd , " +showscores " ) & &
stricmp ( cmd , " bumpgamma " ) & &
stricmp ( cmd , " screenshot " ) ) )
{
M_StartControlPanel ( true ) ;
M_SetMenu ( NAME_Mainmenu , - 1 ) ;
return true ;
}
else
{
return C_DoKey ( ev , & Bindings , & DoubleBindings ) ;
}
}
if ( cmd & & cmd [ 0 ] = = ' + ' )
return C_DoKey ( ev , & Bindings , & DoubleBindings ) ;
return false ;
}
# endif
#if 0
if ( gamestate = = GS_LEVEL )
{
if ( ST_Responder ( ev ) )
return true ; // status window ate it
if ( ! viewactive & & primaryLevel - > automap - > Responder ( ev , false ) )
return true ; // automap ate it
}
else if ( gamestate = = GS_FINALE )
{
if ( F_Responder ( ev ) )
return true ; // finale ate the event
}
# endif
switch ( ev - > type )
{
case EV_KeyDown :
if ( C_DoKey ( ev , & Bindings , & DoubleBindings ) )
return true ;
break ;
case EV_KeyUp :
C_DoKey ( ev , & Bindings , & DoubleBindings ) ;
break ;
#if 0
// [RH] mouse buttons are sent as key up/down events
case EV_Mouse :
mousex = ( int ) ( ev - > x * mouse_sensitivity ) ;
mousey = ( int ) ( ev - > y * mouse_sensitivity ) ;
break ;
# endif
}
// [RH] If the view is active, give the automap a chance at
// the events *last* so that any bound keys get precedence.
#if 0
if ( gamestate = = GS_LEVEL & & viewactive & & primaryLevel - > automap )
return primaryLevel - > automap - > Responder ( ev , true ) ;
# endif
return ( ev - > type = = EV_KeyDown | |
ev - > type = = EV_Mouse ) ;
}
//==========================================================================
//
// D_ProcessEvents
//
// Send all the events of the given timestamp down the responder chain.
// Events are asynchronous inputs generally generated by the game user.
// Events can be discarded if no responder claims them
//
//==========================================================================
void D_ProcessEvents ( void )
{
event_t * ev ;
2019-11-03 23:53:55 +00:00
for ( ; eventtail ! = eventhead ; eventtail = ( eventtail + 1 ) & ( NUM_EVENTS - 1 ) )
2019-11-03 17:19:29 +00:00
{
ev = & events [ eventtail ] ;
if ( ev - > type = = EV_None )
continue ;
if ( ev - > type = = EV_DeviceChange )
( void ) 0 ; //UpdateJoystickMenu(I_UpdateDeviceList());
#if 0
if ( C_Responder ( ev ) )
continue ; // console ate the event
if ( M_Responder ( ev ) )
continue ; // menu ate the event
# endif
G_Responder ( ev ) ;
}
}
//==========================================================================
//
// D_PostEvent
//
// Called by the I/O functions when input is detected.
//
//==========================================================================
2019-11-09 21:22:51 +00:00
void sendKeyForBinding ( int key ) ;
2019-11-03 17:19:29 +00:00
void D_PostEvent ( const event_t * ev )
{
// Do not post duplicate consecutive EV_DeviceChange events.
if ( ev - > type = = EV_DeviceChange & & events [ eventhead ] . type = = EV_DeviceChange )
{
return ;
}
events [ eventhead ] = * ev ;
2019-11-04 00:01:54 +00:00
#if 0 // No idea if this can be made to work ever... For now, pass on the mouse movement event so that the input code can deal with them itself.
2019-11-03 17:19:29 +00:00
if ( ev - > type = = EV_Mouse & & menuactive = = MENU_Off & & ConsoleState ! = c_down & & ConsoleState ! = c_falling & & ! primaryLevel - > localEventManager - > Responder ( ev ) & & ! paused )
{
if ( Button_Mlook . bDown | | freelook )
{
int look = int ( ev - > y * m_pitch * mouse_sensitivity * 16.0 ) ;
if ( invertmouse )
look = - look ;
G_AddViewPitch ( look , true ) ;
events [ eventhead ] . y = 0 ;
}
if ( ! Button_Strafe . bDown & & ! lookstrafe )
{
G_AddViewAngle ( int ( ev - > x * m_yaw * mouse_sensitivity * 8.0 ) , true ) ;
events [ eventhead ] . x = 0 ;
}
if ( ( events [ eventhead ] . x | events [ eventhead ] . y ) = = 0 )
{
return ;
}
}
# endif
2019-11-09 21:22:51 +00:00
if ( ( GUICapture & 8 ) & & ev - > type = = EV_KeyDown )
{
// This must bypass the entire event management
sendKeyForBinding ( ev - > data1 ) ;
return ;
}
2019-11-03 23:55:49 +00:00
// Add the key to the global keyboard state.
// This is probably the biggest roadblock with the input system as it undermines a proper event driven approach.
// Too much code depends on just checking this instead of waiting for events to happen.
// Here's also definitely not the best place to maintain the keyboard state but right now it's unavoidable to do this outside the event processing because so much code depends on it.
// Once all those busy waiting loops can poll the event queue for a proper skip event, this will mostly go away.
inputState . AddEvent ( ev ) ;
// Also add it to the event queue - this is where everything should transition to eventually.
2019-11-03 23:53:55 +00:00
eventhead = ( eventhead + 1 ) & ( NUM_EVENTS - 1 ) ;
2019-11-03 17:19:29 +00:00
}
//==========================================================================
//
// D_RemoveNextCharEvent
//
// Removes the next EV_GUI_Char event in the input queue. Used by the menu,
// since it (generally) consumes EV_GUI_KeyDown events and not EV_GUI_Char
// events, and it needs to ensure that there is no left over input when it's
// done. If there are multiple EV_GUI_KeyDowns before the EV_GUI_Char, then
// there are dead chars involved, so those should be removed, too. We do
// this by changing the message type to EV_None rather than by actually
// removing the event from the queue.
//
//==========================================================================
void D_RemoveNextCharEvent ( )
{
assert ( events [ eventtail ] . type = = EV_GUI_Event & & events [ eventtail ] . subtype = = EV_GUI_KeyDown ) ;
2019-11-03 23:53:55 +00:00
for ( int evnum = eventtail ; evnum ! = eventhead ; evnum = ( evnum + 1 ) & ( NUM_EVENTS - 1 ) )
2019-11-03 17:19:29 +00:00
{
event_t * ev = & events [ evnum ] ;
if ( ev - > type ! = EV_GUI_Event )
break ;
if ( ev - > subtype = = EV_GUI_KeyDown | | ev - > subtype = = EV_GUI_Char )
{
ev - > type = EV_None ;
if ( ev - > subtype = = EV_GUI_Char )
break ;
}
else
{
break ;
}
}
}
2019-11-03 23:55:49 +00:00