/* GWEN Copyright (c) 2010 Facepunch Studios See license in Gwen.h */ #include "gwen_inputhandler.h" #include "controls/gwen_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; char chr; }; static const float KeyRepeatRate = 0.03f; static const float KeyRepeatDelay = 0.3f; struct t_KeyData { t_KeyData() { for ( int i=0; iGetControlAt( MousePosition.x, MousePosition.y ); if ( pHovered != Gwen::HoveredControl ) { if ( Gwen::HoveredControl ) { Controls::Base* OldHover = Gwen::HoveredControl; Gwen::HoveredControl = NULL; OldHover->OnMouseLeave(); } Gwen::HoveredControl = pHovered; if ( Gwen::HoveredControl ) { Gwen::HoveredControl->OnMouseEnter(); } } if ( Gwen::MouseFocus && Gwen::MouseFocus->GetCanvas() == pInCanvas ) { if ( Gwen::HoveredControl ) { Controls::Base* OldHover = Gwen::HoveredControl; Gwen::HoveredControl = NULL; OldHover->Redraw(); } 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 && ( !Gwen::KeyboardFocus->Visible() || !KeyboardFocus->GetKeyboardInputEnabled() ) ) Gwen::KeyboardFocus = NULL; if ( !KeyboardFocus ) return; if ( KeyboardFocus->GetCanvas() != pControl ) return; float fTime = Gwen::Platform::GetTimeInSeconds(); // // Simulate Key-Repeats // for ( int i=0; i 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, char chr ) { //Build the accelerator search string Gwen::String accelString; if ( Gwen::Input::IsControlDown() ) accelString += "CTRL+"; if ( Gwen::Input::IsShiftDown() ) accelString += "SHIFT+"; chr = toupper( chr ); 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, char 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 == 'C' || chr == 'c' ) { Gwen::KeyboardFocus->OnCopy(NULL); return true; } if ( chr == 'V' || chr == 'v' ) { Gwen::KeyboardFocus->OnPaste(NULL); return true; } if ( chr == 'X' || chr == 'x' ) { Gwen::KeyboardFocus->OnCut(NULL); return true; } if ( chr == 'A' || chr == 'a' ) { Gwen::KeyboardFocus->OnSelectAll(NULL); return true; } return false; } bool Gwen::Input::OnKeyEvent( Controls::Base* pCanvas, int iKey, bool bDown ) { Gwen::Controls::Base* pTarget = Gwen::KeyboardFocus; if ( pTarget && pTarget->GetCanvas() != pCanvas ) pTarget = NULL; if ( pTarget && !pTarget->Visible() ) pTarget = NULL; if ( bDown ) { if ( !KeyData.KeyState[ iKey ] ) { KeyData.KeyState[ iKey ] = true; KeyData.NextRepeat[ iKey ] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatDelay; KeyData.Target = pTarget; if ( pTarget ) return pTarget->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; if ( pTarget ) return pTarget->OnKeyRelease( iKey ); } } return false; }