User input events first take

This commit is contained in:
ZZYZX 2017-02-03 12:28:40 +02:00
commit 9bb4cf1c03
7 changed files with 555 additions and 51 deletions

View file

@ -287,6 +287,9 @@ void D_ProcessEvents (void)
continue; // console ate the event
if (M_Responder (ev))
continue; // menu ate the event
// check events
if (E_Responder(ev)) // [ZZ] ZScript ate the event
continue;
G_Responder (ev);
}
}

View file

@ -15,13 +15,15 @@ bool E_RegisterHandler(DStaticEventHandler* handler)
return false;
if (E_CheckHandler(handler))
return false;
handler->OnRegister();
// link into normal list
// update: link at specific position based on order.
DStaticEventHandler* before = nullptr;
for (DStaticEventHandler* existinghandler = E_FirstEventHandler; existinghandler; existinghandler = existinghandler->next)
{
if (existinghandler->GetOrder() > handler->GetOrder())
if (existinghandler->Order > handler->Order)
{
before = existinghandler;
break;
@ -71,6 +73,9 @@ bool E_UnregisterHandler(DStaticEventHandler* handler)
return false;
if (!E_CheckHandler(handler))
return false;
handler->OnUnregister();
// link out of normal list
if (handler->prev)
handler->prev->next = handler->next;
@ -197,8 +202,6 @@ void E_InitStaticHandlers(bool map)
if (map) // don't initialize map handlers if restoring from savegame.
{
Printf("Initializing map handlers\n");
// delete old handlers if any.
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
{
@ -213,7 +216,6 @@ void E_InitStaticHandlers(bool map)
PClass* type = PClass::FindClass(typestring);
if (!type || E_IsStaticType(type)) // don't init the really global stuff here.
continue;
Printf("global -> %s\n", typestring.GetChars());
E_InitStaticHandler(type, typestring, false);
}
@ -221,7 +223,6 @@ void E_InitStaticHandlers(bool map)
{
FString typestring = level.info->EventHandlers[i];
PClass* type = PClass::FindClass(typestring);
Printf("level -> %s\n", typestring.GetChars());
E_InitStaticHandler(type, typestring, true);
}
}
@ -370,6 +371,45 @@ void E_PlayerDisconnected(int num)
handler->PlayerDisconnected(num);
}
bool E_Responder(event_t* ev)
{
if (ev->type == EV_GUI_Event)
{
// iterate handlers back to front by order, and give them this event.
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
{
if (handler->IsUiProcessor && handler->UiProcess(ev))
return true; // event was processed
}
}
else
{
// not sure if we want to handle device changes, but whatevs.
for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev)
{
if (!handler->IsUiProcessor && handler->InputProcess(ev))
return true; // event was processed
}
}
return false;
}
bool E_CheckUiProcessors()
{
for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next)
{
if (handler->IsUiProcessor)
{
//Printf("E_CheckUiProcessors = true\n");
return true;
}
}
//Printf("E_CheckUiProcessors = false\n");
return false;
}
// normal event loopers (non-special, argument-less)
DEFINE_EVENT_LOOPER(RenderFrame)
DEFINE_EVENT_LOOPER(WorldLightning)
@ -382,6 +422,11 @@ IMPLEMENT_CLASS(DBaseEvent, false, false)
IMPLEMENT_CLASS(DRenderEvent, false, false)
IMPLEMENT_CLASS(DWorldEvent, false, false)
IMPLEMENT_CLASS(DPlayerEvent, false, false)
IMPLEMENT_CLASS(DUiEvent, false, false)
IMPLEMENT_CLASS(DInputEvent, false, false)
DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, Order);
DEFINE_FIELD_X(StaticEventHandler, DStaticEventHandler, IsUiProcessor);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos);
DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle);
@ -403,6 +448,22 @@ DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle);
DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, PlayerNumber);
DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, IsReturn);
DEFINE_FIELD_X(UiEvent, DUiEvent, Type);
DEFINE_FIELD_X(UiEvent, DUiEvent, KeyString);
DEFINE_FIELD_X(UiEvent, DUiEvent, KeyChar);
DEFINE_FIELD_X(UiEvent, DUiEvent, MouseX);
DEFINE_FIELD_X(UiEvent, DUiEvent, MouseY);
DEFINE_FIELD_X(UiEvent, DUiEvent, IsShift);
DEFINE_FIELD_X(UiEvent, DUiEvent, IsAlt);
DEFINE_FIELD_X(UiEvent, DUiEvent, IsCtrl);
DEFINE_FIELD_X(InputEvent, DInputEvent, Type);
DEFINE_FIELD_X(InputEvent, DInputEvent, KeyScan);
DEFINE_FIELD_X(InputEvent, DInputEvent, KeyString);
DEFINE_FIELD_X(InputEvent, DInputEvent, KeyChar);
DEFINE_FIELD_X(InputEvent, DInputEvent, MouseX);
DEFINE_FIELD_X(InputEvent, DInputEvent, MouseY);
DEFINE_ACTION_FUNCTION(DEventHandler, Create)
{
PARAM_PROLOGUE;
@ -515,6 +576,9 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, Unregister)
return 0; \
}
DEFINE_EMPTY_HANDLER(DStaticEventHandler, OnRegister)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, OnUnregister)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLoaded)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldUnloaded)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingSpawned)
@ -532,11 +596,8 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerRespawned)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDied)
DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDisconnected)
DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder)
{
PARAM_SELF_PROLOGUE(DStaticEventHandler);
ACTION_RETURN_INT(0);
}
DEFINE_EMPTY_HANDLER(DStaticEventHandler, UiProcess);
DEFINE_EMPTY_HANDLER(DStaticEventHandler, InputProcess);
// ===========================================
//
@ -544,6 +605,30 @@ DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder)
//
// ===========================================
void DStaticEventHandler::OnRegister()
{
IFVIRTUAL(DStaticEventHandler, OnRegister)
{
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_OnRegister_VMPtr)
return;
VMValue params[1] = { (DStaticEventHandler*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
}
void DStaticEventHandler::OnUnregister()
{
IFVIRTUAL(DStaticEventHandler, OnUnregister)
{
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_OnUnregister_VMPtr)
return;
VMValue params[1] = { (DStaticEventHandler*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
}
static DWorldEvent* E_SetupWorldEvent()
{
static DWorldEvent* e = nullptr;
@ -780,28 +865,125 @@ void DStaticEventHandler::PlayerDisconnected(int num)
}
}
static DUiEvent* E_SetupUiEvent()
{
static DUiEvent* e = nullptr;
if (!e) e = (DUiEvent*)RUNTIME_CLASS(DUiEvent)->CreateNew();
e->Type = EV_GUI_None;
e->IsShift = false;
e->IsAlt = false;
e->IsCtrl = false;
e->MouseX = e->MouseY = 0;
e->KeyChar = 0;
e->KeyString = "";
return e;
}
bool DStaticEventHandler::UiProcess(event_t* ev)
{
IFVIRTUAL(DStaticEventHandler, UiProcess)
{
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_UiProcess_VMPtr)
return false;
DUiEvent* e = E_SetupUiEvent();
//
e->Type = (EGUIEvent)ev->subtype;
// we don't want the modders to remember what weird fields mean what for what events.
switch (e->Type)
{
case EV_GUI_None:
break;
case EV_GUI_KeyDown:
case EV_GUI_KeyRepeat:
case EV_GUI_KeyUp:
e->KeyChar = ev->data1;
e->KeyString.Format("%c", e->KeyChar);
e->IsShift = !!(ev->data3 & GKM_SHIFT);
e->IsAlt = !!(ev->data3 & GKM_ALT);
e->IsCtrl = !!(ev->data3 & GKM_CTRL);
break;
case EV_GUI_Char:
e->KeyChar = ev->data1;
e->KeyString.Format("%c", e->KeyChar);
e->IsAlt = !!ev->data2; // only true for Win32, not sure about SDL
break;
default: // mouse event
// note: SDL input doesn't seem to provide these at all
e->MouseX = ev->x;
e->MouseY = ev->y;
e->IsShift = !!(ev->data3 & GKM_SHIFT);
e->IsAlt = !!(ev->data3 & GKM_ALT);
e->IsCtrl = !!(ev->data3 & GKM_CTRL);
break;
}
int processed;
VMReturn results[1] = { &processed };
VMValue params[2] = { (DStaticEventHandler*)this, e };
GlobalVMStack.Call(func, params, 2, results, 1, nullptr);
return !!processed;
}
return false;
}
static DInputEvent* E_SetupInputEvent()
{
static DInputEvent* e = nullptr;
if (!e) e = (DInputEvent*)RUNTIME_CLASS(DInputEvent)->CreateNew();
e->Type = EV_None;
e->KeyScan = 0;
e->KeyChar = 0;
e->KeyString = "";
e->MouseX = e->MouseY = 0;
return e;
}
bool DStaticEventHandler::InputProcess(event_t* ev)
{
IFVIRTUAL(DStaticEventHandler, InputProcess)
{
// don't create excessive DObjects if not going to be processed anyway
if (func == DStaticEventHandler_InputProcess_VMPtr)
return false;
DInputEvent* e = E_SetupInputEvent();
//
e->Type = (EGenericEvent)ev->type;
// we don't want the modders to remember what weird fields mean what for what events.
switch (e->Type)
{
case EV_None:
break;
case EV_KeyDown:
case EV_KeyUp:
e->KeyScan = ev->data1;
e->KeyChar = ev->data2;
e->KeyString.Format("%c", e->KeyChar);
break;
case EV_Mouse:
e->MouseX = ev->x;
e->MouseY = ev->y;
break;
default:
break; // EV_DeviceChange = wat?
}
int processed;
VMReturn results[1] = { &processed };
VMValue params[2] = { (DStaticEventHandler*)this, e };
GlobalVMStack.Call(func, params, 2, results, 1, nullptr);
return !!processed;
}
return false;
}
//
void DStaticEventHandler::OnDestroy()
{
E_UnregisterHandler(this);
Super::OnDestroy();
}
//
int DStaticEventHandler::GetOrder()
{
// if we have cached order, return it.
// otherwise call VM.
if (haveorder)
return order;
IFVIRTUAL(DStaticEventHandler, GetOrder)
{
VMReturn results[1] = { &order };
VMValue params[1] = { (DStaticEventHandler*)this };
GlobalVMStack.Call(func, params, 1, results, 1, nullptr);
haveorder = true;
}
return order;
}

View file

@ -3,6 +3,8 @@
#include "dobject.h"
#include "serializer.h"
#include "d_event.h"
#include "d_gui.h"
class DStaticEventHandler;
@ -49,6 +51,11 @@ void E_PlayerRespawned(int num);
void E_PlayerDied(int num);
// this executes when a player leaves the game
void E_PlayerDisconnected(int num);
// this executes on events.
bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess
// check if there is anything that should receive GUI events
bool E_CheckUiProcessors();
// serialization stuff
void E_SerializeEvents(FSerializer& arc);
@ -67,17 +74,17 @@ public:
{
prev = 0;
next = 0;
order = 0;
haveorder = false;
Order = 0;
IsUiProcessor = false;
}
DStaticEventHandler* prev;
DStaticEventHandler* next;
virtual bool IsStatic() { return true; }
// order is cached to avoid calling the VM for sorting too much
int order;
bool haveorder;
//
int Order;
bool IsUiProcessor;
// serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields
void Serialize(FSerializer& arc) override
@ -91,34 +98,42 @@ public:
{
Printf("DStaticEventHandler::Serialize: store object %s\n", GetClass()->TypeName.GetChars());
}
/* do nothing */
arc("Order", Order);
arc("IsUiProcessor", IsUiProcessor);
}
// destroy handler. this unlinks EventHandler from the list automatically.
void OnDestroy() override;
//
virtual void WorldLoaded();
virtual void WorldUnloaded();
virtual void WorldThingSpawned(AActor*);
virtual void WorldThingDied(AActor*, AActor*);
virtual void WorldThingRevived(AActor*);
virtual void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle);
virtual void WorldThingDestroyed(AActor*);
virtual void WorldLightning();
virtual void WorldTick();
void OnRegister(); // you can set order and IsUi here.
void OnUnregister();
//
virtual void RenderFrame();
void WorldLoaded();
void WorldUnloaded();
void WorldThingSpawned(AActor*);
void WorldThingDied(AActor*, AActor*);
void WorldThingRevived(AActor*);
void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle);
void WorldThingDestroyed(AActor*);
void WorldLightning();
void WorldTick();
//
virtual void PlayerEntered(int num, bool fromhub);
virtual void PlayerRespawned(int num);
virtual void PlayerDied(int num);
virtual void PlayerDisconnected(int num);
void RenderFrame();
// gets the order of this item.
int GetOrder();
//
void PlayerEntered(int num, bool fromhub);
void PlayerRespawned(int num);
void PlayerDied(int num);
void PlayerDisconnected(int num);
//
// return true if handled.
virtual bool InputProcess(event_t* ev);
virtual bool UiProcess(event_t* ev);
};
class DEventHandler : public DStaticEventHandler
{
@ -213,4 +228,47 @@ public:
}
};
class DUiEvent : public DBaseEvent
{
DECLARE_CLASS(DUiEvent, DBaseEvent)
public:
// this essentially translates event_t UI events to ZScript.
EGUIEvent Type;
// for keys/chars/whatever
FString KeyString;
int KeyChar;
// for mouse
int MouseX;
int MouseY;
// global (?)
bool IsShift;
bool IsCtrl;
bool IsAlt;
DUiEvent()
{
Type = EV_GUI_None;
}
};
class DInputEvent : public DBaseEvent
{
DECLARE_CLASS(DInputEvent, DBaseEvent)
public:
// this translates regular event_t events to ZScript (not UI, UI events are sent via DUiEvent and only if requested!)
EGenericEvent Type;
// for keys
int KeyScan;
FString KeyString;
int KeyChar;
// for mouse
int MouseX;
int MouseY;
DInputEvent()
{
Type = EV_None;
}
};
#endif

View file

@ -47,6 +47,7 @@
#include "doomdef.h"
#include "doomstat.h"
#include "v_video.h"
#include "events.h"
#undef Class
@ -94,6 +95,10 @@ void CheckGUICapture()
? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon)
: (MENU_On == menuactive || MENU_OnNoPause == menuactive);
// [ZZ] check active event handlers that want the UI processing
if (!wantCapture && E_CheckUiProcessors())
wantCapture = true;
if (wantCapture != GUICapture)
{
GUICapture = wantCapture;

View file

@ -17,6 +17,7 @@
#include "dikeys.h"
#include "templates.h"
#include "s_sound.h"
#include "events.h"
static void I_CheckGUICapture ();
static void I_CheckNativeMouse ();
@ -154,6 +155,10 @@ static void I_CheckGUICapture ()
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
}
// [ZZ] check active event handlers that want the UI processing
if (!wantCapt && E_CheckUiProcessors())
wantCapt = true;
if (wantCapt != GUICapture)
{
GUICapture = wantCapt;

View file

@ -101,6 +101,7 @@
#include "d_event.h"
#include "v_text.h"
#include "version.h"
#include "events.h"
// Prototypes and declarations.
#include "rawinput.h"
@ -187,6 +188,10 @@ static void I_CheckGUICapture ()
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
}
// [ZZ] check active event handlers that want the UI processing
if (!wantCapt && E_CheckUiProcessors())
wantCapt = true;
if (wantCapt != GUICapture)
{
GUICapture = wantCapt;