123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- /*
- 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()
- {
- for ( int i=0; i<Gwen::Key::Count; i++ )
- {
- KeyState[i] = false;
- NextRepeat[i] = 0;
- }
- Target = NULL;
- LeftMouseDown = false;
- RightMouseDown = false;
- }
- bool KeyState[ Gwen::Key::Count ];
- float NextRepeat[ Gwen::Key::Count ];
- Controls::Base* Target;
- bool LeftMouseDown;
- bool RightMouseDown;
- } KeyData;
- Gwen::Point MousePosition;
- static float g_fLastClickTime[MAX_MOUSE_BUTTONS];
- static Gwen::Point g_pntLastClickPos;
- enum
- {
- ACT_MOUSEMOVE,
- ACT_MOUSEBUTTON,
- ACT_CHAR,
- ACT_MOUSEWHEEL,
- ACT_KEYPRESS,
- ACT_KEYRELEASE,
- ACT_MESSAGE
- };
- void UpdateHoveredControl( Controls::Base* pInCanvas )
- {
- Controls::Base* pHovered = pInCanvas->GetControlAt( MousePosition.x, MousePosition.y );
- if ( Gwen::HoveredControl && pHovered != Gwen::HoveredControl )
- {
- Gwen::HoveredControl->OnMouseLeave();
- pInCanvas->Redraw();
- }
- if ( pHovered != Gwen::HoveredControl )
- {
- Gwen::HoveredControl = pHovered;
- if ( Gwen::HoveredControl )
- Gwen::HoveredControl->OnMouseEnter();
- pInCanvas->Redraw();
- }
- if ( Gwen::MouseFocus && Gwen::MouseFocus->GetCanvas() == pInCanvas )
- {
- Gwen::HoveredControl = Gwen::MouseFocus;
- }
- }
- void FindKeyboardFocus( Controls::Base* pControl )
- {
- if ( !pControl ) return;
- if ( pControl->GetKeyboardInputEnabled() )
- {
- //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;
- if ( pChild == Gwen::KeyboardFocus )
- return;
- }
- pControl->Focus();
- return;
- }
- return FindKeyboardFocus( pControl->GetParent() );
- }
- Gwen::Point Gwen::Input::GetMousePosition()
- {
- return MousePosition;
- }
- void Gwen::Input::OnCanvasThink( Controls::Base* pControl )
- {
- if ( Gwen::MouseFocus && !Gwen::MouseFocus->Visible() )
- Gwen::MouseFocus = NULL;
-
- if (Gwen::KeyboardFocus )
- {
- bool isVisible = Gwen::KeyboardFocus->Visible();
- bool isEnabled = KeyboardFocus->GetKeyboardInputEnabled();
- if ( !isVisible || !isEnabled )
- Gwen::KeyboardFocus = NULL;
- }
- if ( !KeyboardFocus ) return;
- if ( KeyboardFocus->GetCanvas() != pControl ) return;
- float fTime = Gwen::Platform::GetTimeInSeconds();
- //
- // Simulate Key-Repeats
- //
- for ( int i=0; i<Gwen::Key::Count; i++ )
- {
- if ( KeyData.KeyState[i] && KeyData.Target != KeyboardFocus )
- {
- KeyData.KeyState[i] = false;
- continue;
- }
- if ( KeyData.KeyState[i] && fTime > KeyData.NextRepeat[i] )
- {
- KeyData.NextRepeat[i] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatRate;
- if ( KeyboardFocus )
- {
- KeyboardFocus->OnKeyPress( i );
- }
- }
- }
- }
- bool Gwen::Input::IsKeyDown( int iKey )
- {
- return KeyData.KeyState[ iKey ];
- }
- bool Gwen::Input::IsLeftMouseDown()
- {
- return KeyData.LeftMouseDown;
- }
- bool Gwen::Input::IsRightMouseDown()
- {
- return KeyData.RightMouseDown;
- }
- void Gwen::Input::OnMouseMoved( Controls::Base* pCanvas, int x, int y, int /*deltaX*/, int /*deltaY*/ )
- {
- MousePosition.x = x;
- MousePosition.y = y;
- UpdateHoveredControl( pCanvas );
- }
- bool Gwen::Input::OnMouseClicked( Controls::Base* pCanvas, int iMouseButton, bool bDown )
- {
- // 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.
- if ( bDown && (!Gwen::HoveredControl || !Gwen::HoveredControl->IsMenuComponent()) )
- {
- pCanvas->CloseMenus();
- }
- if ( !Gwen::HoveredControl ) return false;
- if ( Gwen::HoveredControl->GetCanvas() != pCanvas ) return false;
- if ( !Gwen::HoveredControl->Visible() ) return false;
- if ( Gwen::HoveredControl == pCanvas ) return false;
- if ( iMouseButton > MAX_MOUSE_BUTTONS )
- return false;
- if ( iMouseButton == 0 ) KeyData.LeftMouseDown = bDown;
- else if ( iMouseButton == 1 ) KeyData.RightMouseDown = bDown;
- // Double click.
- // Todo: Shouldn't double click if mouse has moved significantly
- bool bIsDoubleClick = false;
- if ( bDown &&
- g_pntLastClickPos.x == MousePosition.x &&
- g_pntLastClickPos.y == MousePosition.y &&
- ( Gwen::Platform::GetTimeInSeconds() - g_fLastClickTime[ iMouseButton ] ) < DOUBLE_CLICK_SPEED )
- {
- bIsDoubleClick = true;
- }
- if ( bDown && !bIsDoubleClick )
- {
- g_fLastClickTime[ iMouseButton ] = Gwen::Platform::GetTimeInSeconds();
- g_pntLastClickPos = MousePosition;
- }
- if ( bDown )
- {
- FindKeyboardFocus( Gwen::HoveredControl );
- }
- 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.
- if ( bDown )
- Gwen::HoveredControl->Touch();
- #ifdef GWEN_HOOKSYSTEM
- if ( bDown )
- {
- if ( Hook::CallHook( &Hook::BaseHook::OnControlClicked, Gwen::HoveredControl, MousePosition.x, MousePosition.y ) )
- return true;
- }
- #endif
- switch ( iMouseButton )
- {
- case 0:
- {
- if ( DragAndDrop::OnMouseButton( Gwen::HoveredControl, MousePosition.x, MousePosition.y, bDown ) )
- return true;
- if ( bIsDoubleClick ) Gwen::HoveredControl->OnMouseDoubleClickLeft( MousePosition.x, MousePosition.y );
- else Gwen::HoveredControl->OnMouseClickLeft( MousePosition.x, MousePosition.y, bDown );
- return true;
- }
- case 1:
- {
- if ( bIsDoubleClick ) Gwen::HoveredControl->OnMouseDoubleClickRight( MousePosition.x, MousePosition.y );
- else Gwen::HoveredControl->OnMouseClickRight( MousePosition.x, MousePosition.y, bDown );
- return true;
- }
- }
- return false;
- }
- bool Gwen::Input::HandleAccelerator( Controls::Base* pCanvas, Gwen::UnicodeChar chr )
- {
- //Build the accelerator search string
- Gwen::UnicodeString accelString;
- if ( Gwen::Input::IsControlDown() )
- accelString += L"Ctrl + ";
- if ( Gwen::Input::IsShiftDown() )
- accelString += L"Shift + ";
- accelString += chr;
- //Debug::Msg("Accelerator string :%S\n", accelString.c_str());
- if ( Gwen::KeyboardFocus && Gwen::KeyboardFocus->HandleAccelerator( accelString ) )
- return true;
- if ( Gwen::MouseFocus && Gwen::MouseFocus->HandleAccelerator( accelString ) )
- return true;
- if ( pCanvas->HandleAccelerator( accelString ) )
- return true;
- return false;
- }
- bool Gwen::Input::DoSpecialKeys( Controls::Base* pCanvas, Gwen::UnicodeChar chr )
- {
- if ( !Gwen::KeyboardFocus ) return false;
- if ( Gwen::KeyboardFocus->GetCanvas() != pCanvas ) return false;
- if ( !Gwen::KeyboardFocus->Visible() ) return false;
- if ( !Gwen::Input::IsControlDown() ) return false;
- if ( chr == L'C' || chr == L'c' )
- {
- Gwen::KeyboardFocus->OnCopy(NULL);
- return true;
- }
- if ( chr == L'V' || chr == L'v' )
- {
- Gwen::KeyboardFocus->OnPaste(NULL);
- return true;
- }
- if ( chr == L'X' || chr == L'x' )
- {
- Gwen::KeyboardFocus->OnCut(NULL);
- return true;
- }
- if ( chr == L'A' || chr == L'a' )
- {
- Gwen::KeyboardFocus->OnSelectAll(NULL);
- return true;
- }
-
- return false;
- }
- bool Gwen::Input::OnKeyEvent( Controls::Base* pCanvas, int iKey, bool bDown )
- {
- if ( !Gwen::KeyboardFocus ) return false;
- if ( Gwen::KeyboardFocus->GetCanvas() != pCanvas ) return false;
- if ( !Gwen::KeyboardFocus->Visible() ) return false;
- if ( bDown )
- {
- if ( !KeyData.KeyState[ iKey ] )
- {
- KeyData.KeyState[ iKey ] = true;
- KeyData.NextRepeat[ iKey ] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatDelay;
- KeyData.Target = KeyboardFocus;
- return KeyboardFocus->OnKeyPress( iKey );
- }
- }
- else
- {
- if ( KeyData.KeyState[ iKey ] )
- {
- KeyData.KeyState[ iKey ] = false;
- // BUG BUG. This causes shift left arrow in textboxes
- // to not work. What is disabling it here breaking?
- //KeyData.Target = NULL;
- return KeyboardFocus->OnKeyRelease( iKey );
- }
- }
-
- return false;
- }
|