inputhandler.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. GWEN
  3. Copyright (c) 2010 Facepunch Studios
  4. See license in Gwen.h
  5. */
  6. #include "Gwen/InputHandler.h"
  7. #include "Gwen/Controls/Base.h"
  8. #include "Gwen/DragAndDrop.h"
  9. #include "Gwen/Hook.h"
  10. #include "Gwen/Platform.h"
  11. #define DOUBLE_CLICK_SPEED 0.5f
  12. #define MAX_MOUSE_BUTTONS 5
  13. using namespace Gwen;
  14. struct Action
  15. {
  16. unsigned char type;
  17. int x, y;
  18. Gwen::UnicodeChar chr;
  19. };
  20. static const float KeyRepeatRate = 0.03f;
  21. static const float KeyRepeatDelay = 0.3f;
  22. struct t_KeyData
  23. {
  24. t_KeyData()
  25. {
  26. for ( int i=0; i<Gwen::Key::Count; i++ )
  27. {
  28. KeyState[i] = false;
  29. NextRepeat[i] = 0;
  30. }
  31. Target = NULL;
  32. LeftMouseDown = false;
  33. RightMouseDown = false;
  34. }
  35. bool KeyState[ Gwen::Key::Count ];
  36. float NextRepeat[ Gwen::Key::Count ];
  37. Controls::Base* Target;
  38. bool LeftMouseDown;
  39. bool RightMouseDown;
  40. } KeyData;
  41. Gwen::Point MousePosition;
  42. static float g_fLastClickTime[MAX_MOUSE_BUTTONS];
  43. static Gwen::Point g_pntLastClickPos;
  44. enum
  45. {
  46. ACT_MOUSEMOVE,
  47. ACT_MOUSEBUTTON,
  48. ACT_CHAR,
  49. ACT_MOUSEWHEEL,
  50. ACT_KEYPRESS,
  51. ACT_KEYRELEASE,
  52. ACT_MESSAGE
  53. };
  54. void UpdateHoveredControl( Controls::Base* pInCanvas )
  55. {
  56. Controls::Base* pHovered = pInCanvas->GetControlAt( MousePosition.x, MousePosition.y );
  57. if ( Gwen::HoveredControl && pHovered != Gwen::HoveredControl )
  58. {
  59. Gwen::HoveredControl->OnMouseLeave();
  60. pInCanvas->Redraw();
  61. }
  62. if ( pHovered != Gwen::HoveredControl )
  63. {
  64. Gwen::HoveredControl = pHovered;
  65. if ( Gwen::HoveredControl )
  66. Gwen::HoveredControl->OnMouseEnter();
  67. pInCanvas->Redraw();
  68. }
  69. if ( Gwen::MouseFocus && Gwen::MouseFocus->GetCanvas() == pInCanvas )
  70. {
  71. Gwen::HoveredControl = Gwen::MouseFocus;
  72. }
  73. }
  74. void FindKeyboardFocus( Controls::Base* pControl )
  75. {
  76. if ( !pControl ) return;
  77. if ( pControl->GetKeyboardInputEnabled() )
  78. {
  79. //Make sure none of our children have keyboard focus first - todo recursive
  80. for (Controls::Base::List::iterator iter = pControl->Children.begin(); iter != pControl->Children.end(); ++iter)
  81. {
  82. Controls::Base* pChild = *iter;
  83. if ( pChild == Gwen::KeyboardFocus )
  84. return;
  85. }
  86. pControl->Focus();
  87. return;
  88. }
  89. return FindKeyboardFocus( pControl->GetParent() );
  90. }
  91. Gwen::Point Gwen::Input::GetMousePosition()
  92. {
  93. return MousePosition;
  94. }
  95. void Gwen::Input::OnCanvasThink( Controls::Base* pControl )
  96. {
  97. if ( Gwen::MouseFocus && !Gwen::MouseFocus->Visible() )
  98. Gwen::MouseFocus = NULL;
  99. if (Gwen::KeyboardFocus )
  100. {
  101. bool isVisible = Gwen::KeyboardFocus->Visible();
  102. bool isEnabled = KeyboardFocus->GetKeyboardInputEnabled();
  103. if ( !isVisible || !isEnabled )
  104. Gwen::KeyboardFocus = NULL;
  105. }
  106. if ( !KeyboardFocus ) return;
  107. if ( KeyboardFocus->GetCanvas() != pControl ) return;
  108. float fTime = Gwen::Platform::GetTimeInSeconds();
  109. //
  110. // Simulate Key-Repeats
  111. //
  112. for ( int i=0; i<Gwen::Key::Count; i++ )
  113. {
  114. if ( KeyData.KeyState[i] && KeyData.Target != KeyboardFocus )
  115. {
  116. KeyData.KeyState[i] = false;
  117. continue;
  118. }
  119. if ( KeyData.KeyState[i] && fTime > KeyData.NextRepeat[i] )
  120. {
  121. KeyData.NextRepeat[i] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatRate;
  122. if ( KeyboardFocus )
  123. {
  124. KeyboardFocus->OnKeyPress( i );
  125. }
  126. }
  127. }
  128. }
  129. bool Gwen::Input::IsKeyDown( int iKey )
  130. {
  131. return KeyData.KeyState[ iKey ];
  132. }
  133. bool Gwen::Input::IsLeftMouseDown()
  134. {
  135. return KeyData.LeftMouseDown;
  136. }
  137. bool Gwen::Input::IsRightMouseDown()
  138. {
  139. return KeyData.RightMouseDown;
  140. }
  141. void Gwen::Input::OnMouseMoved( Controls::Base* pCanvas, int x, int y, int /*deltaX*/, int /*deltaY*/ )
  142. {
  143. MousePosition.x = x;
  144. MousePosition.y = y;
  145. UpdateHoveredControl( pCanvas );
  146. }
  147. bool Gwen::Input::OnMouseClicked( Controls::Base* pCanvas, int iMouseButton, bool bDown )
  148. {
  149. // If we click on a control that isn't a menu we want to close
  150. // all the open menus. Menus are children of the canvas.
  151. if ( bDown && (!Gwen::HoveredControl || !Gwen::HoveredControl->IsMenuComponent()) )
  152. {
  153. pCanvas->CloseMenus();
  154. }
  155. if ( !Gwen::HoveredControl ) return false;
  156. if ( Gwen::HoveredControl->GetCanvas() != pCanvas ) return false;
  157. if ( !Gwen::HoveredControl->Visible() ) return false;
  158. if ( Gwen::HoveredControl == pCanvas ) return false;
  159. if ( iMouseButton > MAX_MOUSE_BUTTONS )
  160. return false;
  161. if ( iMouseButton == 0 ) KeyData.LeftMouseDown = bDown;
  162. else if ( iMouseButton == 1 ) KeyData.RightMouseDown = bDown;
  163. // Double click.
  164. // Todo: Shouldn't double click if mouse has moved significantly
  165. bool bIsDoubleClick = false;
  166. if ( bDown &&
  167. g_pntLastClickPos.x == MousePosition.x &&
  168. g_pntLastClickPos.y == MousePosition.y &&
  169. ( Gwen::Platform::GetTimeInSeconds() - g_fLastClickTime[ iMouseButton ] ) < DOUBLE_CLICK_SPEED )
  170. {
  171. bIsDoubleClick = true;
  172. }
  173. if ( bDown && !bIsDoubleClick )
  174. {
  175. g_fLastClickTime[ iMouseButton ] = Gwen::Platform::GetTimeInSeconds();
  176. g_pntLastClickPos = MousePosition;
  177. }
  178. if ( bDown )
  179. {
  180. FindKeyboardFocus( Gwen::HoveredControl );
  181. }
  182. Gwen::HoveredControl->UpdateCursor();
  183. // This tells the child it has been touched, which
  184. // in turn tells its parents, who tell their parents.
  185. // This is basically so that Windows can pop themselves
  186. // to the top when one of their children have been clicked.
  187. if ( bDown )
  188. Gwen::HoveredControl->Touch();
  189. #ifdef GWEN_HOOKSYSTEM
  190. if ( bDown )
  191. {
  192. if ( Hook::CallHook( &Hook::BaseHook::OnControlClicked, Gwen::HoveredControl, MousePosition.x, MousePosition.y ) )
  193. return true;
  194. }
  195. #endif
  196. switch ( iMouseButton )
  197. {
  198. case 0:
  199. {
  200. if ( DragAndDrop::OnMouseButton( Gwen::HoveredControl, MousePosition.x, MousePosition.y, bDown ) )
  201. return true;
  202. if ( bIsDoubleClick ) Gwen::HoveredControl->OnMouseDoubleClickLeft( MousePosition.x, MousePosition.y );
  203. else Gwen::HoveredControl->OnMouseClickLeft( MousePosition.x, MousePosition.y, bDown );
  204. return true;
  205. }
  206. case 1:
  207. {
  208. if ( bIsDoubleClick ) Gwen::HoveredControl->OnMouseDoubleClickRight( MousePosition.x, MousePosition.y );
  209. else Gwen::HoveredControl->OnMouseClickRight( MousePosition.x, MousePosition.y, bDown );
  210. return true;
  211. }
  212. }
  213. return false;
  214. }
  215. bool Gwen::Input::HandleAccelerator( Controls::Base* pCanvas, Gwen::UnicodeChar chr )
  216. {
  217. //Build the accelerator search string
  218. Gwen::UnicodeString accelString;
  219. if ( Gwen::Input::IsControlDown() )
  220. accelString += L"Ctrl + ";
  221. if ( Gwen::Input::IsShiftDown() )
  222. accelString += L"Shift + ";
  223. accelString += chr;
  224. //Debug::Msg("Accelerator string :%S\n", accelString.c_str());
  225. if ( Gwen::KeyboardFocus && Gwen::KeyboardFocus->HandleAccelerator( accelString ) )
  226. return true;
  227. if ( Gwen::MouseFocus && Gwen::MouseFocus->HandleAccelerator( accelString ) )
  228. return true;
  229. if ( pCanvas->HandleAccelerator( accelString ) )
  230. return true;
  231. return false;
  232. }
  233. bool Gwen::Input::DoSpecialKeys( Controls::Base* pCanvas, Gwen::UnicodeChar chr )
  234. {
  235. if ( !Gwen::KeyboardFocus ) return false;
  236. if ( Gwen::KeyboardFocus->GetCanvas() != pCanvas ) return false;
  237. if ( !Gwen::KeyboardFocus->Visible() ) return false;
  238. if ( !Gwen::Input::IsControlDown() ) return false;
  239. if ( chr == L'C' || chr == L'c' )
  240. {
  241. Gwen::KeyboardFocus->OnCopy(NULL);
  242. return true;
  243. }
  244. if ( chr == L'V' || chr == L'v' )
  245. {
  246. Gwen::KeyboardFocus->OnPaste(NULL);
  247. return true;
  248. }
  249. if ( chr == L'X' || chr == L'x' )
  250. {
  251. Gwen::KeyboardFocus->OnCut(NULL);
  252. return true;
  253. }
  254. if ( chr == L'A' || chr == L'a' )
  255. {
  256. Gwen::KeyboardFocus->OnSelectAll(NULL);
  257. return true;
  258. }
  259. return false;
  260. }
  261. bool Gwen::Input::OnKeyEvent( Controls::Base* pCanvas, int iKey, bool bDown )
  262. {
  263. if ( !Gwen::KeyboardFocus ) return false;
  264. if ( Gwen::KeyboardFocus->GetCanvas() != pCanvas ) return false;
  265. if ( !Gwen::KeyboardFocus->Visible() ) return false;
  266. if ( bDown )
  267. {
  268. if ( !KeyData.KeyState[ iKey ] )
  269. {
  270. KeyData.KeyState[ iKey ] = true;
  271. KeyData.NextRepeat[ iKey ] = Gwen::Platform::GetTimeInSeconds() + KeyRepeatDelay;
  272. KeyData.Target = KeyboardFocus;
  273. return KeyboardFocus->OnKeyPress( iKey );
  274. }
  275. }
  276. else
  277. {
  278. if ( KeyData.KeyState[ iKey ] )
  279. {
  280. KeyData.KeyState[ iKey ] = false;
  281. // BUG BUG. This causes shift left arrow in textboxes
  282. // to not work. What is disabling it here breaking?
  283. //KeyData.Target = NULL;
  284. return KeyboardFocus->OnKeyRelease( iKey );
  285. }
  286. }
  287. return false;
  288. }