chore: initial commit

This commit is contained in:
fallenoak 2023-01-02 13:17:18 -06:00
commit 70b00c5c38
No known key found for this signature in database
GPG key ID: 7628F8E61AEA070D
965 changed files with 264882 additions and 0 deletions

40
src/event/CEvent.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "event/CEvent.hpp"
#include "gx/Coordinate.hpp"
CCharEvent& CCharEvent::operator=(const EVENT_DATA_CHAR& data) {
this->ch = data.ch;
this->metaKeyState = data.metaKeyState;
this->repeat = data.repeat;
return *this;
}
CKeyEvent& CKeyEvent::operator=(const EVENT_DATA_KEY& data) {
this->key = data.key;
this->metaKeyState = data.metaKeyState;
this->repeat = data.repeat;
this->time = data.time;
return *this;
}
CMouseEvent& CMouseEvent::operator=(const EVENT_DATA_MOUSE& data) {
this->mode = data.mode;
this->button = data.button;
this->buttonState = data.buttonState;
this->metaKeyState = data.metaKeyState;
this->flags = data.flags;
this->time = data.time;
this->wheelDistance = data.wheelDistance;
NDCToDDC(data.x, data.y, &this->x, &this->y);
return *this;
}
CSizeEvent& CSizeEvent::operator=(const EVENT_DATA_SIZE& data) {
this->w = data.w;
this->h = data.h;
return *this;
}

39
src/event/CEvent.hpp Normal file
View file

@ -0,0 +1,39 @@
#ifndef EVENT_C_EVENT_HPP
#define EVENT_C_EVENT_HPP
#include "event/Types.hpp"
#include <cstdint>
#include <common/Ref.hpp>
class CEvent : public TRefCnt {
public:
// Member variables
uint32_t id;
void* param;
};
class CCharEvent : public CEvent, public EVENT_DATA_CHAR {
public:
// Member functions
CCharEvent& operator=(const EVENT_DATA_CHAR&);
};
class CKeyEvent : public CEvent, public EVENT_DATA_KEY {
public:
// Member functions
CKeyEvent& operator=(const EVENT_DATA_KEY&);
};
class CMouseEvent : public CEvent, public EVENT_DATA_MOUSE {
public:
// Member functions
CMouseEvent& operator=(const EVENT_DATA_MOUSE&);
};
class CSizeEvent : public CEvent, public EVENT_DATA_SIZE {
public:
// Member functions
CSizeEvent& operator=(const EVENT_DATA_SIZE&);
};
#endif

27
src/event/CMakeLists.txt Normal file
View file

@ -0,0 +1,27 @@
file(GLOB PRIVATE_SOURCES "*.cpp")
if(WHOA_SYSTEM_MAC)
file(GLOB MAC_SOURCES
"mac/*.cpp"
"mac/*.mm"
)
list(APPEND PRIVATE_SOURCES ${MAC_SOURCES})
endif()
add_library(event STATIC
${PRIVATE_SOURCES}
)
target_include_directories(event
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(event
PRIVATE
gx
PUBLIC
common
storm
tempest
)

112
src/event/Context.cpp Normal file
View file

@ -0,0 +1,112 @@
#include "event/Context.hpp"
#include "event/Event.hpp"
#include "event/EvtThread.hpp"
#include <common/Time.hpp>
#include <storm/Atomic.hpp>
HEVENTCONTEXT AttachContextToThread(EvtContext* context) {
SInterlockedIncrement(&Event::s_threadListContention);
Event::s_threadListCritsect.Enter();
// Select the thread with the highest weight total
EvtThread* thread = nullptr;
EvtThread* t = Event::s_threadList.Head();
while (t) {
if (!thread || t->m_weightTotal < thread->m_weightTotal) {
thread = t;
}
t = t->Next();
}
if (thread) {
TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Insert(context);
uint32_t v13 = OsGetAsyncTimeMs();
if (v13 != context->m_schedNextWakeTime.m_val) {
context->m_schedNextWakeTime.m_val = v13;
context->m_schedNextWakeTime.Relink();
}
Event::s_threadSlotCritsects[thread->m_threadSlot].Enter();
thread->m_contextQueue.Enqueue(context);
Event::s_threadSlotCritsects[thread->m_threadSlot].Leave();
thread->m_wakeEvent.Set();
uint32_t v14 = context->m_schedWeight + thread->m_weightTotal;
uint32_t v15 = thread->m_contextCount + 1;
thread->m_contextCount = v15;
thread->m_weightTotal = v14;
thread->m_weightAvg = v14 / v15;
} else {
// TODO
}
Event::s_threadListCritsect.Leave();
SInterlockedDecrement(&Event::s_threadListContention);
return context;
}
void DetachContextFromThread(uint32_t a1, EvtContext* a2) {
// TODO
}
EvtContext* GetNextContext(uint32_t hThread) {
EvtContext* context;
Event::s_threadSlotCritsects[hThread].Enter();
context = Event::s_threadSlots[hThread]->m_contextQueue.Dequeue();
Event::s_threadSlotCritsects[hThread].Leave();
if (hThread == Event::s_mainThread) {
Event::s_currentEvtContext = context;
}
return context;
}
void PutContext(uint32_t nextWakeTime, uint32_t newSmoothWeight, EvtContext* context, uint32_t hThread) {
if (nextWakeTime != context->m_schedNextWakeTime.m_val) {
context->m_schedNextWakeTime.m_val = nextWakeTime;
context->m_schedNextWakeTime.Relink();
}
if (context->m_schedSmoothWeight != newSmoothWeight) {
uint32_t v8 = context->m_schedWeight;
context->m_schedSmoothWeight = newSmoothWeight;
int32_t v9;
if (newSmoothWeight <= v8) {
v9 = v8 - newSmoothWeight;
} else {
v9 = newSmoothWeight - v8;
}
context->m_schedRebalance = v9 >= v8 >> 3;
}
if (!SInterlockedIncrement(&Event::s_threadListContention)) {
Event::s_threadListCritsect.Enter();
// TODO
Event::s_threadListCritsect.Leave();
}
SInterlockedDecrement(&Event::s_threadListContention);
if (hThread < Event::s_threadSlotCount) {
Event::s_threadSlotCritsects[hThread].Enter();
Event::s_threadSlots[hThread]->m_contextQueue.Enqueue(context);
Event::s_threadSlotCritsects[hThread].Leave();
}
}

17
src/event/Context.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef EVENT_CONTEXT_HPP
#define EVENT_CONTEXT_HPP
#include "event/Types.hpp"
#include <cstdint>
class EvtContext;
HEVENTCONTEXT AttachContextToThread(EvtContext* context);
void DetachContextFromThread(uint32_t a1, EvtContext* a2);
EvtContext* GetNextContext(uint32_t hThread);
void PutContext(uint32_t nextWakeTime, uint32_t newSmoothWeight, EvtContext* context, uint32_t hThread);
#endif

136
src/event/Event.cpp Normal file
View file

@ -0,0 +1,136 @@
#include "event/Event.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtThread.hpp"
#include "event/Input.hpp"
#include "event/Queue.hpp"
#include "event/Scheduler.hpp"
#include <cstring>
#include <common/Prop.hpp>
#include <common/Time.hpp>
#include <storm/String.hpp>
SEvent Event::s_startEvent = SEvent(1, 0);
SEvent Event::s_shutdownEvent = SEvent(1, 0);
int32_t Event::s_netServer;
int32_t Event::s_threadSlotCount;
SCritSect* Event::s_threadSlotCritsects;
EvtThread** Event::s_threadSlots;
uint32_t Event::s_mainThread;
TSGrowableArray<SThread*> Event::s_schedulerThreads;
ATOMIC32 Event::s_threadListContention { -1 };
SCritSect Event::s_threadListCritsect;
TSList<EvtThread, TSGetLink<EvtThread>> Event::s_threadList;
EvtContext* Event::s_currentEvtContext;
ATOMIC32 Event::s_interactiveCount;
#if defined(WHOA_SYSTEM_MAC)
bool Event::s_shouldLoopTerminate;
#endif
void OsNetPump(uint32_t timeout) {
// TODO
}
void EventInitialize(int32_t threadCount, int32_t netServer) {
IEvtInputInitialize();
int32_t v2 = threadCount;
if (threadCount < 1) {
v2 = 1;
}
IEvtSchedulerInitialize(v2, netServer);
// TODO
// OsInputSetEventPollProc(&sub_47DCA0);
}
int32_t EventIsControlKeyDown() {
return EventIsKeyDown(KEY_LCONTROL) || EventIsKeyDown(KEY_RCONTROL);
}
int32_t EventIsKeyDown(KEY key) {
// TODO
return 0;
}
int32_t EventIsShiftKeyDown() {
return EventIsKeyDown(KEY_LSHIFT) || EventIsKeyDown(KEY_RSHIFT);
}
HEVENTCONTEXT EventCreateContextEx(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags) {
return IEvtSchedulerCreateContext(interactive, initializeHandler, destroyHandler, idleTime, debugFlags);
}
void EventDoMessageLoop() {
IEvtSchedulerProcess();
}
void EventPostCloseEx(HEVENTCONTEXT contextHandle) {
if (!contextHandle) {
contextHandle = PropGet(PROP_EVENTCONTEXT);
}
if (contextHandle) {
uint32_t contextId = *reinterpret_cast<uint32_t*>(contextHandle);
int32_t findMask;
EvtContext* context = TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Ptr(
contextId,
0,
&findMask
);
if (context) {
context->m_critsect.Enter();
if (context->m_schedState == EvtContext::SCHEDSTATE_ACTIVE) {
context->m_schedState = EvtContext::SCHEDSTATE_CLOSED;
}
context->m_critsect.Leave();
if (findMask != -1) {
TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Unlock(
findMask & (INSTANCE_TABLE_SLOT_COUNT - 1),
findMask >= INSTANCE_TABLE_SLOT_COUNT
);
}
}
}
}
void EventRegister(EVENTID id, EVENTHANDLERFUNC handler) {
EventRegisterEx(id, handler, nullptr, 0.0f);
}
void EventRegisterEx(EVENTID id, EVENTHANDLERFUNC handler, void* param, float priority) {
if (id < 0 || id > EVENTIDS || handler == nullptr) {
// TODO
// SErrSetLastError(0x57u);
return;
}
HEVENTCONTEXT hContext = PropGet(PROP_EVENTCONTEXT);
uint32_t contextId = *reinterpret_cast<uint32_t*>(hContext);
int32_t findMask;
EvtContext* context = TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Ptr(
contextId,
0,
&findMask
);
if (context) {
IEvtQueueRegister(context, id, handler, param, priority);
if (findMask != -1) {
TSingletonInstanceId<EvtContext, offsetof(EvtContext, m_id)>::s_idTable.Unlock(
findMask & (INSTANCE_TABLE_SLOT_COUNT - 1),
findMask >= INSTANCE_TABLE_SLOT_COUNT
);
}
}
}

56
src/event/Event.hpp Normal file
View file

@ -0,0 +1,56 @@
#ifndef EVENT_EVENT_HPP
#define EVENT_EVENT_HPP
#include "event/CEvent.hpp"
#include "event/Types.hpp"
#include <cstdint>
#include <storm/Array.hpp>
#include <storm/Atomic.hpp>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
class EvtContext;
class EvtThread;
namespace Event {
extern SEvent s_startEvent;
extern SEvent s_shutdownEvent;
extern int32_t s_netServer;
extern int32_t s_originalThreadPriority;
extern int32_t s_threadSlotCount;
extern SCritSect* s_threadSlotCritsects;
extern EvtThread** s_threadSlots;
extern uint32_t s_mainThread;
extern TSGrowableArray<SThread*> s_schedulerThreads;
extern ATOMIC32 s_threadListContention;
extern SCritSect s_threadListCritsect;
extern TSList<EvtThread, TSGetLink<EvtThread>> s_threadList;
extern EvtContext* s_currentEvtContext;
extern ATOMIC32 s_interactiveCount;
#if defined(WHOA_SYSTEM_MAC)
extern bool s_shouldLoopTerminate;
#endif
}
HEVENTCONTEXT EventCreateContextEx(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags);
void EventDoMessageLoop();
void EventInitialize(int32_t threadCount, int32_t netServer);
int32_t EventIsControlKeyDown();
int32_t EventIsKeyDown(KEY key);
int32_t EventIsShiftKeyDown();
void EventPostCloseEx(HEVENTCONTEXT contextHandle);
void EventRegister(EVENTID id, int32_t (*handler)(const void*, void*));
void EventRegisterEx(EVENTID id, int32_t (*handler)(const void*, void*), void* param, float priority);
void OsNetPump(uint32_t timeout);
#endif

30
src/event/EvtContext.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "event/EvtContext.hpp"
#include <common/Time.hpp>
EvtContext::EvtContext(uint32_t flags, uint32_t idleTime, uint32_t schedWeight, void* callContext, int32_t startWatchdog) :
TSingletonInstanceId<EvtContext, offsetof(TInstanceId<EvtContext>, m_id)>(),
m_critsect(),
m_schedNextWakeTime(),
m_queueHandlerList(),
m_queueMessageList(),
m_queueSyncKeyDownList()
// TODO
// m_timerIdTable()
{
this->m_currTime = 0;
this->m_schedState = SCHEDSTATE_ACTIVE;
this->m_schedLastIdle = OsGetAsyncTimeMs();
this->m_schedFlags = flags;
this->m_schedIdleTime = idleTime;
this->m_schedInitialIdleTime = idleTime;
this->m_schedWeight = schedWeight;
this->m_schedSmoothWeight = schedWeight;
this->m_schedRebalance = 0;
this->m_queueSyncButtonState = 0;
this->m_propContext = PropCreateContext();
this->m_callContext = callContext;
this->m_startWatchdog = startWatchdog;
}
EvtContextQueue::EvtContextQueue() : TSPriorityQueue<EvtContext>(offsetof(EvtContext, m_schedNextWakeTime)) {
}

57
src/event/EvtContext.hpp Normal file
View file

@ -0,0 +1,57 @@
#ifndef EVENT_EVT_CONTEXT_HPP
#define EVENT_EVT_CONTEXT_HPP
#include "event/EvtHandler.hpp"
#include "event/EvtKeyDown.hpp"
#include "event/EvtMessage.hpp"
#include "event/EvtTimer.hpp"
#include "event/Types.hpp"
#include <cstdint>
#include <common/Instance.hpp>
#include <common/Prop.hpp>
#include <storm/Queue.hpp>
#include <storm/Thread.hpp>
class EvtContext : public TSingletonInstanceId<EvtContext, offsetof(TInstanceId<EvtContext>, m_id)> {
public:
// Types
enum SCHEDSTATE {
SCHEDSTATE_ACTIVE = 0x0,
SCHEDSTATE_CLOSED = 0x1,
SCHEDSTATE_DESTROYED = 0x2,
_UNIQUE_SYMBOL_SCHEDSTATE_96 = 0xFFFFFFFF,
};
// Member variables
SCritSect m_critsect;
uint32_t m_currTime;
SCHEDSTATE m_schedState;
TSTimerPriority<uint32_t> m_schedNextWakeTime;
uint32_t m_schedLastIdle;
uint32_t m_schedFlags;
uint32_t m_schedIdleTime;
uint32_t m_schedInitialIdleTime;
uint32_t m_schedWeight;
uint32_t m_schedSmoothWeight;
int32_t m_schedRebalance;
TSExplicitList<EvtHandler, offsetof(EvtHandler, link)> m_queueHandlerList[EVENTIDS];
TSExplicitList<EvtMessage, offsetof(EvtMessage, link)> m_queueMessageList;
uint32_t m_queueSyncButtonState;
TSExplicitList<EvtKeyDown, offsetof(EvtKeyDown, link)> m_queueSyncKeyDownList;
// TODO
// EvtIdTable<EvtTimer*> m_timerIdTable;
EvtTimerQueue m_timerQueue;
HPROPCONTEXT m_propContext;
void* m_callContext;
uint32_t m_startWatchdog;
// Member functions
EvtContext(uint32_t, uint32_t, uint32_t, void*, int32_t);
};
class EvtContextQueue : public TSPriorityQueue<EvtContext> {
public:
EvtContextQueue();
};
#endif

17
src/event/EvtHandler.hpp Normal file
View file

@ -0,0 +1,17 @@
#ifndef EVENT_EVT_HANDLER_HPP
#define EVENT_EVT_HANDLER_HPP
#include <cstdint>
#include <storm/List.hpp>
class EvtHandler {
public:
// Member variables
TSLink<EvtHandler> link;
int32_t (*func)(const void*, void*);
void* param;
float priority;
int32_t marker;
};
#endif

14
src/event/EvtKeyDown.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef EVENT_EVT_KEY_DOWN_HPP
#define EVENT_EVT_KEY_DOWN_HPP
#include "event/Types.hpp"
#include <storm/List.hpp>
class EvtKeyDown {
public:
// Member variables
TSLink<EvtKeyDown> link;
KEY key;
};
#endif

16
src/event/EvtMessage.hpp Normal file
View file

@ -0,0 +1,16 @@
#ifndef EVENT_EVT_MESSAGE_HPP
#define EVENT_EVT_MESSAGE_HPP
#include "event/Types.hpp"
#include <common/Instance.hpp>
#include <storm/List.hpp>
class EvtMessage : public TExtraInstanceRecyclable<EvtMessage> {
public:
// Member variables
TSLink<EvtMessage> link;
EVENTID id;
char data[4];
};
#endif

4
src/event/EvtThread.cpp Normal file
View file

@ -0,0 +1,4 @@
#include "event/EvtThread.hpp"
EvtThread::EvtThread() : TSLinkedNode<EvtThread>() {
}

25
src/event/EvtThread.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef EVENT_EVT_THREAD_HPP
#define EVENT_EVT_THREAD_HPP
#include "event/EvtContext.hpp"
#include <cstdint>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
class EvtThread : public TSLinkedNode<EvtThread> {
public:
// Member variables
uint32_t m_threadSlot;
uint32_t m_threadCount;
uint32_t m_weightTotal;
uint32_t m_weightAvg;
uint32_t m_contextCount;
uint32_t m_rebalance;
SEvent m_wakeEvent = SEvent(0, 0);
EvtContextQueue m_contextQueue;
// Member functions
EvtThread();
};
#endif

27
src/event/EvtTimer.hpp Normal file
View file

@ -0,0 +1,27 @@
#ifndef EVENT_EVT_TIMER_HPP
#define EVENT_EVT_TIMER_HPP
#include <cstdint>
#include <storm/Queue.hpp>
class EvtTimer {
public:
// Member variables
uint32_t id;
TSTimerPriority<uint32_t> targetTime;
float timeout;
int32_t (*handler)(const void*, void*);
void* param;
int32_t (*guidHandler)(const void*, uint64_t, void*);
uint64_t guidParam;
void* guidParam2;
};
class EvtTimerQueue : public TSPriorityQueue<EvtTimer> {
public:
EvtTimerQueue()
: TSPriorityQueue<EvtTimer>(offsetof(EvtTimer, targetTime))
{};
};
#endif

686
src/event/Input.cpp Normal file
View file

@ -0,0 +1,686 @@
#include "event/Input.hpp"
#include "event/EvtContext.hpp"
#include "event/Queue.hpp"
#include "gx/Window.hpp"
#include <common/Time.hpp>
#include <storm/String.hpp>
#include <storm/Unicode.hpp>
#include <tempest/Rect.hpp>
#include <tempest/Vector.hpp>
#if defined(WHOA_SYSTEM_MAC)
#include "app/mac/MacClient.h"
#endif
namespace Input {
CRect s_boundingRect;
int32_t s_queueHead;
int32_t s_queueTail;
OSEVENT s_queue[32];
MOUSEBUTTON s_buttonConversion[16] = {
MOUSE_BUTTON_NONE,
MOUSE_BUTTON_LEFT,
MOUSE_BUTTON_RIGHT,
MOUSE_BUTTON_MIDDLE,
MOUSE_BUTTON_XBUTTON1,
MOUSE_BUTTON_XBUTTON2,
MOUSE_BUTTON_XBUTTON3,
MOUSE_BUTTON_XBUTTON4,
MOUSE_BUTTON_XBUTTON5,
MOUSE_BUTTON_XBUTTON6,
MOUSE_BUTTON_XBUTTON7,
MOUSE_BUTTON_XBUTTON8,
MOUSE_BUTTON_XBUTTON9,
MOUSE_BUTTON_XBUTTON10,
MOUSE_BUTTON_XBUTTON11,
MOUSE_BUTTON_XBUTTON12,
};
}
int32_t Input::s_buttonDown[16];
uint32_t Input::s_buttonState;
C2iVector Input::s_currentMouse;
uint32_t Input::s_mouseHoldButton;
MOUSEMODE Input::s_mouseMode;
int32_t Input::s_numlockState;
int32_t Input::s_simulatedRightButtonClick;
uint32_t Input::s_metaKeyState;
#if defined(WHOA_SYSTEM_WIN)
int32_t Input::s_savedMouseSpeed;
#endif
#if defined(WHOA_SYSTEM_MAC)
double Input::s_savedMouseSpeed;
#endif
void PostChar(EvtContext* context, int32_t ch, int32_t repeat) {
EVENT_DATA_CHAR data;
data.ch = ch;
data.metaKeyState = Input::s_metaKeyState;
data.repeat = repeat;
IEvtQueueDispatch(context, EVENT_ID_CHAR, &data);
}
void PostKeyDown(EvtContext* context, int32_t key, int32_t repeat, int32_t time) {
if (key <= KEY_LASTMETAKEY) {
if ((1 << key) & Input::s_metaKeyState) {
return;
}
Input::s_metaKeyState |= 1 << key;
}
EVENT_DATA_KEY data;
data.key = static_cast<KEY>(key);
data.metaKeyState = Input::s_metaKeyState;
data.repeat = repeat;
data.time = time;
IEvtQueueDispatch(context, EVENT_ID_KEYDOWN, &data);
}
void PostKeyUp(EvtContext* context, int32_t key, int32_t repeat, int32_t time) {
if (key <= KEY_LASTMETAKEY) {
if ( !((1 << key) & Input::s_metaKeyState) ) {
return;
}
Input::s_metaKeyState &= ~(1 << key);
}
EVENT_DATA_KEY data;
data.key = static_cast<KEY>(key);
data.metaKeyState = Input::s_metaKeyState;
data.repeat = repeat;
data.time = time;
IEvtQueueDispatch(context, EVENT_ID_KEYUP, &data);
}
void PostMouseDown(EvtContext* context, MOUSEBUTTON button, int32_t x, int32_t y, int32_t time) {
Input::s_buttonState |= button;
EVENT_DATA_MOUSE data;
data.mode = Input::s_mouseMode;
data.button = button;
data.buttonState = Input::s_buttonState;
data.metaKeyState = Input::s_metaKeyState;
data.flags = GenerateMouseFlags();
data.time = time;
ConvertPosition(x, y, &data.x, &data.y);
IEvtQueueDispatch(context, EVENT_ID_MOUSEDOWN, &data);
}
void PostMouseMove(EvtContext* context, int32_t x, int32_t y, int32_t time) {
EVENT_DATA_MOUSE data;
data.mode = Input::s_mouseMode;
data.button = MOUSE_BUTTON_NONE;
data.buttonState = Input::s_buttonState;
data.metaKeyState = Input::s_metaKeyState;
data.flags = GenerateMouseFlags();
data.time = time;
ConvertPosition(x, y, &data.x, &data.y);
IEvtQueueDispatch(context, EVENT_ID_MOUSEMOVE, &data);
}
void PostMouseUp(EvtContext* context, MOUSEBUTTON button, int32_t x, int32_t y, uint32_t flags, int32_t time) {
Input::s_buttonState &= ~button;
EVENT_DATA_MOUSE data;
data.mode = Input::s_mouseMode;
data.button = button;
data.buttonState = Input::s_buttonState;
data.metaKeyState = Input::s_metaKeyState;
data.flags = flags | GenerateMouseFlags();
data.time = time;
ConvertPosition(x, y, &data.x, &data.y);
IEvtQueueDispatch(context, EVENT_ID_MOUSEUP, &data);
CheckMouseModeState();
}
void PostSize(EvtContext* context, int32_t w, int32_t h) {
EVENT_DATA_SIZE data;
data.w = w;
data.h = h;
IEvtQueueDispatch(context, EVENT_ID_SIZE, &data);
}
void ProcessInput(const int32_t param[], OSINPUT id, int32_t* shutdown, EvtContext* context) {
if (!context) {
// TODO
// nullsub_3();
// SErrSetLastError(0x57u);
}
switch (id) {
case OS_INPUT_CAPTURE_CHANGED:
// TODO
break;
case OS_INPUT_CHAR:
PostChar(
context,
param[0],
param[1]
);
break;
case OS_INPUT_STRING:
// TODO
break;
case OS_INPUT_IME:
// TODO
break;
case OS_INPUT_SIZE:
PostSize(
context,
param[0],
param[1]
);
break;
case OS_INPUT_CLOSE:
// TODO
break;
case OS_INPUT_FOCUS:
// TODO
break;
case OS_INPUT_KEY_DOWN:
PostKeyDown(
context,
param[0],
param[1],
param[3]
);
break;
case OS_INPUT_KEY_UP:
PostKeyUp(
context,
param[0],
param[1],
param[3]
);
break;
case OS_INPUT_MOUSE_DOWN:
PostMouseDown(
context,
static_cast<MOUSEBUTTON>(param[0]),
param[1],
param[2],
param[3]
);
break;
case OS_INPUT_MOUSE_MOVE:
PostMouseMove(
context,
param[1],
param[2],
param[3]
);
break;
case OS_INPUT_MOUSE_WHEEL:
// TODO
break;
case OS_INPUT_MOUSE_MOVE_RELATIVE:
// TODO
break;
case OS_INPUT_MOUSE_UP:
PostMouseUp(
context,
static_cast<MOUSEBUTTON>(param[0]),
param[1],
param[2],
0,
param[3]
);
break;
case OS_INPUT_14:
// TODO
break;
case OS_INPUT_15:
// TODO
break;
case OS_INPUT_16:
// TODO
break;
case OS_INPUT_17:
// TODO
break;
case OS_INPUT_18:
// TODO
break;
case OS_INPUT_SHUTDOWN:
// TODO
break;
}
}
void CheckMouseModeState() {
if (Input::s_mouseHoldButton) {
if (Input::s_mouseHoldButton != (Input::s_mouseHoldButton & Input::s_buttonState)) {
// TODO
// EventSetMouseMode(0, 0);
}
}
}
MOUSEBUTTON ConvertButtonNumberToMOUSEBUTTON(int32_t buttonNumber) {
return Input::s_buttonConversion[buttonNumber];
}
void ConvertPosition(int32_t clientx, int32_t clienty, float* x, float* y) {
if (Input::s_boundingRect.maxX - Input::s_boundingRect.minX != 0.0 && Input::s_boundingRect.maxY - Input::s_boundingRect.minY != 0.0) {
C2Vector pt = {
static_cast<float>(clientx),
static_cast<float>(clienty)
};
if (!Input::s_boundingRect.IsPointInside(pt)) {
// TODO
// - handle out of bounds positions
}
}
tagRECT windowDim;
OsGetDefaultWindowRect(&windowDim);
*x = static_cast<float>(clientx) / static_cast<float>(windowDim.right - windowDim.left);
*y = 1.0 - (static_cast<float>(clienty) / static_cast<float>(windowDim.bottom - windowDim.top));
}
uint32_t GenerateMouseFlags() {
uint32_t flags = 0;
if (Input::s_mouseMode == MOUSE_MODE_RELATIVE) {
flags |= 0x2;
}
return flags;
}
const char* GetButtonName(int32_t button) {
switch (button) {
case 0x1:
return "LeftButton";
case 0x2:
return "MiddleButton";
case 0x4:
return "RightButton";
case 0x8:
return "Button4";
case 0x10:
return "Button5";
case 0x20:
return "Button6";
case 0x40:
return "Button7";
case 0x80:
return "Button8";
case 0x100:
return "Button9";
case 0x200:
return "Button10";
case 0x400:
return "Button11";
case 0x800:
return "Button12";
case 0x1000:
return "Button13";
case 0x2000:
return "Button14";
case 0x4000:
return "Button15";
case 0x8000:
return "Button16";
case 0x10000:
return "Button17";
case 0x20000:
return "Button18";
case 0x40000:
return "Button19";
case 0x80000:
return "Button20";
case 0x100000:
return "Button21";
case 0x200000:
return "Button22";
case 0x400000:
return "Button23";
case 0x800000:
return "Button24";
case 0x1000000:
return "Button25";
case 0x2000000:
return "Button26";
case 0x4000000:
return "Button27";
case 0x8000000:
return "Button28";
case 0x10000000:
return "Button29";
case 0x20000000:
return "Button30";
case 0x40000000:
return "Button31";
default:
return "UNKNOWN";
}
}
void IEvtInputInitialize() {
OsInputInitialize();
}
int32_t IEvtInputProcess(EvtContext* context, int32_t* shutdown) {
if (context) {
// TODO
// nullsub_3();
int32_t v4 = 0;
OSINPUT id;
int32_t param[4];
while (OsInputGet(&id, &param[0], &param[1], &param[2], &param[3])) {
v4 = 1;
ProcessInput(param, id, shutdown, context);
}
return v4;
} else {
// TODO
// nullsub_3();
// SErrSetLastError(0x57u);
return 0;
}
}
const char* KeyCodeToString(KEY key) {
static char charBuf[8];
if (key - 33 <= 222) {
SUniSPutUTF8(key, charBuf);
return charBuf;
}
if (key <= KEY_SPACE) {
switch (key) {
case KEY_NONE:
return "NONE";
case KEY_LSHIFT:
return "LSHIFT";
case KEY_RSHIFT:
return "RSHIFT";
case KEY_LCONTROL:
return "LCTRL";
case KEY_RCONTROL:
return "RCTRL";
case KEY_LALT:
return "LALT";
case KEY_RALT:
return "RALT";
case KEY_SPACE:
return "SPACE";
default:
return "UNKNOWN";
}
}
if (key <= KEY_ESCAPE) {
switch (key) {
case KEY_NUMPAD0:
case KEY_NUMPAD1:
case KEY_NUMPAD2:
case KEY_NUMPAD3:
case KEY_NUMPAD4:
case KEY_NUMPAD5:
case KEY_NUMPAD6:
case KEY_NUMPAD7:
case KEY_NUMPAD8:
case KEY_NUMPAD9:
SStrPrintf(charBuf, sizeof(charBuf), "NUMPAD%d", key);
return charBuf;
case KEY_NUMPAD_PLUS:
return "NUMPADPLUS";
case KEY_NUMPAD_MINUS:
return "NUMPADMINUS";
case KEY_NUMPAD_MULTIPLY:
return "NUMPADMULTIPLY";
case KEY_NUMPAD_DIVIDE:
return "NUMPADDIVIDE";
case KEY_NUMPAD_DECIMAL:
return "NUMPADDECIMAL";
case KEY_ESCAPE:
return "ESCAPE";
default:
return "UNKNOWN";
}
}
if (key <= KEY_PRINTSCREEN) {
switch (key) {
case KEY_ENTER:
return "ENTER";
case KEY_BACKSPACE:
return "BACKSPACE";
case KEY_TAB:
return "TAB";
case KEY_LEFT:
return "LEFT";
case KEY_UP:
return "UP";
case KEY_RIGHT:
return "RIGHT";
case KEY_DOWN:
return "DOWN";
case KEY_INSERT:
return "INSERT";
case KEY_DELETE:
return "DELETE";
case KEY_HOME:
return "HOME";
case KEY_END:
return "END";
case KEY_PAGEUP:
return "PAGEUP";
case KEY_PAGEDOWN:
return "PAGEDOWN";
case KEY_CAPSLOCK:
return "CAPSLOCK";
case KEY_NUMLOCK:
return "NUMLOCK";
case KEY_PRINTSCREEN:
return "PRINTSCREEN";
default:
return "UNKNOWN";
}
}
if (key <= KEY_F12) {
switch (key) {
case KEY_F1:
case KEY_F2:
case KEY_F3:
case KEY_F4:
case KEY_F5:
case KEY_F6:
case KEY_F7:
case KEY_F8:
case KEY_F9:
case KEY_F10:
case KEY_F11:
case KEY_F12:
SStrPrintf(charBuf, sizeof(charBuf), "F%d", key - KEY_F1 + 1);
return charBuf;
default:
return "UNKNOWN";
}
}
if (key == KEY_NUMPAD_EQUALS) {
return "NUMPADEQUALS";
}
return "UNKNOWN";
}
int32_t OsInputGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) {
#if defined(WHOA_SYSTEM_WIN)
// TODO
#endif
#if defined(WHOA_SYSTEM_MAC)
// TODO
// Unknown logic
if (!OsInputIsUsingCocoaEventLoop()) {
// Legacy Carbon input handling
return 0;
}
// TODO
// Steelseries WoW Mouse logic
if (Input::s_queueTail == Input::s_queueHead) {
return 0;
}
OsQueueSetParam(3, OsGetAsyncTimeMs());
return OsQueueGet(id, param0, param1, param2, param3);
#endif
}
void OsInputInitialize() {
#if defined(WHOA_SYSTEM_WIN)
Input::s_numlockState = GetAsyncKeyState(144);
PVOID pvParam = 10;
SystemParametersInfoA(SPI_GETMOUSESPEED, 0, &pvParam, 0);
Input::s_savedMouseSpeed = pvParam;
#endif
#if defined(WHOA_SYSTEM_MAC)
// Legacy Carbon input handling
// if (!byte_143EFE0) {
// Carbon_OsInputRegisterHICommandHandler(0x71756974, sub_A4F230);
// }
MacClient::SetMouseCoalescingEnabled(true);
Input::s_savedMouseSpeed = MacClient::GetMouseSpeed();
#endif
}
bool OsInputIsUsingCocoaEventLoop() {
// TODO
return true;
}
void OsInputPostEvent(OSINPUT id, int32_t param0, int32_t param1, int32_t param2, int32_t param3) {
// TODO
}
int32_t OsQueueGet(OSINPUT* id, int32_t* param0, int32_t* param1, int32_t* param2, int32_t* param3) {
if (Input::s_queueTail == Input::s_queueHead) {
return 0;
}
OSEVENT event = Input::s_queue[Input::s_queueTail];
*id = event.id;
*param0 = event.param[0];
*param1 = event.param[1];
*param2 = event.param[2];
*param3 = event.param[3];
if (Input::s_queueTail == OS_QUEUE_SIZE - 1) {
Input:: s_queueTail = 0;
} else {
++Input::s_queueTail;
}
return 1;
}
void OsQueuePut(OSINPUT id, int32_t param0, int32_t param1, int32_t param2, int32_t param3) {
int32_t nextTail = 0;
int32_t nextHead = 0;
if (Input::s_queueHead != OS_QUEUE_SIZE - 1) {
nextHead = Input::s_queueHead + 1;
}
if (nextHead == Input::s_queueTail) {
if (nextHead != OS_QUEUE_SIZE - 1) {
nextTail = nextHead + 1;
}
Input::s_queueTail = nextTail;
}
OSEVENT* event = &Input::s_queue[Input::s_queueHead];
event->id = id;
event->param[0] = param0;
event->param[1] = param1;
event->param[2] = param2;
event->param[3] = param3;
Input::s_queueHead = nextHead;
}
void OsQueueSetParam(int32_t index, int32_t param) {
int32_t pos = Input::s_queueTail;
while (pos != Input::s_queueHead) {
OSEVENT* event = &Input::s_queue[pos];
event->param[index] = param;
if (pos == OS_QUEUE_SIZE - 1) {
pos = 0;
} else {
++pos;
}
}
}

62
src/event/Input.hpp Normal file
View file

@ -0,0 +1,62 @@
#ifndef EVENT_INPUT_HPP
#define EVENT_INPUT_HPP
#include "event/Types.hpp"
#include <cstdint>
#define OS_QUEUE_SIZE 32
class C2iVector;
class CRect;
class EvtContext;
namespace Input {
extern int32_t s_buttonDown[16];
extern uint32_t s_buttonState;
extern C2iVector s_currentMouse;
extern uint32_t s_mouseHoldButton;
extern MOUSEMODE s_mouseMode;
extern int32_t s_numlockState;
extern int32_t s_simulatedRightButtonClick;
extern uint32_t s_metaKeyState;
#if defined(WHOA_SYSTEM_WIN)
extern int32_t s_savedMouseSpeed;
#endif
#if defined(WHOA_SYSTEM_MAC)
extern double s_savedMouseSpeed;
#endif
}
void CheckMouseModeState(void);
MOUSEBUTTON ConvertButtonNumberToMOUSEBUTTON(int32_t);
void ConvertPosition(int32_t, int32_t, float*, float*);
uint32_t GenerateMouseFlags(void);
const char* GetButtonName(int32_t);
void IEvtInputInitialize();
int32_t IEvtInputProcess(EvtContext* context, int32_t* shutdown);
const char* KeyCodeToString(KEY);
int32_t OsInputGet(OSINPUT*, int32_t*, int32_t*, int32_t*, int32_t*);
void OsInputInitialize(void);
bool OsInputIsUsingCocoaEventLoop(void);
void OsInputPostEvent(OSINPUT, int32_t, int32_t, int32_t, int32_t);
int32_t OsQueueGet(OSINPUT*, int32_t*, int32_t*, int32_t*, int32_t*);
void OsQueuePut(OSINPUT, int32_t, int32_t, int32_t, int32_t);
void OsQueueSetParam(int32_t, int32_t);
#endif

74
src/event/Queue.cpp Normal file
View file

@ -0,0 +1,74 @@
#include "event/Queue.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtHandler.hpp"
#include <storm/Error.hpp>
void IEvtQueueDispatch(EvtContext* context, EVENTID id, const void* data) {
STORM_ASSERT(context);
// TODO
// UpdateSyncState(data, &id, context, v3);
// TODO
// if (SErrIsDisplayingError()) {
// return;
// }
auto handlerList = &context->m_queueHandlerList[id];
EvtHandler marker;
marker.marker = 1;
handlerList->LinkNode(&marker, 1, nullptr);
EvtHandler* handler;
while (1) {
handler = marker.link.Next();
if (!handler) {
break;
}
handlerList->LinkNode(&marker, 1, marker.link.Next());
if (!handler->marker && !handler->func(data, handler->param)) {
break;
}
}
handlerList->UnlinkNode(&marker);
}
void IEvtQueueDispatchAll(EvtContext* context) {
// TODO
}
void IEvtQueueRegister(EvtContext* context, EVENTID id, int32_t (*handler)(const void*, void*), void* param, float priority) {
STORM_ASSERT(context);
auto handlerList = &context->m_queueHandlerList[id];
EvtHandler* evtHandler;
void* m = SMemAlloc(sizeof(EvtHandler), __FILE__, __LINE__, 0x8);
if (m) {
evtHandler = new (m) EvtHandler();
} else {
evtHandler = nullptr;
}
evtHandler->priority = priority;
evtHandler->param = param;
evtHandler->func = handler;
evtHandler->marker = 0;
EvtHandler* h = handlerList->Head();
while (h && (priority < h->priority || h->marker)) {
h = handlerList->Link(h)->Next();
}
handlerList->LinkNode(evtHandler, 1, h);
}

14
src/event/Queue.hpp Normal file
View file

@ -0,0 +1,14 @@
#ifndef EVENT_QUEUE_HPP
#define EVENT_QUEUE_HPP
#include "event/Types.hpp"
class EvtContext;
void IEvtQueueDispatch(EvtContext* context, EVENTID id, const void* data);
void IEvtQueueDispatchAll(EvtContext* context);
void IEvtQueueRegister(EvtContext* context, EVENTID id, int32_t (*handler)(const void*, void*), void* param, float priority);
#endif

382
src/event/Scheduler.cpp Normal file
View file

@ -0,0 +1,382 @@
#include "event/Scheduler.hpp"
#include "event/Context.hpp"
#include "event/Event.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtThread.hpp"
#include "event/Input.hpp"
#include "event/Queue.hpp"
#include "event/Synthesize.hpp"
#include "event/Timer.hpp"
#include <algorithm>
#include <cstring>
#include <common/Call.hpp>
#include <common/Prop.hpp>
#include <common/Time.hpp>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
#include <storm/Thread.hpp>
#if defined(WHOA_SYSTEM_MAC)
#include "event/mac/Event.h"
#endif
void DestroySchedulerThread(uint32_t a1) {
// TODO
}
HEVENTCONTEXT IEvtSchedulerCreateContext(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags) {
if (idleTime < 1) {
idleTime = 1;
}
char contextName[256];
void* callContext = nullptr;
if (debugFlags & 0x1) {
SStrPrintf(contextName, 256, "Context: interactive = %u, idleTime = %u", interactive, idleTime);
callContext = OsCallInitializeContext(contextName);
}
void* m = SMemAlloc(sizeof(EvtContext), __FILE__, __LINE__, 0);
EvtContext* context;
if (m) {
context = new (m) EvtContext(
interactive != 0 ? 2 : 0,
idleTime,
interactive != 0 ? 1000 : 1,
callContext,
(debugFlags >> 1) & 1
);
} else {
context = nullptr;
}
if (interactive) {
SInterlockedIncrement(&Event::s_interactiveCount);
}
if (initializeHandler) {
IEvtQueueRegister(context, EVENT_ID_INITIALIZE, initializeHandler, 0, 1000.0);
}
if (destroyHandler) {
IEvtQueueRegister(context, EVENT_ID_DESTROY, destroyHandler, 0, 1000.0);
}
return AttachContextToThread(context);
}
void IEvtSchedulerInitialize(int32_t threadCount, int32_t netServer) {
if (Event::s_threadSlotCount) {
// SErrDisplayAppFatal("IEvtScheduler already initialized");
}
Event::s_netServer = netServer;
// TODO
// Thread::s_originalThreadPriority = SGetCurrentThreadPriority();
int32_t threadSlotCount = 1;
while (threadSlotCount < threadCount) {
threadSlotCount *= 2;
}
Event::s_threadSlotCount = threadSlotCount;
// Allocate SCritSects for each thread slot
int32_t v4 = sizeof(SCritSect) * threadSlotCount;
void* v5 = SMemAlloc((v4 + 4), ".\\EvtSched.cpp", 791, 0);
if (v5) {
Event::s_threadSlotCritsects = new (v5) SCritSect[threadSlotCount];
} else {
Event::s_threadSlotCritsects = nullptr;
}
// Allocate EvtThread pointers for each thread slot
Event::s_threadSlots = static_cast<EvtThread**>(SMemAlloc(sizeof(EvtThread*) * threadSlotCount, __FILE__, __LINE__, 0));
memset(Event::s_threadSlots, 0, sizeof(EvtThread*) * threadSlotCount);
Event::s_startEvent.Reset();
Event::s_shutdownEvent.Reset();
Event::s_mainThread = InitializeSchedulerThread();
for (int32_t i = 0; i < threadCount - 1; ++i) {
void* m = SMemAlloc(sizeof(SThread), __FILE__, __LINE__, 0);
SThread* thread;
if (m) {
thread = new (m) SThread();
} else {
thread = nullptr;
}
Event::s_schedulerThreads.SetCount(Event::s_schedulerThreads.Count() + 1);
Event::s_schedulerThreads[Event::s_schedulerThreads.Count() - 1] = thread;
char threadName[16];
SStrPrintf(threadName, 16, "EvtSched#%d", i);
if (!SThread::Create(&SchedulerThreadProc, 0, *thread, threadName, 0)) {
// TODO
}
}
}
void IEvtSchedulerProcess() {
#if defined(WHOA_SYSTEM_WIN)
Event::s_startEvent.Set();
SchedulerThreadProc(1);
Event::s_mainThread = 0;
#endif
#if defined(WHOA_SYSTEM_MAC)
Event::s_startEvent.Set();
if (OsInputIsUsingCocoaEventLoop()) {
PropSelectContext(0);
Event::s_startEvent.Wait(0xFFFFFFFF);
uintptr_t v0 = SGetCurrentThreadId();
char v2[64];
SStrPrintf(v2, 64, "Engine %x", v0);
OsCallInitialize(v2);
RunCocoaEventLoop();
DestroySchedulerThread(Event::s_mainThread);
OsCallDestroy();
Event::s_mainThread = 0;
} else {
// Legacy
// sub_890180(1);
// dword_141B3C8 = 0;
}
#endif
}
void IEvtSchedulerShutdown() {
// TODO
}
uint32_t InitializeSchedulerThread() {
SInterlockedIncrement(&Event::s_threadListContention);
Event::s_threadListCritsect.Enter();
uint32_t slot = Event::s_threadSlotCount;
for (int32_t i = 0; i < Event::s_threadSlotCount; ++i) {
if (slot == Event::s_threadSlotCount
|| Event::s_threadSlots[i] == nullptr
|| Event::s_threadSlots[i]->m_threadCount < Event::s_threadSlots[slot]->m_threadCount)
{
slot = i;
if (!Event::s_threadSlots[i]) {
break;
}
}
}
EvtThread* v4 = Event::s_threadSlots[slot];
if (!v4) {
v4 = Event::s_threadList.NewNode(1, 0, 0x8);
v4->m_threadCount = 0;
v4->m_weightTotal = 0;
v4->m_weightAvg = 0;
v4->m_contextCount = 0;
v4->m_rebalance = 0;
v4->m_threadSlot = slot;
Event::s_threadSlotCritsects[slot].Enter();
Event::s_threadSlots[slot] = v4;
Event::s_threadSlotCritsects[slot].Leave();
}
++v4->m_threadCount;
Event::s_threadListCritsect.Leave();
SInterlockedDecrement(&Event::s_threadListContention);
return slot;
}
bool SchedulerMainProcess() {
return SchedulerThreadProcProcess(Event::s_mainThread) != 0;
}
uint32_t SchedulerThreadProc(void* mainThread) {
uint32_t v1;
if (mainThread) {
v1 = Event::s_mainThread;
} else {
v1 = InitializeSchedulerThread();
}
PropSelectContext(0);
Event::s_startEvent.Wait(0xFFFFFFFF);
uintptr_t v2 = SGetCurrentThreadId();
char v4[64];
SStrPrintf(v4, 64, "Engine %x", v2);
OsCallInitialize(v4);
while (!SchedulerThreadProcProcess(v1));
DestroySchedulerThread(v1);
OsCallDestroy();
return 0;
}
int32_t SchedulerThreadProcProcess(uint32_t a1) {
// TODO
// if (SGetCurrentThreadPriority() != Event::s_originalThreadPriority) {
// SSetCurrentThreadPriority(Event::s_originalThreadPriority);
// }
if (!Event::s_shutdownEvent.Wait(0)) {
return 1;
}
EvtContext* context = GetNextContext(a1);
int32_t v11;
if (context) {
v11 = context->m_schedNextWakeTime.m_val - OsGetAsyncTimeMs();
if (v11 < 0) {
v11 = 0;
}
}
uint32_t v14;
if (Event::s_netServer) {
if (v11 == -1) {
v11 = 100;
}
OsNetPump(v11);
v14 = 258;
} else {
v14 = Event::s_threadSlots[a1]->m_wakeEvent.Wait(v11);
}
if (!context) {
return 0;
}
PropSelectContext(context->m_propContext);
PropSet(PROP_EVENTCONTEXT, &context->m_id);
OsCallSetContext(context->m_callContext);
uint32_t currTime = OsGetAsyncTimeMs();
uint32_t v19 = context->m_id;
if (v14 == 258) {
if (SynthesizeInitialize(context)) {
if (context->m_startWatchdog) {
// nullsub_5(20, 1);
// *a2 = 1;
}
}
uint32_t v9 = (currTime - context->m_schedLastIdle);
context->m_schedLastIdle = currTime;
double elapsedSec = v9 * 0.001;
// TODO
// FrameTime::Update(currTime, elapsedSec);
IEvtTimerDispatch(context);
if (context->m_schedFlags & 0x2) {
int32_t shutdown = 0;
IEvtInputProcess(context, &shutdown);
if (shutdown) {
context->m_critsect.Enter();
if (context->m_schedState == EvtContext::SCHEDSTATE_ACTIVE) {
context->m_schedState = EvtContext::SCHEDSTATE_CLOSED;
}
context->m_critsect.Leave();
IEvtSchedulerShutdown();
}
}
SynthesizePoll(context);
IEvtQueueDispatchAll(context);
SynthesizeIdle(context, currTime, elapsedSec);
SynthesizePaint(context);
}
if (a1 == Event::s_mainThread) {
// TODO
// dword_B417C4 = 0;
}
context->m_critsect.Enter();
uint32_t closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
DetachContextFromThread(a1, context);
SynthesizeDestroy(context);
return 0;
}
uint32_t nextDelay;
if (context->m_schedFlags & 0x4) {
nextDelay = 0;
} else {
int32_t v15 = IEvtTimerGetNextTime(context, currTime);
int32_t v16 = context->m_schedIdleTime;
nextDelay = v15;
if (v16 != context->m_schedInitialIdleTime) {
nextDelay = context->m_schedIdleTime;
}
nextDelay = std::min(
nextDelay,
std::max((uint32_t)0, v16 + context->m_schedLastIdle - currTime)
);
}
OsCallResetContext(context->m_callContext);
PropSelectContext(nullptr);
PutContext(nextDelay + currTime, context->m_schedSmoothWeight, context, a1);
return 0;
}

25
src/event/Scheduler.hpp Normal file
View file

@ -0,0 +1,25 @@
#ifndef EVENT_SCHEDULER_HPP
#define EVENT_SCHEDULER_HPP
#include "event/Types.hpp"
#include <cstdint>
void DestroySchedulerThread(uint32_t a1);
HEVENTCONTEXT IEvtSchedulerCreateContext(int32_t interactive, int32_t (*initializeHandler)(const void*, void*), int32_t (*destroyHandler)(const void*, void*), uint32_t idleTime, uint32_t debugFlags);
void IEvtSchedulerInitialize(int32_t threadCount, int32_t netServer);
void IEvtSchedulerProcess();
void IEvtSchedulerShutdown();
uint32_t InitializeSchedulerThread();
bool SchedulerMainProcess();
uint32_t SchedulerThreadProc(void* mainThread);
int32_t SchedulerThreadProcProcess(uint32_t a1);
#endif

81
src/event/Synthesize.cpp Normal file
View file

@ -0,0 +1,81 @@
#include "event/Synthesize.hpp"
#include "event/EvtContext.hpp"
#include "event/Queue.hpp"
#include <common/Time.hpp>
void SynthesizeDestroy(EvtContext* context) {
// TODO
exit(0);
}
void SynthesizeIdle(EvtContext* context, uint32_t currTime, float elapsedSec) {
bool closed;
context->m_critsect.Enter();
closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
uint32_t schedFlags = context->m_schedFlags;
if (schedFlags & 0x2) {
context->m_schedFlags = schedFlags | 0x4;
}
EVENT_DATA_IDLE data;
data.elapsedSec = elapsedSec;
data.time = currTime;
IEvtQueueDispatch(context, EVENT_ID_IDLE, &data);
}
int32_t SynthesizeInitialize(EvtContext* context) {
uint32_t schedFlags = context->m_schedFlags;
if (schedFlags & 0x1) {
return 0;
}
context->m_schedFlags = schedFlags | 0x1;
context->m_schedLastIdle = OsGetAsyncTimeMs();
IEvtQueueDispatch(context, EVENT_ID_INITIALIZE, nullptr);
return 1;
}
void SynthesizePaint(EvtContext* context) {
bool closed;
context->m_critsect.Enter();
closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
uint32_t schedFlags = context->m_schedFlags;
if (schedFlags & 0x4) {
context->m_schedFlags = schedFlags & ~0x4;
IEvtQueueDispatch(context, EVENT_ID_PAINT, nullptr);
}
}
void SynthesizePoll(EvtContext* context) {
bool closed;
context->m_critsect.Enter();
closed = context->m_schedState == EvtContext::SCHEDSTATE_CLOSED;
context->m_critsect.Leave();
if (closed) {
return;
}
IEvtQueueDispatch(context, EVENT_ID_POLL, nullptr);
}

18
src/event/Synthesize.hpp Normal file
View file

@ -0,0 +1,18 @@
#ifndef EVENT_SYNTHESIZE_HPP
#define EVENT_SYNTHESIZE_HPP
#include <cstdint>
class EvtContext;
void SynthesizeDestroy(EvtContext* context);
void SynthesizeIdle(EvtContext* context, uint32_t currTime, float elapsedSec);
int32_t SynthesizeInitialize(EvtContext* context);
void SynthesizePaint(EvtContext* context);
void SynthesizePoll(EvtContext* context);
#endif

29
src/event/Timer.cpp Normal file
View file

@ -0,0 +1,29 @@
#include "event/Timer.hpp"
#include "event/EvtContext.hpp"
#include "event/EvtTimer.hpp"
#include <storm/Error.hpp>
int32_t IEvtTimerDispatch(EvtContext* context) {
// TODO
return 0;
}
uint32_t IEvtTimerGetNextTime(EvtContext* context, uint32_t currTime) {
STORM_ASSERT(context);
context->m_critsect.Enter();
uint32_t nextTime = -1;
if (context->m_timerQueue.Count()) {
auto queue = static_cast<EvtTimer*>(context->m_timerQueue[0]);
auto targetTime = queue->targetTime.m_val;
nextTime = targetTime - currTime;
nextTime = nextTime < 0 ? 0 : nextTime;
}
context->m_critsect.Leave();
return nextTime;
}

12
src/event/Timer.hpp Normal file
View file

@ -0,0 +1,12 @@
#ifndef EVENT_TIMER_HPP
#define EVENT_TIMER_HPP
#include <cstdint>
class EvtContext;
int32_t IEvtTimerDispatch(EvtContext* context);
uint32_t IEvtTimerGetNextTime(EvtContext* context, uint32_t currTime);
#endif

252
src/event/Types.hpp Normal file
View file

@ -0,0 +1,252 @@
#ifndef EVENT_TYPES_HPP
#define EVENT_TYPES_HPP
#include <cstdint>
typedef void* HEVENTCONTEXT;
typedef int32_t (*EVENTHANDLERFUNC)(const void*, void*);
enum EVENTID {
EVENT_ID_0 = 0,
EVENT_ID_CHAR = 1,
EVENT_ID_FOCUS = 2,
EVENT_ID_3 = 3,
EVENT_ID_DESTROY = 4,
EVENT_ID_5 = 5,
EVENT_ID_IDLE = 6,
EVENT_ID_POLL = 7,
EVENT_ID_INITIALIZE = 8,
EVENT_ID_KEYDOWN = 9,
EVENT_ID_KEYUP = 10,
EVENT_ID_KEYDOWN_REPEATING = 11,
EVENT_ID_MOUSEDOWN = 12,
EVENT_ID_MOUSEMOVE = 13,
EVENT_ID_MOUSEMOVE_RELATIVE = 14,
EVENT_ID_MOUSEUP = 15,
EVENT_ID_MOUSEMODE_CHANGED = 16,
EVENT_ID_MOUSEWHEEL = 17,
EVENT_ID_18 = 18,
EVENT_ID_19 = 19,
EVENT_ID_20 = 20,
EVENT_ID_21 = 21,
EVENT_ID_22 = 22,
EVENT_ID_PAINT = 23,
EVENT_ID_24 = 24,
EVENT_ID_25 = 25,
EVENT_ID_26 = 26,
EVENT_ID_27 = 27,
EVENT_ID_28 = 28,
EVENT_ID_29 = 29,
EVENT_ID_30 = 30,
EVENT_ID_31 = 31,
EVENT_ID_32 = 32,
EVENT_ID_33 = 33,
EVENT_ID_IME = 34,
EVENT_ID_SIZE = 35,
EVENTIDS = 36
};
enum KEY {
KEY_NONE = 0xFFFFFFFF,
KEY_LSHIFT = 0x0,
KEY_RSHIFT = 0x1,
KEY_LCONTROL = 0x2,
KEY_RCONTROL = 0x3,
KEY_LALT = 0x4,
KEY_RALT = 0x5,
KEY_LASTMETAKEY = 0x5,
KEY_SPACE = 0x20,
KEY_0 = 0x30,
KEY_1 = 0x31,
KEY_2 = 0x32,
KEY_3 = 0x33,
KEY_4 = 0x34,
KEY_5 = 0x35,
KEY_6 = 0x36,
KEY_7 = 0x37,
KEY_8 = 0x38,
KEY_9 = 0x39,
KEY_A = 0x41,
KEY_B = 0x42,
KEY_C = 0x43,
KEY_D = 0x44,
KEY_E = 0x45,
KEY_F = 0x46,
KEY_G = 0x47,
KEY_H = 0x48,
KEY_I = 0x49,
KEY_J = 0x4A,
KEY_K = 0x4B,
KEY_L = 0x4C,
KEY_M = 0x4D,
KEY_N = 0x4E,
KEY_O = 0x4F,
KEY_P = 0x50,
KEY_Q = 0x51,
KEY_R = 0x52,
KEY_S = 0x53,
KEY_T = 0x54,
KEY_U = 0x55,
KEY_V = 0x56,
KEY_W = 0x57,
KEY_X = 0x58,
KEY_Y = 0x59,
KEY_Z = 0x5A,
KEY_TILDE = 0x60,
KEY_NUMPAD0 = 0x100,
KEY_NUMPAD1 = 0x101,
KEY_NUMPAD2 = 0x102,
KEY_NUMPAD3 = 0x103,
KEY_NUMPAD4 = 0x104,
KEY_NUMPAD5 = 0x105,
KEY_NUMPAD6 = 0x106,
KEY_NUMPAD7 = 0x107,
KEY_NUMPAD8 = 0x108,
KEY_NUMPAD9 = 0x109,
KEY_NUMPAD_PLUS = 0x10A,
KEY_NUMPAD_MINUS = 0x10B,
KEY_NUMPAD_MULTIPLY = 0x10C,
KEY_NUMPAD_DIVIDE = 0x10D,
KEY_NUMPAD_DECIMAL = 0x10E,
KEY_NUMPAD_EQUALS = 0x30C,
KEY_PLUS = 0x3D,
KEY_MINUS = 0x2D,
KEY_BRACKET_OPEN = 0x5B,
KEY_BRACKET_CLOSE = 0x5D,
KEY_SLASH = 0x2F,
KEY_BACKSLASH = 0x5C,
KEY_SEMICOLON = 0x3B,
KEY_APOSTROPHE = 0x27,
KEY_COMMA = 0x2C,
KEY_PERIOD = 0x2E,
KEY_ESCAPE = 0x200,
KEY_ENTER = 0x201,
KEY_BACKSPACE = 0x202,
KEY_TAB = 0x203,
KEY_LEFT = 0x204,
KEY_UP = 0x205,
KEY_RIGHT = 0x206,
KEY_DOWN = 0x207,
KEY_INSERT = 0x208,
KEY_DELETE = 0x209,
KEY_HOME = 0x20A,
KEY_END = 0x20B,
KEY_PAGEUP = 0x20C,
KEY_PAGEDOWN = 0x20D,
KEY_CAPSLOCK = 0x20E,
KEY_NUMLOCK = 0x20F,
KEY_SCROLLLOCK = 0x210,
KEY_PAUSE = 0x211,
KEY_PRINTSCREEN = 0x212,
KEY_F1 = 0x300,
KEY_F2 = 0x301,
KEY_F3 = 0x302,
KEY_F4 = 0x303,
KEY_F5 = 0x304,
KEY_F6 = 0x305,
KEY_F7 = 0x306,
KEY_F8 = 0x307,
KEY_F9 = 0x308,
KEY_F10 = 0x309,
KEY_F11 = 0x30A,
KEY_F12 = 0x30B,
KEY_F13 = 0x212,
KEY_F14 = 0x30D,
KEY_F15 = 0x30E,
KEY_F16 = 0x30F,
KEY_F17 = 0x310,
KEY_F18 = 0x311,
KEY_F19 = 0x312,
KEY_LAST = 0x313
};
enum MOUSEBUTTON {
MOUSE_BUTTON_NONE = 0x0,
MOUSE_BUTTON_LEFT = 0x1,
MOUSE_BUTTON_MIDDLE = 0x2,
MOUSE_BUTTON_RIGHT = 0x4,
MOUSE_BUTTON_XBUTTON1 = 0x8,
MOUSE_BUTTON_XBUTTON2 = 0x10,
MOUSE_BUTTON_XBUTTON3 = 0x20,
MOUSE_BUTTON_XBUTTON4 = 0x40,
MOUSE_BUTTON_XBUTTON5 = 0x80,
MOUSE_BUTTON_XBUTTON6 = 0x100,
MOUSE_BUTTON_XBUTTON7 = 0x200,
MOUSE_BUTTON_XBUTTON8 = 0x400,
MOUSE_BUTTON_XBUTTON9 = 0x800,
MOUSE_BUTTON_XBUTTON10 = 0x1000,
MOUSE_BUTTON_XBUTTON11 = 0x2000,
MOUSE_BUTTON_XBUTTON12 = 0x4000,
MOUSE_BUTTON_ALL = 0xFFFFFFFF
};
enum MOUSEMODE {
MOUSE_MODE_NORMAL = 0x0,
MOUSE_MODE_RELATIVE = 0x1,
MOUSE_MODES = 0x2
};
enum OSINPUT {
OS_INPUT_CAPTURE_CHANGED = 0,
OS_INPUT_CHAR = 1,
OS_INPUT_STRING = 2,
OS_INPUT_IME = 3,
OS_INPUT_SIZE = 4,
OS_INPUT_CLOSE = 5,
OS_INPUT_FOCUS = 6,
OS_INPUT_KEY_DOWN = 7,
OS_INPUT_KEY_UP = 8,
OS_INPUT_MOUSE_DOWN = 9,
OS_INPUT_MOUSE_MOVE = 10,
OS_INPUT_MOUSE_WHEEL = 11,
OS_INPUT_MOUSE_MOVE_RELATIVE = 12,
OS_INPUT_MOUSE_UP = 13,
OS_INPUT_14 = 14,
OS_INPUT_15 = 15,
OS_INPUT_16 = 16,
OS_INPUT_17 = 17,
OS_INPUT_18 = 18,
OS_INPUT_SHUTDOWN = 19
};
struct OSEVENT {
OSINPUT id;
int32_t param[4];
};
struct EVENT_DATA_CHAR {
int32_t ch;
uint32_t metaKeyState;
uint32_t repeat;
};
struct EVENT_DATA_IDLE {
float elapsedSec;
uint32_t time;
};
struct EVENT_DATA_KEY {
KEY key;
uint32_t metaKeyState;
uint32_t repeat;
uint32_t time;
};
struct EVENT_DATA_MOUSE {
MOUSEMODE mode;
MOUSEBUTTON button;
uint32_t buttonState;
uint32_t metaKeyState;
uint32_t flags;
float x;
float y;
int32_t wheelDistance;
uint32_t time;
};
struct EVENT_DATA_SIZE {
int32_t w;
int32_t h;
};
#endif

6
src/event/mac/Event.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef EVENT_MAC_EVENT_H
#define EVENT_MAC_EVENT_H
void RunCocoaEventLoop();
#endif

9
src/event/mac/Event.mm Normal file
View file

@ -0,0 +1,9 @@
#include "event/mac/Event.h"
#include "event/Event.hpp"
#include <AppKit/AppKit.h>
void RunCocoaEventLoop() {
if (!Event::s_shouldLoopTerminate) {
[NSApp run];
}
}