raze/source/common/console/d_event.cpp

253 lines
7.2 KiB
C++
Raw Normal View History

//-----------------------------------------------------------------------------
//
// 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 "c_console.h"
#include "d_gui.h"
#include "inputstate.h"
int eventhead;
int eventtail;
event_t events[NUM_EVENTS];
//==========================================================================
//
// 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;
for (; eventtail != eventhead ; eventtail = (eventtail+1)&(NUM_EVENTS-1))
{
ev = &events[eventtail];
if (ev->type == EV_None)
continue;
if (ev->type == EV_DeviceChange)
(void)0;//UpdateJoystickMenu(I_UpdateDeviceList());
if (C_Responder (ev))
continue; // console ate the event
#if 0
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.
//
//==========================================================================
void sendKeyForBinding(int key);
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;
#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.
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
if ((GUICapture & 8) && ev->type == EV_KeyDown)
{
// This must bypass the entire event management
sendKeyForBinding(ev->data1);
return;
}
// 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.
eventhead = (eventhead+1)&(NUM_EVENTS-1);
}
//==========================================================================
//
// 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);
for (int evnum = eventtail; evnum != eventhead; evnum = (evnum+1) & (NUM_EVENTS-1))
{
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;
}
}
}