diff --git a/src/gui/C4StartupOptionsDlg.cpp b/src/gui/C4StartupOptionsDlg.cpp index bcbbbd885..6e7e39695 100644 --- a/src/gui/C4StartupOptionsDlg.cpp +++ b/src/gui/C4StartupOptionsDlg.cpp @@ -23,6 +23,7 @@ #include "graphics/C4Draw.h" #include "graphics/C4GraphicsResource.h" #include "gui/C4MouseControl.h" +#include "gui/C4KeyboardInput.h" #include "gui/C4StartupMainDlg.h" #include "network/C4Network2.h" #include "platform/C4GamePadCon.h" @@ -147,7 +148,17 @@ C4StartupOptionsDlg::KeySelDialog::KeySelDialog(const C4PlayerControlAssignment : C4GUI::MessageDialog(GetDlgMessage(assignment, assignment_set).getData(), LoadResStr("IDS_MSG_DEFINEKEY"), C4GUI::MessageDialog::btnAbort | C4GUI::MessageDialog::btnReset, GetDlgIcon(assignment_set), C4GUI::MessageDialog::dsRegular), key(KEY_Undefined), assignment(assignment), assignment_set(assignment_set) { - pKeyListener = new C4KeyBinding(C4KeyCodeEx(KEY_Any, KEYS_None), "DefineKey", KEYSCOPE_Gui, new C4GUI::DlgKeyCBPassKey(*this, &C4StartupOptionsDlg::KeySelDialog::KeyDown), C4CustomKey::PRIO_PlrControl); + pKeyListener = new C4KeyBinding( + C4KeyCodeEx(KEY_Any, KEYS_None), + "DefineKey", + KEYSCOPE_Gui, + new C4GUI::DlgKeyCBPassKey( + *this, + &C4StartupOptionsDlg::KeySelDialog::KeyDown, + &C4StartupOptionsDlg::KeySelDialog::KeyUp + ), + C4CustomKey::PRIO_PlrControl + ); } StdStrBuf C4StartupOptionsDlg::KeySelDialog::GetDlgMessage(const C4PlayerControlAssignment *assignment, const C4PlayerControlAssignmentSet *assignment_set) @@ -183,7 +194,61 @@ C4StartupOptionsDlg::KeySelDialog::~KeySelDialog() delete pKeyListener; } -bool C4StartupOptionsDlg::KeySelDialog::KeyDown(const C4KeyCodeEx &key) +void C4StartupOptionsDlg::KeySelDialog::MouseInput(C4GUI::CMouse& rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) +{ + // Original action + C4GUI::MessageDialog::MouseInput(rMouse, iButton, iX, iY, dwKeyParam); + + // Find out to where the input was made (code duplication with C4GUI::Window::MouseInput) + // get client pos + C4Rect &rcClientRect = GetClientRect(), &rcBounds = GetBounds(); + iX -= rcClientRect.x - rcBounds.x; iY -= rcClientRect.y - rcBounds.y; + // forward to topmost child element + for (Element *pChild = pLast; pChild; pChild = pChild->GetPrev()) + if (pChild->fVisible && pChild->GetBounds().Contains(iX, iY)) + { + if (dynamic_cast(pChild)) + break; + else + return; + } + // Only process the input event if the user certainly didn't click a button or anything… + + // Logic duplication of C4PlayerControl::DoMouseInput (and C4MouseControl::Move for the wheel_dir.) There has to be a better way. :( + uint8_t mouseevent_code; + int wheel_dir = 0; + if (iButton == C4MC_Button_Wheel) wheel_dir = (short)(dwKeyParam >> 16); + switch (iButton) + { + case C4MC_Button_LeftUp: + case C4MC_Button_RightUp: + case C4MC_Button_MiddleUp: + case C4MC_Button_X1Up: + case C4MC_Button_X2Up: + case C4MC_Button_None: + return; + case C4MC_Button_LeftDown: mouseevent_code = KEY_MOUSE_ButtonLeft; break; + case C4MC_Button_LeftDouble: mouseevent_code = KEY_MOUSE_ButtonLeftDouble; break; + case C4MC_Button_RightDown: mouseevent_code = KEY_MOUSE_ButtonRight; break; + case C4MC_Button_RightDouble: mouseevent_code = KEY_MOUSE_ButtonRightDouble; break; + case C4MC_Button_MiddleDown: mouseevent_code = KEY_MOUSE_ButtonMiddle; break; + case C4MC_Button_MiddleDouble: mouseevent_code = KEY_MOUSE_ButtonMiddleDouble; break; + case C4MC_Button_X1Down: mouseevent_code = KEY_MOUSE_ButtonX1; break; + case C4MC_Button_X1Double: mouseevent_code = KEY_MOUSE_ButtonX1Double; break; + case C4MC_Button_X2Down: mouseevent_code = KEY_MOUSE_ButtonX2; break; + case C4MC_Button_X2Double: mouseevent_code = KEY_MOUSE_ButtonX2Double; break; + case C4MC_Button_Wheel: + if (!wheel_dir) return; + mouseevent_code = (wheel_dir > 0) ? KEY_MOUSE_Wheel1Up : KEY_MOUSE_Wheel1Down; break; + } + C4KeyCodeEx key{KEY_Mouse(0, mouseevent_code), KEYS_None}; + if (dwKeyParam & MK_CONTROL) key.dwShift |= KEYS_Control; + if (dwKeyParam & MK_SHIFT) key.dwShift |= KEYS_Shift; + if (dwKeyParam & MK_ALT) key.dwShift |= KEYS_Alt; + KeyDown(key); +} + +bool C4StartupOptionsDlg::KeySelDialog::KeyPress(const C4KeyCodeEx &key, bool fDown) { // safety if (!assignment || !assignment_set) return false; @@ -200,6 +265,13 @@ bool C4StartupOptionsDlg::KeySelDialog::KeyDown(const C4KeyCodeEx &key) { if (!assignment_set->HasKeyboard()) return false; } + // FIXME: There doesn't seem to be any kind of KEY_IsModifier function… + switch (key.Key) { + case K_CONTROL_L: case K_SHIFT_L: case K_ALT_L: + case K_CONTROL_R: case K_SHIFT_R: case K_ALT_R: + if (fDown) + return false; + } // okay, use it this->key=key; Close(true); diff --git a/src/gui/C4StartupOptionsDlg.h b/src/gui/C4StartupOptionsDlg.h index 689be61db..740adf86a 100644 --- a/src/gui/C4StartupOptionsDlg.h +++ b/src/gui/C4StartupOptionsDlg.h @@ -165,7 +165,10 @@ private: static C4GUI::Icons GetDlgIcon(const class C4PlayerControlAssignmentSet *assignment_set); protected: - bool KeyDown(const C4KeyCodeEx &key); + bool KeyDown(const C4KeyCodeEx &key) { return KeyPress(key, true); }; + bool KeyUp(const C4KeyCodeEx &key) { return KeyPress(key, false); }; + bool KeyPress(const C4KeyCodeEx &key, bool fDown); + void MouseInput(C4GUI::CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; public: KeySelDialog(const class C4PlayerControlAssignment *assignment, const class C4PlayerControlAssignmentSet *assignment_set); ~KeySelDialog() override;