isle-portable/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp
Misha d9c4151bb8
implement LegoInputManager::ProcessOneEvent (#498)
* push changes

* fix

* Match

* Rename functions

* Space

* Fix GetPresenterAt

---------

Co-authored-by: Christian Semmler <mail@csemmler.com>
2024-01-28 15:20:21 +01:00

429 lines
9.8 KiB
C++

#include "legoinputmanager.h"
#include "legocontrolmanager.h"
#include "legoomni.h"
#include "legovideomanager.h"
#include "mxautolocker.h"
#include "roi/legoroi.h"
DECOMP_SIZE_ASSERT(LegoInputManager, 0x338)
DECOMP_SIZE_ASSERT(LegoNotifyList, 0x18)
DECOMP_SIZE_ASSERT(LegoNotifyListCursor, 0x10)
DECOMP_SIZE_ASSERT(LegoEventQueue, 0x18)
// GLOBAL: LEGO1 0x100f31b0
MxS32 g_unk0x100f31b0 = -1;
// GLOBAL: LEGO1 0x100f31b4
MxS32 g_unk0x100f31b4 = 0;
// FUNCTION: LEGO1 0x1005b790
LegoInputManager::LegoInputManager()
{
m_keyboardNotifyList = NULL;
m_world = NULL;
m_camera = NULL;
m_eventQueue = NULL;
m_unk0x80 = 0;
m_autoDragTimerID = 0;
m_unk0x6c = 0;
m_unk0x70 = 0;
m_controlManager = NULL;
m_unk0x81 = 0;
m_unk0x88 = FALSE;
m_directInput = NULL;
m_directInputDevice = NULL;
m_unk0x94 = 0;
m_unk0x195 = 0;
m_joyid = -1;
m_joystickIndex = -1;
m_useJoystick = FALSE;
m_unk0x335 = FALSE;
m_unk0x336 = FALSE;
m_unk0x74 = 0x19;
m_autoDragTime = 1000;
}
// FUNCTION: LEGO1 0x1005b8b0
MxResult LegoInputManager::Tickle()
{
ProcessEvents();
return SUCCESS;
}
// FUNCTION: LEGO1 0x1005b8f0
LegoInputManager::~LegoInputManager()
{
Destroy();
}
// FUNCTION: LEGO1 0x1005b960
MxResult LegoInputManager::Create(HWND p_hwnd)
{
MxResult result = SUCCESS;
m_controlManager = new LegoControlManager;
if (!m_keyboardNotifyList)
m_keyboardNotifyList = new LegoNotifyList;
if (!m_eventQueue)
m_eventQueue = new LegoEventQueue;
CreateAndAcquireKeyboard(p_hwnd);
GetJoystickId();
if (!m_keyboardNotifyList || !m_eventQueue || !m_directInputDevice) {
Destroy();
result = FAILURE;
}
return result;
}
// FUNCTION: LEGO1 0x1005bfe0
void LegoInputManager::Destroy()
{
ReleaseDX();
if (m_keyboardNotifyList)
delete m_keyboardNotifyList;
m_keyboardNotifyList = NULL;
if (m_eventQueue)
delete m_eventQueue;
m_eventQueue = NULL;
if (m_controlManager)
delete m_controlManager;
}
// FUNCTION: LEGO1 0x1005c030
void LegoInputManager::CreateAndAcquireKeyboard(HWND p_hwnd)
{
HINSTANCE hinstance = (HINSTANCE) GetWindowLong(p_hwnd, GWL_HINSTANCE);
HRESULT hresult = DirectInputCreate(hinstance, 0x500, &m_directInput, NULL); // 0x500 for DX5
if (hresult == DI_OK) {
HRESULT createdeviceresult = m_directInput->CreateDevice(GUID_SysKeyboard, &m_directInputDevice, NULL);
if (createdeviceresult == DI_OK) {
m_directInputDevice->SetCooperativeLevel(p_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND);
m_directInputDevice->SetDataFormat(&c_dfDIKeyboard);
m_directInputDevice->Acquire();
}
}
}
// FUNCTION: LEGO1 0x1005c0a0
void LegoInputManager::ReleaseDX()
{
if (m_directInputDevice != NULL) {
m_directInputDevice->Unacquire();
m_directInputDevice->Release();
m_directInputDevice = NULL;
}
if (m_directInput != NULL) {
m_directInput->Release();
m_directInput = NULL;
}
}
// FUNCTION: LEGO1 0x1005c240
MxResult LegoInputManager::GetJoystickId()
{
JOYINFOEX joyinfoex;
if (m_useJoystick != FALSE) {
MxS32 joyid = m_joystickIndex;
if (joyid >= 0) {
joyinfoex.dwSize = 0x34;
joyinfoex.dwFlags = 0xFF;
if (joyGetPosEx(joyid, &joyinfoex) == JOYERR_NOERROR &&
joyGetDevCaps(joyid, &m_joyCaps, 0x194) == JOYERR_NOERROR) {
m_joyid = joyid;
return SUCCESS;
}
}
for (joyid = JOYSTICKID1; joyid < 16; joyid++) {
joyinfoex.dwSize = 0x34;
joyinfoex.dwFlags = 0xFF;
if (joyGetPosEx(joyid, &joyinfoex) == JOYERR_NOERROR &&
joyGetDevCaps(joyid, &m_joyCaps, 0x194) == JOYERR_NOERROR) {
m_joyid = joyid;
return SUCCESS;
}
}
}
return FAILURE;
}
// FUNCTION: LEGO1 0x1005c320
MxResult LegoInputManager::GetJoystickState(
MxU32* p_joystickX,
MxU32* p_joystickY,
DWORD* p_buttonsState,
MxU32* p_povPosition
)
{
if (m_useJoystick != FALSE) {
if (m_joyid < 0 && GetJoystickId() == -1) {
m_useJoystick = FALSE;
return FAILURE;
}
JOYINFOEX joyinfoex;
joyinfoex.dwSize = 0x34;
joyinfoex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNBUTTONS;
MxU32 capabilities = m_joyCaps.wCaps;
if ((capabilities & JOYCAPS_HASPOV) != 0) {
joyinfoex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNPOV | JOY_RETURNBUTTONS;
if ((capabilities & JOYCAPS_POVCTS) != 0)
joyinfoex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNPOV | JOY_RETURNBUTTONS | JOY_RETURNPOVCTS;
}
MMRESULT mmresult = joyGetPosEx(m_joyid, &joyinfoex);
if (mmresult == MMSYSERR_NOERROR) {
*p_buttonsState = joyinfoex.dwButtons;
MxU32 xmin = m_joyCaps.wXmin;
MxU32 ymax = m_joyCaps.wYmax;
MxU32 ymin = m_joyCaps.wYmin;
MxS32 ydiff = ymax - ymin;
*p_joystickX = ((joyinfoex.dwXpos - xmin) * 100) / (m_joyCaps.wXmax - xmin);
*p_joystickY = ((joyinfoex.dwYpos - m_joyCaps.wYmin) * 100) / ydiff;
if ((m_joyCaps.wCaps & (JOYCAPS_POV4DIR | JOYCAPS_POVCTS)) != 0) {
if (joyinfoex.dwPOV == JOY_POVCENTERED) {
*p_povPosition = (MxU32) -1;
return SUCCESS;
}
*p_povPosition = joyinfoex.dwPOV / 100;
return SUCCESS;
}
else {
*p_povPosition = (MxU32) -1;
return SUCCESS;
}
}
}
return FAILURE;
}
// FUNCTION: LEGO1 0x1005c470
void LegoInputManager::Register(MxCore* p_notify)
{
MxAutoLocker lock(&m_criticalSection);
LegoNotifyListCursor cursor(m_keyboardNotifyList);
if (!cursor.Find(p_notify))
m_keyboardNotifyList->Append(p_notify);
}
// FUNCTION: LEGO1 0x1005c5c0
void LegoInputManager::UnRegister(MxCore* p_notify)
{
MxAutoLocker lock(&m_criticalSection);
LegoNotifyListCursor cursor(m_keyboardNotifyList);
if (cursor.Find(p_notify))
cursor.Detach();
}
// FUNCTION: LEGO1 0x1005c700
void LegoInputManager::SetCamera(LegoCameraController* p_camera)
{
m_camera = p_camera;
}
// FUNCTION: LEGO1 0x1005c710
void LegoInputManager::ClearCamera()
{
m_camera = NULL;
}
// FUNCTION: LEGO1 0x1005c720
void LegoInputManager::SetWorld(LegoWorld* p_world)
{
m_world = p_world;
}
// FUNCTION: LEGO1 0x1005c730
void LegoInputManager::ClearWorld()
{
m_world = NULL;
}
// FUNCTION: LEGO1 0x1005c740
void LegoInputManager::QueueEvent(NotificationId p_id, MxU8 p_modifier, MxLong p_x, MxLong p_y, MxU8 p_key)
{
LegoEventNotificationParam param = LegoEventNotificationParam(p_id, NULL, p_modifier, p_x, p_y, p_key);
if (((!m_unk0x88) || ((m_unk0x335 && (param.GetType() == c_notificationButtonDown)))) ||
((m_unk0x336 && (p_key == ' ')))) {
ProcessOneEvent(param);
}
}
// FUNCTION: LEGO1 0x1005c820
void LegoInputManager::ProcessEvents()
{
MxAutoLocker lock(&m_criticalSection);
LegoEventNotificationParam event;
while (m_eventQueue->Dequeue(event)) {
if (ProcessOneEvent(event))
break;
}
}
// FUNCTION: LEGO1 0x1005c9c0
MxBool LegoInputManager::ProcessOneEvent(LegoEventNotificationParam& p_param)
{
MxBool processRoi;
if (p_param.GetType() == c_notificationKeyPress) {
if (!Lego()->IsTimerRunning() || p_param.GetKey() == 0x13) {
if (p_param.GetKey() == 0x10) {
if (m_unk0x195) {
m_unk0x80 = 0;
p_param.SetType(c_notificationDrag);
if (m_camera) {
m_camera->Notify(p_param);
}
}
m_unk0x195 = !m_unk0x195;
return TRUE;
}
LegoNotifyListCursor cursor(m_keyboardNotifyList);
MxCore* target;
while (cursor.Next(target)) {
if (target->Notify(p_param) != 0) {
return TRUE;
}
}
}
}
else {
if (!Lego()->IsTimerRunning()) {
processRoi = TRUE;
if (m_unk0x335 != 0) {
if (p_param.GetType() == c_notificationButtonDown) {
LegoEventNotificationParam notification(c_notificationKeyPress, NULL, 0, 0, 0, ' ');
LegoNotifyListCursor cursor(m_keyboardNotifyList);
MxCore* target;
while (cursor.Next(target)) {
if (target->Notify(notification) != 0) {
return TRUE;
}
}
}
return TRUE;
}
if (m_unk0x195 && p_param.GetType() == c_notificationButtonDown) {
m_unk0x195 = 0;
return TRUE;
}
if (m_world != NULL && m_world->Notify(p_param) != 0) {
return TRUE;
}
if (p_param.GetType() == c_notificationButtonDown) {
MxPresenter* presenter = VideoManager()->GetPresenterAt(p_param.GetX(), p_param.GetY());
if (presenter) {
if (presenter->GetDisplayZ() < 0) {
processRoi = FALSE;
if (m_controlManager->FUN_10029210(p_param, presenter)) {
return TRUE;
}
}
else {
LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY());
if (roi == NULL && m_controlManager->FUN_10029210(p_param, presenter)) {
return TRUE;
}
}
}
}
else if (p_param.GetType() == c_notificationButtonUp) {
if (g_unk0x100f31b0 != -1 || m_controlManager->GetUnknown0x10() ||
m_controlManager->GetUnknown0x0c() == 1) {
MxBool result = m_controlManager->FUN_10029210(p_param, NULL);
StopAutoDragTimer();
m_unk0x80 = 0;
m_unk0x81 = 0;
return result;
}
}
if (FUN_1005cdf0(p_param)) {
if (processRoi && p_param.GetType() == c_notificationType11) {
LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY());
p_param.SetROI(roi);
if (roi && roi->GetUnk0x0c() == 1) {
for (OrientableROI* oroi = roi->GetUnknown0xd4(); oroi; oroi = oroi->GetUnknown0xd4())
roi = (LegoROI*) oroi;
LegoEntity* entity = roi->GetUnknown0x104();
if (entity && entity->Notify(p_param) != 0) {
return TRUE;
}
}
}
if (m_camera && m_camera->Notify(p_param) != 0) {
return TRUE;
}
}
}
}
return FALSE;
}
// STUB: LEGO1 0x1005cdf0
MxBool LegoInputManager::FUN_1005cdf0(LegoEventNotificationParam& p_param)
{
// TODO
return FALSE;
}
// FUNCTION: LEGO1 0x1005cfb0
void LegoInputManager::StartAutoDragTimer()
{
m_autoDragTimerID = ::SetTimer(LegoOmni::GetInstance()->GetWindowHandle(), 1, m_autoDragTime, NULL);
}
// FUNCTION: LEGO1 0x1005cfd0
void LegoInputManager::StopAutoDragTimer()
{
if (m_autoDragTimerID)
::KillTimer(LegoOmni::GetInstance()->GetWindowHandle(), m_autoDragTimerID);
}
// FUNCTION: LEGO1 0x1005cff0
void LegoInputManager::EnableInputProcessing()
{
m_unk0x88 = FALSE;
g_unk0x100f31b0 = -1;
g_unk0x100f31b4 = 0;
}