From 44657a1a1e7bef8b9b76d9d50883001afda0d40d Mon Sep 17 00:00:00 2001 From: Xottab-DUTY Date: Fri, 27 Jul 2018 17:17:45 +0500 Subject: [PATCH] Support for exclusive input mode Tweaks for window hit test --- src/xrEngine/Device_Initialize.cpp | 23 ++++----- src/xrEngine/Device_destroy.cpp | 5 +- src/xrEngine/XR_IOConsole.cpp | 2 +- src/xrEngine/device.cpp | 14 +++-- src/xrEngine/edit_actions.cpp | 7 +-- src/xrEngine/line_edit_control.cpp | 5 +- src/xrEngine/x_ray.cpp | 8 +-- src/xrEngine/xr_input.cpp | 82 +++++++++++++----------------- src/xrEngine/xr_input.h | 32 ++++-------- src/xrEngine/xr_ioc_cmd.cpp | 2 +- src/xrGame/MainMenu.cpp | 4 +- 11 files changed, 81 insertions(+), 103 deletions(-) diff --git a/src/xrEngine/Device_Initialize.cpp b/src/xrEngine/Device_Initialize.cpp index 1d2c1e57e1b..3220bcc1988 100644 --- a/src/xrEngine/Device_Initialize.cpp +++ b/src/xrEngine/Device_Initialize.cpp @@ -4,6 +4,7 @@ #include "Include/editor/ide.hpp" #include "engine_impl.hpp" +#include "xr_input.h" #include "GameFont.h" #include "PerformanceAlert.hpp" #include "xrCore/ModuleLookup.hpp" @@ -72,15 +73,18 @@ void CRenderDevice::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) SDL_HitTestResult WindowHitTest(SDL_Window* /*window*/, const SDL_Point* area, void* /*data*/) { + if (pInput->InputIsGrabbed()) + return SDL_HITTEST_NORMAL; + const auto& rect = Device.m_rcWindowClient; // size of additional interactive area (in pixels) constexpr int hit = 15; - const bool leftSide = area->x < rect.x + hit; - const bool topSide = area->y < rect.y + hit; - const bool bottomSide = area->y > rect.h - hit; - const bool rightSide = area->x > rect.w - hit; + const bool leftSide = area->x <= rect.x + hit; + const bool topSide = area->y <= rect.y + hit; + const bool bottomSide = area->y >= rect.h - hit; + const bool rightSide = area->x >= rect.w - hit; if (leftSide && topSide) return SDL_HITTEST_RESIZE_TOPLEFT; @@ -106,14 +110,5 @@ SDL_HitTestResult WindowHitTest(SDL_Window* /*window*/, const SDL_Point* area, v if (leftSide) return SDL_HITTEST_RESIZE_LEFT; - const int centerX = rect.w / 2; - const int centerY = rect.h / 2; - - // Allow drag from any point except window center - // For this case, 'hit' is a size of a square in the center - if ((area->x > centerX + hit || area->x < centerX - hit) - || (area->y > centerY + hit || area->y < centerY - hit)) - return SDL_HITTEST_DRAGGABLE; - - return SDL_HITTEST_NORMAL; + return SDL_HITTEST_DRAGGABLE; } diff --git a/src/xrEngine/Device_destroy.cpp b/src/xrEngine/Device_destroy.cpp index 5c8b2459b45..cfc30729646 100644 --- a/src/xrEngine/Device_destroy.cpp +++ b/src/xrEngine/Device_destroy.cpp @@ -16,7 +16,6 @@ void CRenderDevice::Destroy() if (!b_is_Ready) return; Log("Destroying Direct3D..."); - pInput->ClipCursor(false); GEnv.Render->ValidateHW(); GEnv.DU->OnDeviceDestroy(); b_is_Ready = false; @@ -51,7 +50,7 @@ void CRenderDevice::Reset(bool precache) { const auto dwWidth_before = dwWidth; const auto dwHeight_before = dwHeight; - pInput->ClipCursor(false); + pInput->GrabInput(false); const auto tm_start = TimerAsync(); @@ -76,5 +75,5 @@ void CRenderDevice::Reset(bool precache) seqResolutionChanged.Process(); if (!GEnv.isDedicatedServer) - pInput->ClipCursor(true); + pInput->GrabInput(true); } diff --git a/src/xrEngine/XR_IOConsole.cpp b/src/xrEngine/XR_IOConsole.cpp index 4fa0e7441c8..94b0a28137b 100644 --- a/src/xrEngine/XR_IOConsole.cpp +++ b/src/xrEngine/XR_IOConsole.cpp @@ -624,7 +624,7 @@ void CConsole::Hide() // if ( g_pGameLevel || // ( g_pGamePersistent && g_pGamePersistent->m_pMainMenu && g_pGamePersistent->m_pMainMenu->IsActive() )) - if (pInput->get_exclusive_mode()) + if (pInput->IsExclusiveMode()) { SDL_WarpMouseGlobal(m_mouse_pos.x, m_mouse_pos.y); // Replace with SDL_WarpMouseInWindow in case set window-relative coordinates } diff --git a/src/xrEngine/device.cpp b/src/xrEngine/device.cpp index c44a2fa9899..e6696903fc9 100644 --- a/src/xrEngine/device.cpp +++ b/src/xrEngine/device.cpp @@ -383,6 +383,14 @@ void CRenderDevice::message_loop() OnWM_Activate(0, event.window.data2); break; + case SDL_WINDOWEVENT_ENTER: + SDL_ShowCursor(SDL_FALSE); + break; + + case SDL_WINDOWEVENT_LEAVE: + SDL_ShowCursor(SDL_TRUE); + break; + case SDL_WINDOWEVENT_CLOSE: event.type = SDL_QUIT; } @@ -425,7 +433,7 @@ void CRenderDevice::Run() SDL_FlushEvents(SDL_WINDOWEVENT, SDL_SYSWMEVENT); SDL_ShowWindow(m_sdlWnd); SDL_RaiseWindow(m_sdlWnd); - pInput->ClipCursor(true); + pInput->GrabInput(true); message_loop(); seqAppEnd.Process(); // Stop Balance-Thread @@ -553,9 +561,9 @@ void CRenderDevice::OnWM_Activate(WPARAM wParam, LPARAM /*lParam*/) const BOOL isWndActive = (fActive != WA_INACTIVE && !fMinimized) ? TRUE : FALSE; if (!editor() && !GEnv.isDedicatedServer && isWndActive) - pInput->ClipCursor(true); + pInput->GrabInput(true); else - pInput->ClipCursor(false); + pInput->GrabInput(false); extern int ps_always_active; const BOOL isGameActive = ps_always_active || isWndActive; diff --git a/src/xrEngine/edit_actions.cpp b/src/xrEngine/edit_actions.cpp index a3385e3d619..baabfd002f6 100644 --- a/src/xrEngine/edit_actions.cpp +++ b/src/xrEngine/edit_actions.cpp @@ -9,7 +9,6 @@ #include "edit_actions.h" #include "line_edit_control.h" #include "xr_input.h" -#include #include namespace text_editor @@ -76,7 +75,7 @@ void type_pair::on_key_press(line_edit_control* const control) char c_shift = m_char_shift; SDL_Event event; - while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_TEXTEDITING, SDL_TEXTINPUT)) + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT)) { switch (event.type) { @@ -92,10 +91,6 @@ void type_pair::on_key_press(line_edit_control* const control) } break; } - - case SDL_TEXTEDITING: - // XXX: use this? - break; } } diff --git a/src/xrEngine/line_edit_control.cpp b/src/xrEngine/line_edit_control.cpp index 4d8b5584588..29f30febd58 100644 --- a/src/xrEngine/line_edit_control.cpp +++ b/src/xrEngine/line_edit_control.cpp @@ -720,7 +720,10 @@ void line_edit_control::clamp_cur_pos() { clamp(m_cur_pos, 0, (int)xr_strlen(m_e void line_edit_control::SwitchKL() { #ifdef WINDOWS - if (pInput->get_exclusive_mode()) + // XXX: do we even need this? + // Check if SDL_HINT_GRAB_KEYBOARD works + // and enable in case if we will need this + if (false && pInput->IsExclusiveMode()) ActivateKeyboardLayout((HKL)HKL_NEXT, 0); #endif } diff --git a/src/xrEngine/x_ray.cpp b/src/xrEngine/x_ray.cpp index 57557ee9e12..7386e6184d9 100644 --- a/src/xrEngine/x_ray.cpp +++ b/src/xrEngine/x_ray.cpp @@ -159,8 +159,8 @@ void CApplication::OnEvent(EVENT E, u64 P1, u64 P2) { if (E == eQuit) { - if (pInput != NULL) - pInput->ClipCursor(false); + if (pInput != nullptr) + pInput->GrabInput(false); g_SASH.EndBenchmark(); @@ -200,8 +200,8 @@ void CApplication::OnEvent(EVENT E, u64 P1, u64 P2) } else if (E == eDisconnect) { - if (pInput != NULL && TRUE == Engine.Event.Peek("KERNEL:quit")) - pInput->ClipCursor(false); + if (pInput != nullptr && TRUE == Engine.Event.Peek("KERNEL:quit")) + pInput->GrabInput(false); if (g_pGameLevel) { diff --git a/src/xrEngine/xr_input.cpp b/src/xrEngine/xr_input.cpp index d13b3620797..6e350def180 100644 --- a/src/xrEngine/xr_input.cpp +++ b/src/xrEngine/xr_input.cpp @@ -19,30 +19,20 @@ ENGINE_API Flags32 psMouseInvert = {FALSE}; float stop_vibration_time = flt_max; -#define MOUSEBUFFERSIZE 64 -#define KEYBOARDBUFFERSIZE 64 - -static bool g_exclusive = true; static void on_error_dialog(bool before) { - if (!pInput || !g_exclusive || Device.editor()) + if (!pInput || !pInput->IsExclusiveMode() || Device.editor()) return; if (before) - { - pInput->ClipCursor(false); - pInput->unacquire(); - } + pInput->GrabInput(false); else - { - pInput->ClipCursor(true); - pInput->acquire(true); - } + pInput->GrabInput(true); } -CInput::CInput(bool exclusive, int deviceForInit) +CInput::CInput(const bool exclusive) { - g_exclusive = exclusive; + exclusiveInput = exclusive; Log("Starting INPUT device..."); @@ -58,22 +48,20 @@ CInput::CInput(bool exclusive, int deviceForInit) xrDebug::SetDialogHandler(on_error_dialog); + SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); SDL_StopTextInput(); // sanity -#ifdef ENGINE_BUILD Device.seqAppActivate.Add(this); Device.seqAppDeactivate.Add(this, REG_PRIORITY_HIGH); Device.seqFrame.Add(this, REG_PRIORITY_HIGH); -#endif } -CInput::~CInput(void) +CInput::~CInput() { -#ifdef ENGINE_BUILD + GrabInput(false); Device.seqFrame.Remove(this); Device.seqAppDeactivate.Remove(this); Device.seqAppActivate.Remove(this); -#endif } //----------------------------------------------------------------------- @@ -83,12 +71,6 @@ void CInput::DumpStatistics(IGameFont& font, IPerformanceAlert* alert) font.OutNext("*** INPUT: %2.2fms", pInput->GetStats().FrameTime.result); } -void CInput::SetAllAcquire(bool bAcquire) {} - -void CInput::SetMouseAcquire(bool bAcquire) {} -void CInput::SetKBDAcquire(bool bAcquire) {} - - void CInput::MouseUpdate() { SDL_PumpEvents(); @@ -255,21 +237,37 @@ bool CInput::iGetAsyncBtnState(int btn) { return mouseState[btn]; } -void CInput::ClipCursor(bool clip) + +void CInput::ClipCursor(const bool clip) { if (clip) { - SDL_SetWindowGrab(Device.m_sdlWnd, SDL_TRUE); + SDL_ShowCursor(SDL_TRUE); SDL_SetRelativeMouseMode(SDL_TRUE); } else { - SDL_SetWindowGrab(Device.m_sdlWnd, SDL_FALSE); + SDL_ShowCursor(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE); } } -//------------------------------------------------------- +void CInput::GrabInput(const bool grab) +{ + ClipCursor(grab); + + if (IsExclusiveMode()) + SDL_SetWindowGrab(Device.m_sdlWnd, grab ? SDL_TRUE : SDL_FALSE); + + inputGrabbed = grab; + +} + +bool CInput::InputIsGrabbed() const +{ + return inputGrabbed; +} + void CInput::iCapture(IInputReceiver* p) { VERIFY(p); @@ -313,7 +311,6 @@ void CInput::OnAppActivate(void) if (CurrentIR()) CurrentIR()->IR_OnActivate(); - SetAllAcquire(true); ZeroMemory(mouseState, sizeof(mouseState)); ZeroMemory(keyboardState, sizeof(keyboardState)); ZeroMemory(mouseTimeStamp, sizeof(mouseTimeStamp)); @@ -325,7 +322,6 @@ void CInput::OnAppDeactivate(void) if (CurrentIR()) CurrentIR()->IR_OnDeactivate(); - SetAllAcquire(false); ZeroMemory(mouseState, sizeof(mouseState)); ZeroMemory(keyboardState, sizeof(keyboardState)); ZeroMemory(mouseTimeStamp, sizeof(mouseTimeStamp)); @@ -352,26 +348,18 @@ IInputReceiver* CInput::CurrentIR() { if (cbStack.size()) return cbStack.back(); - else - return NULL; + return nullptr; } -void CInput::unacquire() {} - -void CInput::acquire(const bool& exclusive) +void CInput::ExclusiveMode(const bool exclusive) { - // pMouse->SetCooperativeLevel(Device.editor() ? Device.editor()->main_handle() : RDEVICE.m_sdlWnd, - // (exclusive ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE) | DISCL_FOREGROUND | DISCL_NOWINKEY); - // pMouse->Acquire(); + GrabInput(false); + exclusiveInput = exclusive; + GrabInput(true); } -void CInput::exclusive_mode(const bool& exclusive) -{ - g_exclusive = exclusive; - unacquire(); - acquire(exclusive); -} -bool CInput::get_exclusive_mode() { return g_exclusive; } +bool CInput::IsExclusiveMode() const { return exclusiveInput; } + void CInput::feedback(u16 s1, u16 s2, float time) { stop_vibration_time = RDEVICE.fTimeGlobal + time; diff --git a/src/xrEngine/xr_input.h b/src/xrEngine/xr_input.h index 46208ee4dec..0284feb5044 100644 --- a/src/xrEngine/xr_input.h +++ b/src/xrEngine/xr_input.h @@ -38,19 +38,10 @@ inline int KeyToMouseButton(const int dik, const bool fromZero = true) class ENGINE_API IInputReceiver; -//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ -//описание класса -const int mouse_device_key = 1; -const int keyboard_device_key = 2; -const int all_device_key = mouse_device_key | keyboard_device_key; -const int default_key = mouse_device_key | keyboard_device_key; - class ENGINE_API CInput -#ifndef M_BORLAND : public pureFrame, public pureAppActivate, public pureAppDeactivate -#endif { public: enum @@ -84,6 +75,8 @@ class ENGINE_API CInput void KeyUpdate(); InputStatistics stats; + bool exclusiveInput; + bool inputGrabbed; public: u32 dwCurTime; @@ -91,31 +84,28 @@ class ENGINE_API CInput const InputStatistics& GetStats() const { return stats; } void DumpStatistics(class IGameFont& font, class IPerformanceAlert* alert); - void SetAllAcquire(bool bAcquire = true); - void SetMouseAcquire(bool bAcquire); - void SetKBDAcquire(bool bAcquire); void iCapture(IInputReceiver* pc); void iRelease(IInputReceiver* pc); bool iGetAsyncKeyState(int dik); bool iGetAsyncBtnState(int btn); void iGetLastMouseDelta(Ivector2& p) { p.set(offs[0], offs[1]); } - void ClipCursor(bool clip); + void ClipCursor(const bool clip); + void GrabInput(const bool grab); + bool InputIsGrabbed() const; - CInput(bool exclusive = true, int deviceForInit = default_key); + CInput(const bool exclusive = true); ~CInput(); - virtual void OnFrame(void); - virtual void OnAppActivate(void); - virtual void OnAppDeactivate(void); + virtual void OnFrame(); + virtual void OnAppActivate(); + virtual void OnAppDeactivate(); IInputReceiver* CurrentIR(); public: - void exclusive_mode(const bool& exclusive); - IC bool get_exclusive_mode(); - void unacquire(); - void acquire(const bool& exclusive); + void ExclusiveMode(const bool exclusive); + bool IsExclusiveMode() const; bool get_dik_name(int dik, LPSTR dest, int dest_sz); void feedback(u16 s1, u16 s2, float time); diff --git a/src/xrEngine/xr_ioc_cmd.cpp b/src/xrEngine/xr_ioc_cmd.cpp index f1651a5dda7..b7c580ec7ee 100644 --- a/src/xrEngine/xr_ioc_cmd.cpp +++ b/src/xrEngine/xr_ioc_cmd.cpp @@ -642,7 +642,7 @@ class CCC_ExclusiveMode : public IConsole_Command else InvalidSyntax(); - pInput->exclusive_mode(value); + pInput->ExclusiveMode(value); } virtual void Save(IWriter* F) {} diff --git a/src/xrGame/MainMenu.cpp b/src/xrGame/MainMenu.cpp index ec7e768f9dd..85b1824525a 100644 --- a/src/xrGame/MainMenu.cpp +++ b/src/xrGame/MainMenu.cpp @@ -352,7 +352,7 @@ void CMainMenu::IR_OnKeyboardPress(int dik) && (pInput->iGetAsyncKeyState(SDL_SCANCODE_LGUI) || pInput->iGetAsyncKeyState(SDL_SCANCODE_RGUI))) { IWantMyMouseBackScreamed = true; - pInput->ClipCursor(false); + pInput->GrabInput(false); } if (SDL_SCANCODE_F12 == dik) @@ -372,7 +372,7 @@ void CMainMenu::IR_OnKeyboardRelease(int dik) if (IWantMyMouseBackScreamed) { IWantMyMouseBackScreamed = false; - pInput->ClipCursor(true); + pInput->GrabInput(true); }