raze/source/common/console/d_event.cpp
Christoph Oelckers 52cfb7fb92 - completely disconnected the old menu from the rest of the game to allow rebuilding the new one.
Sadly this uncovered a few more places where script events are allowed too broad access to the game state.
2019-11-23 23:05:24 +01:00

240 lines
6.7 KiB
C++

//-----------------------------------------------------------------------------
//
// 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"
#include "menu.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 (M_Responder (ev))
continue; // menu ate the event
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;
}
if (ev->type == EV_Mouse && GUICapture == 0 && appactive && g_mouseGrabbed)
{
inputState.MouseAddToPos(ev->x / 3, -ev->y / 2);
return;
}
else if (ev->type == EV_GUI_Event && ev->subtype == EV_GUI_MouseMove && appactive && GUICapture == 0 && !g_mouseGrabbed)
{
inputState.MouseSetAbs(ev->data1, ev->data2);
return;
}
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.
inputState.AddEvent(ev);
// Also add it to the event queue.
events[eventhead] = *ev;
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;
}
}
}