2015-04-16 16:55:32 +00:00
|
|
|
/*
|
|
|
|
GWEN
|
|
|
|
Copyright (c) 2010 Facepunch Studios
|
|
|
|
See license in Gwen.h
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "Gwen/InputHandler.h"
|
|
|
|
#include "Gwen/Controls/Base.h"
|
|
|
|
#include "Gwen/DragAndDrop.h"
|
|
|
|
#include "Gwen/Hook.h"
|
|
|
|
#include "Gwen/Platform.h"
|
|
|
|
|
|
|
|
#define DOUBLE_CLICK_SPEED 0.5f
|
|
|
|
#define MAX_MOUSE_BUTTONS 5
|
|
|
|
|
|
|
|
using namespace Gwen;
|
|
|
|
|
|
|
|
struct Action
|
|
|
|
{
|
|
|
|
unsigned char type;
|
|
|
|
|
|
|
|
int x, y;
|
|
|
|
Gwen::UnicodeChar chr;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const float KeyRepeatRate = 0.03f;
|
|
|
|
static const float KeyRepeatDelay = 0.3f;
|
|
|
|
|
|
|
|
struct t_KeyData
|
|
|
|
{
|
|
|
|
t_KeyData()
|
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
for (int i = 0; i < Gwen::Key::Count; i++)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
KeyState[i] = false;
|
|
|
|
NextRepeat[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Target = NULL;
|
|
|
|
LeftMouseDown = false;
|
|
|
|
RightMouseDown = false;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
bool KeyState[Gwen::Key::Count];
|
|
|
|
float NextRepeat[Gwen::Key::Count];
|
2015-04-16 16:55:32 +00:00
|
|
|
Controls::Base* Target;
|
|
|
|
bool LeftMouseDown;
|
|
|
|
bool RightMouseDown;
|
|
|
|
|
|
|
|
} KeyData;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
Gwen::Point MousePosition;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
static float g_fLastClickTime[MAX_MOUSE_BUTTONS];
|
|
|
|
static Gwen::Point g_pntLastClickPos;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
ACT_MOUSEMOVE,
|
|
|
|
ACT_MOUSEBUTTON,
|
|
|
|
ACT_CHAR,
|
|
|
|
ACT_MOUSEWHEEL,
|
|
|
|
ACT_KEYPRESS,
|
|
|
|
ACT_KEYRELEASE,
|
|
|
|
ACT_MESSAGE
|
|
|
|
};
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
void UpdateHoveredControl(Controls::Base* pInCanvas)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
Controls::Base* pHovered = pInCanvas->GetControlAt(MousePosition.x, MousePosition.y);
|
2015-04-16 16:55:32 +00:00
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::HoveredControl && pHovered != Gwen::HoveredControl)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::HoveredControl->OnMouseLeave();
|
|
|
|
|
|
|
|
pInCanvas->Redraw();
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (pHovered != Gwen::HoveredControl)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::HoveredControl = pHovered;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::HoveredControl)
|
2015-04-16 16:55:32 +00:00
|
|
|
Gwen::HoveredControl->OnMouseEnter();
|
|
|
|
|
|
|
|
pInCanvas->Redraw();
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::MouseFocus && Gwen::MouseFocus->GetCanvas() == pInCanvas)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::HoveredControl = Gwen::MouseFocus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
void FindKeyboardFocus(Controls::Base* pControl)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!pControl) return;
|
|
|
|
if (pControl->GetKeyboardInputEnabled())
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
//Make sure none of our children have keyboard focus first - todo recursive
|
|
|
|
for (Controls::Base::List::iterator iter = pControl->Children.begin(); iter != pControl->Children.end(); ++iter)
|
|
|
|
{
|
|
|
|
Controls::Base* pChild = *iter;
|
2018-09-23 21:17:31 +00:00
|
|
|
if (pChild == Gwen::KeyboardFocus)
|
2015-04-16 16:55:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
pControl->Focus();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
return FindKeyboardFocus(pControl->GetParent());
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Gwen::Point Gwen::Input::GetMousePosition()
|
|
|
|
{
|
|
|
|
return MousePosition;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
void Gwen::Input::OnCanvasThink(Controls::Base* pControl)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::MouseFocus && !Gwen::MouseFocus->Visible())
|
2015-04-16 16:55:32 +00:00
|
|
|
Gwen::MouseFocus = NULL;
|
2018-09-23 21:17:31 +00:00
|
|
|
|
|
|
|
if (Gwen::KeyboardFocus)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
bool isVisible = Gwen::KeyboardFocus->Visible();
|
|
|
|
bool isEnabled = KeyboardFocus->GetKeyboardInputEnabled();
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!isVisible || !isEnabled)
|
2015-04-16 16:55:32 +00:00
|
|
|
Gwen::KeyboardFocus = NULL;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!KeyboardFocus) return;
|
|
|
|
if (KeyboardFocus->GetCanvas() != pControl) return;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
|
|
|
float fTime = Gwen::Platform::GetTimeInSeconds();
|
|
|
|
|
|
|
|
//
|
|
|
|
// Simulate Key-Repeats
|
|
|
|
//
|
2018-09-23 21:17:31 +00:00
|
|
|
for (int i = 0; i < Gwen::Key::Count; i++)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (KeyData.KeyState[i] && KeyData.Target != KeyboardFocus)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
KeyData.KeyState[i] = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (KeyData.KeyState[i] && fTime > KeyData.NextRepeat[i])
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
KeyData.NextRepeat[i] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatRate;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (KeyboardFocus)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
KeyboardFocus->OnKeyPress(i);
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
bool Gwen::Input::IsKeyDown(int iKey)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
return KeyData.KeyState[iKey];
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool Gwen::Input::IsLeftMouseDown()
|
|
|
|
{
|
|
|
|
return KeyData.LeftMouseDown;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Gwen::Input::IsRightMouseDown()
|
|
|
|
{
|
|
|
|
return KeyData.RightMouseDown;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
void Gwen::Input::OnMouseMoved(Controls::Base* pCanvas, int x, int y, int /*deltaX*/, int /*deltaY*/)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
MousePosition.x = x;
|
|
|
|
MousePosition.y = y;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
UpdateHoveredControl(pCanvas);
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
bool Gwen::Input::OnMouseClicked(Controls::Base* pCanvas, int iMouseButton, bool bDown)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
// If we click on a control that isn't a menu we want to close
|
|
|
|
// all the open menus. Menus are children of the canvas.
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown && (!Gwen::HoveredControl || !Gwen::HoveredControl->IsMenuComponent()))
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
pCanvas->CloseMenus();
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!Gwen::HoveredControl) return false;
|
|
|
|
if (Gwen::HoveredControl->GetCanvas() != pCanvas) return false;
|
|
|
|
if (!Gwen::HoveredControl->Visible()) return false;
|
|
|
|
if (Gwen::HoveredControl == pCanvas) return false;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (iMouseButton > MAX_MOUSE_BUTTONS)
|
2015-04-16 16:55:32 +00:00
|
|
|
return false;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (iMouseButton == 0)
|
|
|
|
KeyData.LeftMouseDown = bDown;
|
|
|
|
else if (iMouseButton == 1)
|
|
|
|
KeyData.RightMouseDown = bDown;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
|
|
|
// Double click.
|
|
|
|
// Todo: Shouldn't double click if mouse has moved significantly
|
|
|
|
bool bIsDoubleClick = false;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown &&
|
|
|
|
g_pntLastClickPos.x == MousePosition.x &&
|
2015-04-16 16:55:32 +00:00
|
|
|
g_pntLastClickPos.y == MousePosition.y &&
|
2018-09-23 21:17:31 +00:00
|
|
|
(Gwen::Platform::GetTimeInSeconds() - g_fLastClickTime[iMouseButton]) < DOUBLE_CLICK_SPEED)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
bIsDoubleClick = true;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown && !bIsDoubleClick)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
g_fLastClickTime[iMouseButton] = Gwen::Platform::GetTimeInSeconds();
|
2015-04-16 16:55:32 +00:00
|
|
|
g_pntLastClickPos = MousePosition;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
FindKeyboardFocus(Gwen::HoveredControl);
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Gwen::HoveredControl->UpdateCursor();
|
|
|
|
|
|
|
|
// This tells the child it has been touched, which
|
|
|
|
// in turn tells its parents, who tell their parents.
|
|
|
|
// This is basically so that Windows can pop themselves
|
|
|
|
// to the top when one of their children have been clicked.
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown)
|
2015-04-16 16:55:32 +00:00
|
|
|
Gwen::HoveredControl->Touch();
|
|
|
|
|
|
|
|
#ifdef GWEN_HOOKSYSTEM
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Hook::CallHook(&Hook::BaseHook::OnControlClicked, Gwen::HoveredControl, MousePosition.x, MousePosition.y))
|
2015-04-16 16:55:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
switch (iMouseButton)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
case 0:
|
2018-09-23 21:17:31 +00:00
|
|
|
{
|
|
|
|
if (DragAndDrop::OnMouseButton(Gwen::HoveredControl, MousePosition.x, MousePosition.y, bDown))
|
2015-04-16 16:55:32 +00:00
|
|
|
return true;
|
2018-09-23 21:17:31 +00:00
|
|
|
|
|
|
|
if (bIsDoubleClick)
|
|
|
|
Gwen::HoveredControl->OnMouseDoubleClickLeft(MousePosition.x, MousePosition.y);
|
|
|
|
else
|
|
|
|
Gwen::HoveredControl->OnMouseClickLeft(MousePosition.x, MousePosition.y, bDown);
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-16 16:55:32 +00:00
|
|
|
|
|
|
|
case 1:
|
2018-09-23 21:17:31 +00:00
|
|
|
{
|
|
|
|
if (bIsDoubleClick)
|
|
|
|
Gwen::HoveredControl->OnMouseDoubleClickRight(MousePosition.x, MousePosition.y);
|
|
|
|
else
|
|
|
|
Gwen::HoveredControl->OnMouseClickRight(MousePosition.x, MousePosition.y, bDown);
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
bool Gwen::Input::HandleAccelerator(Controls::Base* pCanvas, Gwen::UnicodeChar chr)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
//Build the accelerator search string
|
|
|
|
Gwen::UnicodeString accelString;
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::Input::IsControlDown())
|
2015-04-16 16:55:32 +00:00
|
|
|
accelString += L"Ctrl + ";
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::Input::IsShiftDown())
|
2015-04-16 16:55:32 +00:00
|
|
|
accelString += L"Shift + ";
|
|
|
|
|
|
|
|
accelString += chr;
|
|
|
|
|
|
|
|
//Debug::Msg("Accelerator string :%S\n", accelString.c_str());
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::KeyboardFocus && Gwen::KeyboardFocus->HandleAccelerator(accelString))
|
2015-04-16 16:55:32 +00:00
|
|
|
return true;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (Gwen::MouseFocus && Gwen::MouseFocus->HandleAccelerator(accelString))
|
2015-04-16 16:55:32 +00:00
|
|
|
return true;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (pCanvas->HandleAccelerator(accelString))
|
2015-04-16 16:55:32 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
bool Gwen::Input::DoSpecialKeys(Controls::Base* pCanvas, Gwen::UnicodeChar chr)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!Gwen::KeyboardFocus) return false;
|
|
|
|
if (Gwen::KeyboardFocus->GetCanvas() != pCanvas) return false;
|
|
|
|
if (!Gwen::KeyboardFocus->Visible()) return false;
|
|
|
|
if (!Gwen::Input::IsControlDown()) return false;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (chr == L'C' || chr == L'c')
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::KeyboardFocus->OnCopy(NULL);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (chr == L'V' || chr == L'v')
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::KeyboardFocus->OnPaste(NULL);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (chr == L'X' || chr == L'x')
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::KeyboardFocus->OnCut(NULL);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (chr == L'A' || chr == L'a')
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
|
|
|
Gwen::KeyboardFocus->OnSelectAll(NULL);
|
|
|
|
return true;
|
|
|
|
}
|
2018-09-23 21:17:31 +00:00
|
|
|
|
2015-04-16 16:55:32 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
bool Gwen::Input::OnKeyEvent(Controls::Base* pCanvas, int iKey, bool bDown)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!Gwen::KeyboardFocus) return false;
|
|
|
|
if (Gwen::KeyboardFocus->GetCanvas() != pCanvas) return false;
|
|
|
|
if (!Gwen::KeyboardFocus->Visible()) return false;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
if (bDown)
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (!KeyData.KeyState[iKey])
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
KeyData.KeyState[iKey] = true;
|
|
|
|
KeyData.NextRepeat[iKey] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatDelay;
|
2015-04-16 16:55:32 +00:00
|
|
|
KeyData.Target = KeyboardFocus;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
return KeyboardFocus->OnKeyPress(iKey);
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
if (KeyData.KeyState[iKey])
|
2015-04-16 16:55:32 +00:00
|
|
|
{
|
2018-09-23 21:17:31 +00:00
|
|
|
KeyData.KeyState[iKey] = false;
|
2015-04-16 16:55:32 +00:00
|
|
|
|
|
|
|
// BUG BUG. This causes shift left arrow in textboxes
|
|
|
|
// to not work. What is disabling it here breaking?
|
|
|
|
//KeyData.Target = NULL;
|
|
|
|
|
2018-09-23 21:17:31 +00:00
|
|
|
return KeyboardFocus->OnKeyRelease(iKey);
|
2015-04-16 16:55:32 +00:00
|
|
|
}
|
|
|
|
}
|
2018-09-23 21:17:31 +00:00
|
|
|
|
2015-04-16 16:55:32 +00:00
|
|
|
return false;
|
|
|
|
}
|