Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3198 lines
93 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #if defined( WIN32 ) && !defined( _X360 )
  8. #include <windows.h>
  9. #include <imm.h>
  10. #define DO_IME
  11. #endif
  12. #include <string.h>
  13. #include "vgui_internal.h"
  14. #include "VPanel.h"
  15. #include "utlvector.h"
  16. #include <KeyValues.h>
  17. #include "tier0/vcrmode.h"
  18. #include <vgui/VGUI.h>
  19. #include <vgui/ISystem.h>
  20. #include <vgui/IClientPanel.h>
  21. #include <vgui/IInputInternal.h>
  22. #include <vgui/IPanel.h>
  23. #include <vgui/ISurface.h>
  24. #include <vgui/IVGui.h>
  25. #include <vgui/KeyCode.h>
  26. #include <vgui/MouseCode.h>
  27. #include "vgui/Cursor.h"
  28. #include <vgui/keyrepeat.h>
  29. #include "utllinkedlist.h"
  30. #include "tier0/icommandline.h"
  31. #if defined( _X360 )
  32. #include "xbox/xbox_win32stubs.h"
  33. #endif
  34. /*
  35. > Subject: RE: l4d2 & motd
  36. >
  37. > From: Alfred Reynolds
  38. > I'd go with the if it ain't broke don't touch it route, might as well
  39. > leave win32 as is and just knobble the asserts where we know we won't implement it.
  40. >
  41. >> From: Mike Sartain
  42. >> Well now that's interesting. Is it ok to remove it for win32 then?
  43. >>
  44. >>> From: Alfred Reynolds
  45. >>> We never did the IME work, AFAIK it only ever worked on the game's
  46. >>> console in game which isn't useful for users. So, no demand, hard
  47. >>> (actually, really hard) to implement so it wasn't done.
  48. >>>
  49. >>>> From: Mike Sartain
  50. >>>> There are also a bunch of IME Language functions in
  51. >>>> vgui2/src/inputwin32.cpp that are NYI on Linux as well - but it looks
  52. >>>> like those haven't ever been implemented on OSX either. Alfred, what
  53. >>>> is the story there?
  54. */
  55. #if 0 // !defined( DO_IME ) && !defined( _X360 )
  56. #define ASSERT_IF_IME_NYI() Assert( !"IME Support NYI" )
  57. #else
  58. #define ASSERT_IF_IME_NYI()
  59. #endif
  60. // memdbgon must be the last include file in a .cpp file!!!
  61. #include "tier0/memdbgon.h"
  62. bool IsDispatchingMessageQueue( void );
  63. using namespace vgui;
  64. class CInputSystem : public IInputInternal
  65. {
  66. public:
  67. CInputSystem();
  68. ~CInputSystem();
  69. virtual void RunFrame();
  70. virtual void PanelDeleted(VPANEL panel);
  71. virtual void UpdateMouseFocus(int x, int y);
  72. virtual void SetMouseFocus(VPANEL newMouseFocus);
  73. virtual void SetCursorPos(int x, int y);
  74. virtual void UpdateCursorPosInternal( int x, int y );
  75. virtual void GetCursorPos(int &x, int &y);
  76. virtual void SetCursorOveride(HCursor cursor);
  77. virtual HCursor GetCursorOveride();
  78. virtual void SetMouseCapture(VPANEL panel);
  79. virtual VPANEL GetFocus();
  80. virtual VPANEL GetCalculatedFocus();
  81. virtual VPANEL GetMouseOver();
  82. virtual bool WasMousePressed(MouseCode code);
  83. virtual bool WasMouseDoublePressed(MouseCode code);
  84. virtual bool IsMouseDown(MouseCode code);
  85. virtual bool WasMouseReleased(MouseCode code);
  86. virtual bool WasKeyPressed(KeyCode code);
  87. virtual bool IsKeyDown(KeyCode code);
  88. virtual bool WasKeyTyped(KeyCode code);
  89. virtual bool WasKeyReleased(KeyCode code);
  90. virtual void GetKeyCodeText(KeyCode code, char *buf, int buflen);
  91. virtual bool InternalCursorMoved(int x,int y); //expects input in surface space
  92. virtual bool InternalMousePressed(MouseCode code);
  93. virtual bool InternalMouseDoublePressed(MouseCode code);
  94. virtual bool InternalMouseReleased(MouseCode code);
  95. virtual bool InternalMouseWheeled(int delta);
  96. virtual bool InternalKeyCodePressed(KeyCode code);
  97. virtual void InternalKeyCodeTyped(KeyCode code);
  98. virtual void InternalKeyTyped(wchar_t unichar);
  99. virtual bool InternalKeyCodeReleased(KeyCode code);
  100. virtual void SetKeyCodeState( KeyCode code, bool bPressed );
  101. virtual void SetMouseCodeState( MouseCode code, MouseCodeState_t state );
  102. virtual void UpdateButtonState( const InputEvent_t &event );
  103. virtual VPANEL GetAppModalSurface();
  104. // set the modal dialog panel.
  105. // all events will go only to this panel and its children.
  106. virtual void SetAppModalSurface(VPANEL panel);
  107. // release the modal dialog panel
  108. // do this when your modal dialog finishes.
  109. virtual void ReleaseAppModalSurface();
  110. // returns true if the specified panel is a child of the current modal panel
  111. // if no modal panel is set, then this always returns TRUE
  112. virtual bool IsChildOfModalPanel(VPANEL panel, bool checkModalSubTree = true );
  113. // Creates/ destroys "input" contexts, which contains information
  114. // about which controls have mouse + key focus, for example.
  115. virtual HInputContext CreateInputContext();
  116. virtual void DestroyInputContext( HInputContext context );
  117. // Associates a particular panel with an input context
  118. // Associating NULL is valid; it disconnects the panel from the context
  119. virtual void AssociatePanelWithInputContext( HInputContext context, VPANEL pRoot );
  120. // Activates a particular input context, use DEFAULT_INPUT_CONTEXT
  121. // to get the one normally used by VGUI
  122. virtual void ActivateInputContext( HInputContext context );
  123. virtual void PostCursorMessage( );
  124. virtual void HandleExplicitSetCursor( );
  125. virtual void ResetInputContext( HInputContext context );
  126. virtual void GetCursorPosition( int &x, int &y );
  127. virtual void SetIMEWindow( void *hwnd );
  128. virtual void *GetIMEWindow();
  129. // Change keyboard layout type
  130. virtual void OnChangeIME( bool forward );
  131. virtual int GetCurrentIMEHandle();
  132. virtual int GetEnglishIMEHandle();
  133. // Returns the Language Bar label (Chinese, Korean, Japanese, Russion, Thai, etc.)
  134. virtual void GetIMELanguageName( wchar_t *buf, int unicodeBufferSizeInBytes );
  135. // Returns the short code for the language (EN, CH, KO, JP, RU, TH, etc. ).
  136. virtual void GetIMELanguageShortCode( wchar_t *buf, int unicodeBufferSizeInBytes );
  137. // Call with NULL dest to get item count
  138. virtual int GetIMELanguageList( LanguageItem *dest, int destcount );
  139. virtual int GetIMEConversionModes( ConversionModeItem *dest, int destcount );
  140. virtual int GetIMESentenceModes( SentenceModeItem *dest, int destcount );
  141. virtual void OnChangeIMEByHandle( int handleValue );
  142. virtual void OnChangeIMEConversionModeByHandle( int handleValue );
  143. virtual void OnChangeIMESentenceModeByHandle( int handleValue );
  144. virtual void OnInputLanguageChanged();
  145. virtual void OnIMEStartComposition();
  146. virtual void OnIMEComposition( int flags );
  147. virtual void OnIMEEndComposition();
  148. virtual void OnIMEShowCandidates();
  149. virtual void OnIMEChangeCandidates();
  150. virtual void OnIMECloseCandidates();
  151. virtual void OnIMERecomputeModes();
  152. virtual int GetCandidateListCount();
  153. virtual void GetCandidate( int num, wchar_t *dest, int destSizeBytes );
  154. virtual int GetCandidateListSelectedItem();
  155. virtual int GetCandidateListPageSize();
  156. virtual int GetCandidateListPageStart();
  157. virtual void SetCandidateWindowPos( int x, int y );
  158. virtual bool GetShouldInvertCompositionString();
  159. virtual bool CandidateListStartsAtOne();
  160. virtual void SetCandidateListPageStart( int start );
  161. // Passes in a keycode which allows hitting other mouse buttons w/o cancelling capture mode
  162. virtual void SetMouseCaptureEx(VPANEL panel, MouseCode captureStartMouseCode );
  163. virtual void RegisterKeyCodeUnhandledListener( VPANEL panel );
  164. virtual void UnregisterKeyCodeUnhandledListener( VPANEL panel );
  165. // Posts unhandled message to all interested panels
  166. virtual void OnKeyCodeUnhandled( int keyCode );
  167. // Assumes subTree is a child panel of the root panel for the vgui contect
  168. // if restrictMessagesToSubTree is true, then mouse and kb messages are only routed to the subTree and it's children and mouse/kb focus
  169. // can only be on one of the subTree children, if a mouse click occurs outside of the subtree, and "UnhandledMouseClick" message is sent to unhandledMouseClickListener panel
  170. // if it's set
  171. // if restrictMessagesToSubTree is false, then mouse and kb messages are routed as normal except that they are not routed down into the subtree
  172. // however, if a mouse click occurs outside of the subtree, and "UnhandleMouseClick" message is sent to unhandledMouseClickListener panel
  173. // if it's set
  174. virtual void SetModalSubTree( VPANEL subTree, VPANEL unhandledMouseClickListener, bool restrictMessagesToSubTree = true );
  175. virtual void ReleaseModalSubTree();
  176. virtual VPANEL GetModalSubTree();
  177. // These toggle whether the modal subtree is exclusively receiving messages or conversely whether it's being excluded from receiving messages
  178. virtual void SetModalSubTreeReceiveMessages( bool state );
  179. virtual bool ShouldModalSubTreeReceiveMessages() const;
  180. virtual VPANEL GetMouseCapture();
  181. virtual VPANEL GetMouseFocus();
  182. private:
  183. VPanel *GetMouseFocusIgnoringModalSubtree();
  184. void InternalSetCompositionString( const wchar_t *compstr );
  185. void InternalShowCandidateWindow();
  186. void InternalHideCandidateWindow();
  187. void InternalUpdateCandidateWindow();
  188. bool PostKeyMessage(KeyValues *message);
  189. void DestroyCandidateList();
  190. void CreateNewCandidateList();
  191. VPanel *CalculateNewKeyFocus();
  192. void PostModalSubTreeMessage( VPanel *subTree, bool state );
  193. // returns true if the specified panel is a child of the current modal panel
  194. // if no modal panel is set, then this always returns TRUE
  195. bool IsChildOfModalSubTree(VPANEL panel);
  196. void SurfaceSetCursorPos( int x, int y );
  197. void SurfaceGetCursorPos( int &x, int &y );
  198. struct InputContext_t
  199. {
  200. VPANEL _rootPanel;
  201. bool _mousePressed[MOUSE_COUNT];
  202. bool _mouseDoublePressed[MOUSE_COUNT];
  203. bool _mouseDown[MOUSE_COUNT];
  204. bool _mouseReleased[MOUSE_COUNT];
  205. bool _keyPressed[BUTTON_CODE_COUNT];
  206. bool _keyTyped[BUTTON_CODE_COUNT];
  207. bool _keyDown[BUTTON_CODE_COUNT];
  208. bool _keyReleased[BUTTON_CODE_COUNT];
  209. VPanel *_keyFocus;
  210. VPanel *_oldMouseFocus;
  211. VPanel *_mouseFocus; // the panel that has the current mouse focus - same as _mouseOver unless _mouseCapture is set
  212. VPanel *_mouseOver; // the panel that the mouse is currently over, NULL if not over any vgui item
  213. VPanel *_mouseCapture; // the panel that has currently captured mouse focus
  214. MouseCode m_MouseCaptureStartCode; // The Mouse button which was pressed to initiate mouse capture
  215. VPanel *_appModalPanel; // the modal dialog panel.
  216. int m_nCursorX;
  217. int m_nCursorY;
  218. int m_nLastPostedCursorX;
  219. int m_nLastPostedCursorY;
  220. int m_nExternallySetCursorX;
  221. int m_nExternallySetCursorY;
  222. bool m_bSetCursorExplicitly;
  223. CUtlVector< VPanel * > m_KeyCodeUnhandledListeners;
  224. VPanel *m_pModalSubTree;
  225. VPanel *m_pUnhandledMouseClickListener;
  226. bool m_bRestrictMessagesToModalSubTree;
  227. CKeyRepeatHandler m_keyRepeater;
  228. };
  229. void InitInputContext( InputContext_t *pContext );
  230. InputContext_t *GetInputContext( HInputContext context );
  231. void PanelDeleted(VPANEL focus, InputContext_t &context);
  232. HCursor _cursorOverride;
  233. const char *_keyTrans[KEY_LAST];
  234. InputContext_t m_DefaultInputContext;
  235. HInputContext m_hContext; // current input context
  236. CUtlLinkedList< InputContext_t, HInputContext > m_Contexts;
  237. #ifdef DO_IME
  238. void *_imeWnd;
  239. CANDIDATELIST *_imeCandidates;
  240. #endif
  241. int m_nDebugMessages;
  242. };
  243. CInputSystem g_Input;
  244. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CInputSystem, IInput, VGUI_INPUT_INTERFACE_VERSION, g_Input); // export IInput to everyone else, not IInputInternal!
  245. EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CInputSystem, IInputInternal, VGUI_INPUTINTERNAL_INTERFACE_VERSION, g_Input); // for use in external surfaces only! (like the engine surface)
  246. namespace vgui
  247. {
  248. vgui::IInputInternal *g_pInput = &g_Input;
  249. }
  250. CInputSystem::CInputSystem()
  251. {
  252. m_nDebugMessages = -1;
  253. #ifdef DO_IME
  254. _imeWnd = null;
  255. _imeCandidates = null;
  256. #endif
  257. InitInputContext( &m_DefaultInputContext );
  258. m_hContext = DEFAULT_INPUT_CONTEXT;
  259. // build key to text translation table
  260. // first byte unshifted key
  261. // second byte shifted key
  262. // the rest is the name of the key
  263. _keyTrans[KEY_0] ="0)KEY_0";
  264. _keyTrans[KEY_1] ="1!KEY_1";
  265. _keyTrans[KEY_2] ="2@KEY_2";
  266. _keyTrans[KEY_3] ="3#KEY_3";
  267. _keyTrans[KEY_4] ="4$KEY_4";
  268. _keyTrans[KEY_5] ="5%KEY_5";
  269. _keyTrans[KEY_6] ="6^KEY_6";
  270. _keyTrans[KEY_7] ="7&KEY_7";
  271. _keyTrans[KEY_8] ="8*KEY_8";
  272. _keyTrans[KEY_9] ="9(KEY_9";
  273. _keyTrans[KEY_A] ="aAKEY_A";
  274. _keyTrans[KEY_B] ="bBKEY_B";
  275. _keyTrans[KEY_C] ="cCKEY_C";
  276. _keyTrans[KEY_D] ="dDKEY_D";
  277. _keyTrans[KEY_E] ="eEKEY_E";
  278. _keyTrans[KEY_F] ="fFKEY_F";
  279. _keyTrans[KEY_G] ="gGKEY_G";
  280. _keyTrans[KEY_H] ="hHKEY_H";
  281. _keyTrans[KEY_I] ="iIKEY_I";
  282. _keyTrans[KEY_J] ="jJKEY_J";
  283. _keyTrans[KEY_K] ="kKKEY_K";
  284. _keyTrans[KEY_L] ="lLKEY_L"", L";
  285. _keyTrans[KEY_M] ="mMKEY_M";
  286. _keyTrans[KEY_N] ="nNKEY_N";
  287. _keyTrans[KEY_O] ="oOKEY_O";
  288. _keyTrans[KEY_P] ="pPKEY_P";
  289. _keyTrans[KEY_Q] ="qQKEY_Q";
  290. _keyTrans[KEY_R] ="rRKEY_R";
  291. _keyTrans[KEY_S] ="sSKEY_S";
  292. _keyTrans[KEY_T] ="tTKEY_T";
  293. _keyTrans[KEY_U] ="uUKEY_U";
  294. _keyTrans[KEY_V] ="vVKEY_V";
  295. _keyTrans[KEY_W] ="wWKEY_W";
  296. _keyTrans[KEY_X] ="xXKEY_X";
  297. _keyTrans[KEY_Y] ="yYKEY_Y";
  298. _keyTrans[KEY_Z] ="zZKEY_Z";
  299. _keyTrans[KEY_PAD_0] ="0\0KEY_PAD_0";
  300. _keyTrans[KEY_PAD_1] ="1\0KEY_PAD_1";
  301. _keyTrans[KEY_PAD_2] ="2\0KEY_PAD_2";
  302. _keyTrans[KEY_PAD_3] ="3\0KEY_PAD_3";
  303. _keyTrans[KEY_PAD_4] ="4\0KEY_PAD_4";
  304. _keyTrans[KEY_PAD_5] ="5\0KEY_PAD_5";
  305. _keyTrans[KEY_PAD_6] ="6\0KEY_PAD_6";
  306. _keyTrans[KEY_PAD_7] ="7\0KEY_PAD_7";
  307. _keyTrans[KEY_PAD_8] ="8\0KEY_PAD_8";
  308. _keyTrans[KEY_PAD_9] ="9\0KEY_PAD_9";
  309. _keyTrans[KEY_PAD_DIVIDE] ="//KEY_PAD_DIVIDE";
  310. _keyTrans[KEY_PAD_MULTIPLY] ="**KEY_PAD_MULTIPLY";
  311. _keyTrans[KEY_PAD_MINUS] ="--KEY_PAD_MINUS";
  312. _keyTrans[KEY_PAD_PLUS] ="++KEY_PAD_PLUS";
  313. _keyTrans[KEY_PAD_ENTER] ="\0\0KEY_PAD_ENTER";
  314. _keyTrans[KEY_PAD_DECIMAL] =".\0KEY_PAD_DECIMAL"", L";
  315. _keyTrans[KEY_LBRACKET] ="[{KEY_LBRACKET";
  316. _keyTrans[KEY_RBRACKET] ="]}KEY_RBRACKET";
  317. _keyTrans[KEY_SEMICOLON] =";:KEY_SEMICOLON";
  318. _keyTrans[KEY_APOSTROPHE] ="'\"KEY_APOSTROPHE";
  319. _keyTrans[KEY_BACKQUOTE] ="`~KEY_BACKQUOTE";
  320. _keyTrans[KEY_COMMA] =",<KEY_COMMA";
  321. _keyTrans[KEY_PERIOD] =".>KEY_PERIOD";
  322. _keyTrans[KEY_SLASH] ="/?KEY_SLASH";
  323. _keyTrans[KEY_BACKSLASH] ="\\|KEY_BACKSLASH";
  324. _keyTrans[KEY_MINUS] ="-_KEY_MINUS";
  325. _keyTrans[KEY_EQUAL] ="=+KEY_EQUAL"", L";
  326. _keyTrans[KEY_ENTER] ="\0\0KEY_ENTER";
  327. _keyTrans[KEY_SPACE] =" KEY_SPACE";
  328. _keyTrans[KEY_BACKSPACE] ="\0\0KEY_BACKSPACE";
  329. _keyTrans[KEY_TAB] ="\0\0KEY_TAB";
  330. _keyTrans[KEY_CAPSLOCK] ="\0\0KEY_CAPSLOCK";
  331. _keyTrans[KEY_NUMLOCK] ="\0\0KEY_NUMLOCK";
  332. _keyTrans[KEY_ESCAPE] ="\0\0KEY_ESCAPE";
  333. _keyTrans[KEY_SCROLLLOCK] ="\0\0KEY_SCROLLLOCK";
  334. _keyTrans[KEY_INSERT] ="\0\0KEY_INSERT";
  335. _keyTrans[KEY_DELETE] ="\0\0KEY_DELETE";
  336. _keyTrans[KEY_HOME] ="\0\0KEY_HOME";
  337. _keyTrans[KEY_END] ="\0\0KEY_END";
  338. _keyTrans[KEY_PAGEUP] ="\0\0KEY_PAGEUP";
  339. _keyTrans[KEY_PAGEDOWN] ="\0\0KEY_PAGEDOWN";
  340. _keyTrans[KEY_BREAK] ="\0\0KEY_BREAK";
  341. _keyTrans[KEY_LSHIFT] ="\0\0KEY_LSHIFT";
  342. _keyTrans[KEY_RSHIFT] ="\0\0KEY_RSHIFT";
  343. _keyTrans[KEY_LALT] ="\0\0KEY_LALT";
  344. _keyTrans[KEY_RALT] ="\0\0KEY_RALT";
  345. _keyTrans[KEY_LCONTROL] ="\0\0KEY_LCONTROL"", L";
  346. _keyTrans[KEY_RCONTROL] ="\0\0KEY_RCONTROL"", L";
  347. _keyTrans[KEY_LWIN] ="\0\0KEY_LWIN";
  348. _keyTrans[KEY_RWIN] ="\0\0KEY_RWIN";
  349. _keyTrans[KEY_APP] ="\0\0KEY_APP";
  350. _keyTrans[KEY_UP] ="\0\0KEY_UP";
  351. _keyTrans[KEY_LEFT] ="\0\0KEY_LEFT";
  352. _keyTrans[KEY_DOWN] ="\0\0KEY_DOWN";
  353. _keyTrans[KEY_RIGHT] ="\0\0KEY_RIGHT";
  354. _keyTrans[KEY_F1] ="\0\0KEY_F1";
  355. _keyTrans[KEY_F2] ="\0\0KEY_F2";
  356. _keyTrans[KEY_F3] ="\0\0KEY_F3";
  357. _keyTrans[KEY_F4] ="\0\0KEY_F4";
  358. _keyTrans[KEY_F5] ="\0\0KEY_F5";
  359. _keyTrans[KEY_F6] ="\0\0KEY_F6";
  360. _keyTrans[KEY_F7] ="\0\0KEY_F7";
  361. _keyTrans[KEY_F8] ="\0\0KEY_F8";
  362. _keyTrans[KEY_F9] ="\0\0KEY_F9";
  363. _keyTrans[KEY_F10] ="\0\0KEY_F10";
  364. _keyTrans[KEY_F11] ="\0\0KEY_F11";
  365. _keyTrans[KEY_F12] ="\0\0KEY_F12";
  366. }
  367. CInputSystem::~CInputSystem()
  368. {
  369. DestroyCandidateList();
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Resets an input context
  373. //-----------------------------------------------------------------------------
  374. void CInputSystem::InitInputContext( InputContext_t *pContext )
  375. {
  376. pContext->_rootPanel = NULL;
  377. pContext->_keyFocus = NULL;
  378. pContext->_oldMouseFocus = NULL;
  379. pContext->_mouseFocus = NULL;
  380. pContext->_mouseOver = NULL;
  381. pContext->_mouseCapture = NULL;
  382. pContext->_appModalPanel = NULL;
  383. pContext->m_nCursorX = pContext->m_nCursorY = 0;
  384. pContext->m_nLastPostedCursorX = pContext->m_nLastPostedCursorY = -9999;
  385. pContext->m_nExternallySetCursorX = pContext->m_nExternallySetCursorY = 0;
  386. pContext->m_bSetCursorExplicitly = false;
  387. // zero mouse and keys
  388. memset(pContext->_mousePressed, 0, sizeof(pContext->_mousePressed));
  389. memset(pContext->_mouseDoublePressed, 0, sizeof(pContext->_mouseDoublePressed));
  390. memset(pContext->_mouseDown, 0, sizeof(pContext->_mouseDown));
  391. memset(pContext->_mouseReleased, 0, sizeof(pContext->_mouseReleased));
  392. memset(pContext->_keyPressed, 0, sizeof(pContext->_keyPressed));
  393. memset(pContext->_keyTyped, 0, sizeof(pContext->_keyTyped));
  394. memset(pContext->_keyDown, 0, sizeof(pContext->_keyDown));
  395. memset(pContext->_keyReleased, 0, sizeof(pContext->_keyReleased));
  396. pContext->m_MouseCaptureStartCode = (MouseCode)-1;
  397. pContext->m_KeyCodeUnhandledListeners.RemoveAll();
  398. pContext->m_pModalSubTree = NULL;
  399. pContext->m_pUnhandledMouseClickListener = NULL;
  400. pContext->m_bRestrictMessagesToModalSubTree = false;
  401. }
  402. void CInputSystem::ResetInputContext( HInputContext context )
  403. {
  404. // FIXME: Needs to release various keys, mouse buttons, etc...?
  405. // At least needs to cause things to lose focus
  406. InitInputContext( GetInputContext(context) );
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Creates/ destroys "input" contexts, which contains information
  410. // about which controls have mouse + key focus, for example.
  411. //-----------------------------------------------------------------------------
  412. HInputContext CInputSystem::CreateInputContext()
  413. {
  414. HInputContext i = m_Contexts.AddToTail();
  415. InitInputContext( &m_Contexts[i] );
  416. return i;
  417. }
  418. void CInputSystem::DestroyInputContext( HInputContext context )
  419. {
  420. Assert( context != DEFAULT_INPUT_CONTEXT );
  421. if ( m_hContext == context )
  422. {
  423. ActivateInputContext( DEFAULT_INPUT_CONTEXT );
  424. }
  425. m_Contexts.Remove(context);
  426. }
  427. //-----------------------------------------------------------------------------
  428. // Returns the current input context
  429. //-----------------------------------------------------------------------------
  430. CInputSystem::InputContext_t *CInputSystem::GetInputContext( HInputContext context )
  431. {
  432. if (context == DEFAULT_INPUT_CONTEXT)
  433. return &m_DefaultInputContext;
  434. return &m_Contexts[context];
  435. }
  436. //-----------------------------------------------------------------------------
  437. // Associates a particular panel with an input context
  438. // Associating NULL is valid; it disconnects the panel from the context
  439. //-----------------------------------------------------------------------------
  440. void CInputSystem::AssociatePanelWithInputContext( HInputContext context, VPANEL pRoot )
  441. {
  442. // Changing the root panel should invalidate keysettings, etc.
  443. if (GetInputContext(context)->_rootPanel != pRoot)
  444. {
  445. ResetInputContext( context );
  446. GetInputContext(context)->_rootPanel = pRoot;
  447. }
  448. }
  449. //-----------------------------------------------------------------------------
  450. // Activates a particular input context, use DEFAULT_INPUT_CONTEXT
  451. // to get the one normally used by VGUI
  452. //-----------------------------------------------------------------------------
  453. void CInputSystem::ActivateInputContext( HInputContext context )
  454. {
  455. Assert( (context == DEFAULT_INPUT_CONTEXT) || m_Contexts.IsValidIndex(context) );
  456. m_hContext = context;
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose:
  460. //-----------------------------------------------------------------------------
  461. void CInputSystem::RunFrame()
  462. {
  463. if ( m_nDebugMessages == -1 )
  464. {
  465. m_nDebugMessages = CommandLine()->FindParm( "-vguifocus" ) ? 1 : 0;
  466. }
  467. InputContext_t *pContext = GetInputContext(m_hContext);
  468. // tick whoever has the focus
  469. if (pContext->_keyFocus)
  470. {
  471. // when modal dialogs are up messages only get sent to the dialogs children.
  472. if (IsChildOfModalPanel((VPANEL)pContext->_keyFocus))
  473. {
  474. g_pIVgui->PostMessage((VPANEL)pContext->_keyFocus, new KeyValues("KeyFocusTicked"), NULL);
  475. }
  476. }
  477. // tick whoever has the focus
  478. if (pContext->_mouseFocus)
  479. {
  480. // when modal dialogs are up messages only get sent to the dialogs children.
  481. if (IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
  482. {
  483. g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseFocusTicked"), NULL);
  484. }
  485. }
  486. // Mouse has wandered "off" the modal panel, just force a regular arrow cursor until it wanders back within the proper bounds
  487. else if ( pContext->_appModalPanel )
  488. {
  489. g_pSurface->SetCursor( vgui::dc_arrow );
  490. }
  491. //clear mouse and key states
  492. int i;
  493. for (i = 0; i < MOUSE_COUNT; i++)
  494. {
  495. pContext->_mousePressed[i] = 0;
  496. pContext->_mouseDoublePressed[i] = 0;
  497. pContext->_mouseReleased[i] = 0;
  498. }
  499. for (i = 0; i < BUTTON_CODE_COUNT; i++)
  500. {
  501. pContext->_keyPressed[i] = 0;
  502. pContext->_keyTyped[i] = 0;
  503. pContext->_keyReleased[i] = 0;
  504. }
  505. VPanel *wantedKeyFocus = CalculateNewKeyFocus();
  506. // make sure old and new focus get painted
  507. if (pContext->_keyFocus != wantedKeyFocus)
  508. {
  509. if (pContext->_keyFocus != NULL)
  510. {
  511. pContext->_keyFocus->Client()->InternalFocusChanged(true);
  512. // there may be out of order operations here, since we're directly calling SendMessage,
  513. // but we need to have focus messages happen immediately, since otherwise mouse events
  514. // happen out of order - more specifically, they happen before the focus changes
  515. // send a message to the window saying that it's losing focus
  516. {
  517. MEM_ALLOC_CREDIT();
  518. KeyValues *pMessage = new KeyValues( "KillFocus" );
  519. KeyValues::AutoDelete autodelete_pMessage( pMessage );
  520. pMessage->SetPtr( "newPanel", wantedKeyFocus );
  521. pContext->_keyFocus->SendMessage( pMessage, 0 );
  522. }
  523. if ( pContext->_keyFocus )
  524. {
  525. pContext->_keyFocus->Client()->Repaint();
  526. }
  527. // repaint the nearest popup as well, since it will need to redraw after losing focus
  528. VPanel *dlg = pContext->_keyFocus;
  529. while (dlg && !dlg->IsPopup())
  530. {
  531. dlg = dlg->GetParent();
  532. }
  533. if (dlg)
  534. {
  535. dlg->Client()->Repaint();
  536. }
  537. }
  538. if (wantedKeyFocus != NULL)
  539. {
  540. wantedKeyFocus->Client()->InternalFocusChanged(false);
  541. // there may be out of order operations here, since we're directly calling SendMessage,
  542. // but we need to have focus messages happen immediately, since otherwise mouse events
  543. // happen out of order - more specifically, they happen before the focus changes
  544. // send a message to the window saying that it's gaining focus
  545. {
  546. MEM_ALLOC_CREDIT();
  547. KeyValues *pMsg = new KeyValues("SetFocus");
  548. KeyValues::AutoDelete autodelete_pMsg( pMsg );
  549. wantedKeyFocus->SendMessage( pMsg, 0 );
  550. }
  551. wantedKeyFocus->Client()->Repaint();
  552. // repaint the nearest popup as well, since it will need to redraw after gaining focus
  553. VPanel *dlg = wantedKeyFocus;
  554. while (dlg && !dlg->IsPopup())
  555. {
  556. dlg = dlg->GetParent();
  557. }
  558. if (dlg)
  559. {
  560. dlg->Client()->Repaint();
  561. }
  562. }
  563. if ( m_nDebugMessages > 0 )
  564. {
  565. g_pIVgui->DPrintf2( "changing kb focus from %s to %s\n",
  566. pContext->_keyFocus ? pContext->_keyFocus->GetName() : "(no name)",
  567. wantedKeyFocus ? wantedKeyFocus->GetName() : "(no name)" );
  568. }
  569. // accept the focus request
  570. pContext->_keyFocus = wantedKeyFocus;
  571. if (pContext->_keyFocus)
  572. {
  573. pContext->_keyFocus->MoveToFront();
  574. }
  575. }
  576. // Pump any key repeats
  577. KeyCode repeatCode = pContext->m_keyRepeater.KeyRepeated();
  578. if (repeatCode)
  579. {
  580. InternalKeyCodePressed( repeatCode );
  581. }
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Purpose: Calculate the new key focus
  585. //-----------------------------------------------------------------------------
  586. VPanel *CInputSystem::CalculateNewKeyFocus()
  587. {
  588. InputContext_t *pContext = GetInputContext(m_hContext);
  589. // get the top-order panel
  590. VPanel *wantedKeyFocus = NULL;
  591. VPanel *pRoot = (VPanel *)pContext->_rootPanel;
  592. VPanel *top = pRoot;
  593. if ( g_pSurface->GetPopupCount() > 0 )
  594. {
  595. // find the highest-level window that is both visible and a popup
  596. int nIndex = g_pSurface->GetPopupCount();
  597. while ( nIndex )
  598. {
  599. top = (VPanel *)g_pSurface->GetPopup( --nIndex );
  600. // traverse the hierarchy and check if the popup really is visible
  601. if (top &&
  602. // top->IsPopup() && // These are right out of of the popups list!!!
  603. top->IsVisible() &&
  604. top->IsKeyBoardInputEnabled() &&
  605. !g_pSurface->IsMinimized((VPANEL)top) &&
  606. IsChildOfModalSubTree( (VPANEL)top ) &&
  607. (!pRoot || top->HasParent( pRoot )) )
  608. {
  609. bool bIsVisible = top->IsVisible();
  610. VPanel *p = top->GetParent();
  611. // drill down the hierarchy checking that everything is visible
  612. while(p && bIsVisible)
  613. {
  614. if( p->IsVisible()==false)
  615. {
  616. bIsVisible = false;
  617. break;
  618. }
  619. p=p->GetParent();
  620. }
  621. if ( bIsVisible && !g_pSurface->IsMinimized( (VPANEL)top ) )
  622. break;
  623. }
  624. top = pRoot;
  625. }
  626. }
  627. if (top)
  628. {
  629. // ask the top-level panel for what it considers to be the current focus
  630. wantedKeyFocus = (VPanel *)top->Client()->GetCurrentKeyFocus();
  631. if (!wantedKeyFocus)
  632. {
  633. wantedKeyFocus = top;
  634. }
  635. }
  636. // check to see if any of this surfaces panels have the focus
  637. if (!g_pSurface->HasFocus())
  638. {
  639. wantedKeyFocus=NULL;
  640. }
  641. // check if we are in modal state,
  642. // and if we are make sure this panel is a child of us.
  643. if (!IsChildOfModalPanel((VPANEL)wantedKeyFocus))
  644. {
  645. wantedKeyFocus=NULL;
  646. }
  647. return wantedKeyFocus;
  648. }
  649. //-----------------------------------------------------------------------------
  650. // Purpose:
  651. //-----------------------------------------------------------------------------
  652. void CInputSystem::PanelDeleted(VPANEL vfocus, InputContext_t &context)
  653. {
  654. VPanel *focus = (VPanel *)vfocus;
  655. if (context._keyFocus == focus)
  656. {
  657. if ( m_nDebugMessages > 0 )
  658. {
  659. g_pIVgui->DPrintf2( "removing kb focus %s\n",
  660. context._keyFocus ? context._keyFocus->GetName() : "(no name)" );
  661. }
  662. context._keyFocus = NULL;
  663. }
  664. if (context._mouseOver == focus)
  665. {
  666. /*
  667. if ( m_nDebugMessages > 0 )
  668. {
  669. g_pIVgui->DPrintf2( "removing kb focus %s\n",
  670. context._keyFocus ? pcontext._keyFocus->GetName() : "(no name)" );
  671. }
  672. */
  673. context._mouseOver = NULL;
  674. }
  675. if (context._oldMouseFocus == focus)
  676. {
  677. context._oldMouseFocus = NULL;
  678. }
  679. if (context._mouseFocus == focus)
  680. {
  681. context._mouseFocus = NULL;
  682. }
  683. // NOTE: These two will only ever happen for the default context at the moment
  684. if (context._mouseCapture == focus)
  685. {
  686. SetMouseCapture(NULL);
  687. context._mouseCapture = NULL;
  688. }
  689. if (context._appModalPanel == focus)
  690. {
  691. ReleaseAppModalSurface();
  692. }
  693. if ( context.m_pUnhandledMouseClickListener == focus )
  694. {
  695. context.m_pUnhandledMouseClickListener = NULL;
  696. }
  697. if ( context.m_pModalSubTree == focus )
  698. {
  699. context.m_pModalSubTree = NULL;
  700. context.m_bRestrictMessagesToModalSubTree = false;
  701. }
  702. context.m_KeyCodeUnhandledListeners.FindAndRemove( focus );
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose:
  706. // Input : *focus -
  707. //-----------------------------------------------------------------------------
  708. void CInputSystem::PanelDeleted(VPANEL focus)
  709. {
  710. HInputContext i;
  711. for (i = m_Contexts.Head(); i != m_Contexts.InvalidIndex(); i = m_Contexts.Next(i) )
  712. {
  713. PanelDeleted( focus, m_Contexts[i] );
  714. }
  715. PanelDeleted( focus, m_DefaultInputContext );
  716. }
  717. //-----------------------------------------------------------------------------
  718. // Purpose: Sets the new mouse focus
  719. // won't override _mouseCapture settings
  720. // Input : newMouseFocus -
  721. //-----------------------------------------------------------------------------
  722. void CInputSystem::SetMouseFocus(VPANEL newMouseFocus)
  723. {
  724. // check if we are in modal state,
  725. // and if we are make sure this panel is a child of us.
  726. if (!IsChildOfModalPanel(newMouseFocus))
  727. {
  728. return;
  729. }
  730. bool wantsMouse, isPopup; // = popup->GetMouseInput();
  731. VPanel *panel = (VPanel *)newMouseFocus;
  732. InputContext_t *pContext = GetInputContext( m_hContext );
  733. wantsMouse = false;
  734. if ( newMouseFocus )
  735. {
  736. do
  737. {
  738. wantsMouse = panel->IsMouseInputEnabled();
  739. isPopup = panel->IsPopup();
  740. panel = panel->GetParent();
  741. }
  742. while ( wantsMouse && !isPopup && panel && panel->GetParent() ); // only consider panels that want mouse input
  743. }
  744. // if this panel doesn't want mouse input don't let it get focus
  745. if (newMouseFocus && !wantsMouse)
  746. {
  747. return;
  748. }
  749. if ((VPANEL)pContext->_mouseOver != newMouseFocus || (!pContext->_mouseCapture && (VPANEL)pContext->_mouseFocus != newMouseFocus) )
  750. {
  751. pContext->_oldMouseFocus = pContext->_mouseOver;
  752. pContext->_mouseOver = (VPanel *)newMouseFocus;
  753. //tell the old panel with the mouseFocus that the cursor exited
  754. if ( pContext->_oldMouseFocus != NULL )
  755. {
  756. // only notify of entry if the mouse is not captured or we're the captured panel
  757. if ( !pContext->_mouseCapture || pContext->_oldMouseFocus == pContext->_mouseCapture )
  758. {
  759. g_pIVgui->PostMessage( (VPANEL)pContext->_oldMouseFocus, new KeyValues( "CursorExited" ), NULL );
  760. }
  761. }
  762. //tell the new panel with the mouseFocus that the cursor entered
  763. if ( pContext->_mouseOver != NULL )
  764. {
  765. // only notify of entry if the mouse is not captured or we're the captured panel
  766. if ( !pContext->_mouseCapture || pContext->_mouseOver == pContext->_mouseCapture )
  767. {
  768. g_pIVgui->PostMessage( (VPANEL)pContext->_mouseOver, new KeyValues( "CursorEntered" ), NULL );
  769. }
  770. }
  771. // set where the mouse is currently over
  772. // mouse capture overrides destination
  773. VPanel *newFocus = pContext->_mouseCapture ? pContext->_mouseCapture : pContext->_mouseOver;
  774. if ( m_nDebugMessages > 0 )
  775. {
  776. g_pIVgui->DPrintf2( "changing mouse focus from %s to %s\n",
  777. pContext->_mouseFocus ? pContext->_mouseFocus->GetName() : "(no name)",
  778. newFocus ? newFocus->GetName() : "(no name)" );
  779. }
  780. pContext->_mouseFocus = newFocus;
  781. }
  782. }
  783. VPanel *CInputSystem::GetMouseFocusIgnoringModalSubtree()
  784. {
  785. // find the panel that has the focus
  786. VPanel *focus = NULL;
  787. InputContext_t *pContext = GetInputContext( m_hContext );
  788. int x, y;
  789. x = pContext->m_nCursorX;
  790. y = pContext->m_nCursorY;
  791. if (!pContext->_rootPanel)
  792. {
  793. if (g_pSurface->IsCursorVisible() && g_pSurface->IsWithin(x, y))
  794. {
  795. // faster version of code below
  796. // checks through each popup in order, top to bottom windows
  797. for (int i = g_pSurface->GetPopupCount() - 1; i >= 0; i--)
  798. {
  799. VPanel *popup = (VPanel *)g_pSurface->GetPopup(i);
  800. VPanel *panel = popup;
  801. bool wantsMouse = panel->IsMouseInputEnabled();
  802. bool isVisible = !g_pSurface->IsMinimized((VPANEL)panel);
  803. while ( isVisible && panel && panel->GetParent() ) // only consider panels that want mouse input
  804. {
  805. isVisible = panel->IsVisible();
  806. panel = panel->GetParent();
  807. }
  808. if ( wantsMouse && isVisible )
  809. {
  810. focus = (VPanel *)popup->Client()->IsWithinTraverse(x, y, false);
  811. if (focus)
  812. break;
  813. }
  814. }
  815. if (!focus)
  816. {
  817. focus = (VPanel *)((VPanel *)g_pSurface->GetEmbeddedPanel())->Client()->IsWithinTraverse(x, y, false);
  818. }
  819. }
  820. }
  821. else
  822. {
  823. focus = (VPanel *)((VPanel *)(pContext->_rootPanel))->Client()->IsWithinTraverse(x, y, false);
  824. }
  825. // check if we are in modal state,
  826. // and if we are make sure this panel is a child of us.
  827. if ( !IsChildOfModalPanel((VPANEL)focus, false ))
  828. {
  829. // should this be _appModalPanel?
  830. focus = NULL;
  831. }
  832. return focus;
  833. }
  834. //-----------------------------------------------------------------------------
  835. // Purpose: Calculates which panel the cursor is currently over and sets it up
  836. // as the current mouse focus.
  837. //-----------------------------------------------------------------------------
  838. void CInputSystem::UpdateMouseFocus(int x, int y)
  839. {
  840. // find the panel that has the focus
  841. VPanel *focus = NULL;
  842. InputContext_t *pContext = GetInputContext( m_hContext );
  843. if (g_pSurface->IsCursorVisible() && g_pSurface->IsWithin(x, y))
  844. {
  845. // faster version of code below
  846. // checks through each popup in order, top to bottom windows
  847. int c = g_pSurface->GetPopupCount();
  848. for (int i = c - 1; i >= 0; i--)
  849. {
  850. VPanel *popup = (VPanel *)g_pSurface->GetPopup(i);
  851. VPanel *panel = popup;
  852. if ( pContext->_rootPanel && !popup->HasParent((VPanel*)pContext->_rootPanel) )
  853. {
  854. // if we have a root panel, only consider popups that belong to it
  855. continue;
  856. }
  857. #if defined( _DEBUG )
  858. char const *pchName = popup->GetName();
  859. NOTE_UNUSED( pchName );
  860. #endif
  861. bool wantsMouse = panel->IsMouseInputEnabled() && IsChildOfModalSubTree( (VPANEL)panel );
  862. if ( !wantsMouse )
  863. continue;
  864. bool isVisible = !g_pSurface->IsMinimized((VPANEL)panel);
  865. if ( !isVisible )
  866. continue;
  867. while ( isVisible && panel && panel->GetParent() ) // only consider panels that want mouse input
  868. {
  869. isVisible = panel->IsVisible();
  870. panel = panel->GetParent();
  871. }
  872. if ( !wantsMouse || !isVisible )
  873. continue;
  874. focus = (VPanel *)popup->Client()->IsWithinTraverse(x, y, false);
  875. if (focus)
  876. break;
  877. }
  878. if (!focus)
  879. {
  880. focus = (VPanel *)((VPanel *)g_pSurface->GetEmbeddedPanel())->Client()->IsWithinTraverse(x, y, false);
  881. }
  882. }
  883. // mouse focus debugging code
  884. /*
  885. static VPanel *oldFocus = (VPanel *)0x0001;
  886. if (oldFocus != focus)
  887. {
  888. oldFocus = focus;
  889. if (focus)
  890. {
  891. g_pIVgui->DPrintf2("mouse over: (%s, %s)\n", focus->GetName(), focus->GetClassName());
  892. }
  893. else
  894. {
  895. g_pIVgui->DPrintf2("mouse over: (NULL)\n");
  896. }
  897. }
  898. */
  899. // check if we are in modal state,
  900. // and if we are make sure this panel is a child of us.
  901. if (!IsChildOfModalPanel((VPANEL)focus))
  902. {
  903. // should this be _appModalPanel?
  904. focus = NULL;
  905. }
  906. SetMouseFocus((VPANEL)focus);
  907. }
  908. // Passes in a keycode which allows hitting other mouse buttons w/o cancelling capture mode
  909. void CInputSystem::SetMouseCaptureEx(VPANEL panel, MouseCode captureStartMouseCode )
  910. {
  911. // This sets m_MouseCaptureStartCode to -1, so we set the real value afterward
  912. SetMouseCapture( panel );
  913. // check if we are in modal state,
  914. // and if we are make sure this panel is a child of us.
  915. if (!IsChildOfModalPanel(panel))
  916. {
  917. return;
  918. }
  919. InputContext_t *pContext = GetInputContext( m_hContext );
  920. Assert( pContext );
  921. pContext->m_MouseCaptureStartCode = captureStartMouseCode;
  922. }
  923. VPANEL CInputSystem::GetMouseCapture()
  924. {
  925. InputContext_t *pContext = GetInputContext( m_hContext );
  926. return (VPANEL)pContext->_mouseCapture;
  927. }
  928. //-----------------------------------------------------------------------------
  929. // Purpose: Sets or releases the mouse capture
  930. // Input : panel - pointer to the panel to get mouse capture
  931. // a NULL panel means that you want to clear the mouseCapture
  932. // MouseCaptureLost is sent to the panel that loses the mouse capture
  933. //-----------------------------------------------------------------------------
  934. void CInputSystem::SetMouseCapture(VPANEL panel)
  935. {
  936. // check if we are in modal state,
  937. // and if we are make sure this panel is a child of us.
  938. if (!IsChildOfModalPanel(panel))
  939. {
  940. return;
  941. }
  942. InputContext_t *pContext = GetInputContext( m_hContext );
  943. Assert( pContext );
  944. pContext->m_MouseCaptureStartCode = (MouseCode)-1;
  945. // send a message if the panel is losing mouse capture
  946. if (pContext->_mouseCapture && panel != (VPANEL)pContext->_mouseCapture)
  947. {
  948. g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MouseCaptureLost"), NULL);
  949. }
  950. if (panel == NULL)
  951. {
  952. if (pContext->_mouseCapture != NULL)
  953. {
  954. g_pSurface->EnableMouseCapture((VPANEL)pContext->_mouseCapture, false);
  955. }
  956. }
  957. else
  958. {
  959. g_pSurface->EnableMouseCapture(panel, true);
  960. }
  961. pContext->_mouseCapture = (VPanel *)panel;
  962. }
  963. // returns true if the specified panel is a child of the current modal panel
  964. // if no modal panel is set, then this always returns TRUE
  965. bool CInputSystem::IsChildOfModalSubTree(VPANEL panel)
  966. {
  967. if ( !panel )
  968. return true;
  969. InputContext_t *pContext = GetInputContext( m_hContext );
  970. if ( pContext->m_pModalSubTree )
  971. {
  972. // If panel is child of modal subtree, the allow messages to route to it if restrict messages is set
  973. bool isChildOfModal = ((VPanel *)panel)->HasParent(pContext->m_pModalSubTree );
  974. if ( isChildOfModal )
  975. {
  976. return pContext->m_bRestrictMessagesToModalSubTree;
  977. }
  978. // If panel is not a child of modal subtree, then only allow messages if we're not restricting them to the modal subtree
  979. else
  980. {
  981. return !pContext->m_bRestrictMessagesToModalSubTree;
  982. }
  983. }
  984. return true;
  985. }
  986. //-----------------------------------------------------------------------------
  987. // Purpose: check if we are in modal state,
  988. // and if we are make sure this panel has the modal panel as a parent
  989. //-----------------------------------------------------------------------------
  990. bool CInputSystem::IsChildOfModalPanel(VPANEL panel, bool checkModalSubTree /*= true*/ )
  991. {
  992. // NULL is ok.
  993. if (!panel)
  994. return true;
  995. InputContext_t *pContext = GetInputContext( m_hContext );
  996. // if we are in modal state, make sure this panel is a child of us.
  997. if (pContext->_appModalPanel)
  998. {
  999. if (!((VPanel *)panel)->HasParent(pContext->_appModalPanel))
  1000. {
  1001. return false;
  1002. }
  1003. }
  1004. if ( !checkModalSubTree )
  1005. return true;
  1006. // Defer to modal subtree logic instead...
  1007. return IsChildOfModalSubTree( panel );
  1008. }
  1009. //-----------------------------------------------------------------------------
  1010. // Purpose:
  1011. //-----------------------------------------------------------------------------
  1012. VPANEL CInputSystem::GetFocus()
  1013. {
  1014. return (VPANEL)( GetInputContext( m_hContext )->_keyFocus );
  1015. }
  1016. //-----------------------------------------------------------------------------
  1017. // Purpose:
  1018. //-----------------------------------------------------------------------------
  1019. VPANEL CInputSystem::GetCalculatedFocus()
  1020. {
  1021. return (VPANEL) CalculateNewKeyFocus();
  1022. }
  1023. //-----------------------------------------------------------------------------
  1024. // Purpose:
  1025. //-----------------------------------------------------------------------------
  1026. VPANEL CInputSystem::GetMouseOver()
  1027. {
  1028. return (VPANEL)( GetInputContext( m_hContext )->_mouseOver );
  1029. }
  1030. VPANEL CInputSystem::GetMouseFocus()
  1031. {
  1032. return (VPANEL)( GetInputContext( m_hContext )->_mouseFocus );
  1033. }
  1034. bool CInputSystem::WasMousePressed( MouseCode code )
  1035. {
  1036. return GetInputContext( m_hContext )->_mousePressed[ code - MOUSE_FIRST ];
  1037. }
  1038. bool CInputSystem::WasMouseDoublePressed( MouseCode code )
  1039. {
  1040. return GetInputContext( m_hContext )->_mouseDoublePressed[ code - MOUSE_FIRST ];
  1041. }
  1042. bool CInputSystem::IsMouseDown( MouseCode code )
  1043. {
  1044. return GetInputContext( m_hContext )->_mouseDown[ code - MOUSE_FIRST ];
  1045. }
  1046. bool CInputSystem::WasMouseReleased( MouseCode code )
  1047. {
  1048. return GetInputContext( m_hContext )->_mouseReleased[ code - MOUSE_FIRST ];
  1049. }
  1050. bool CInputSystem::WasKeyPressed( KeyCode code )
  1051. {
  1052. return GetInputContext( m_hContext )->_keyPressed[ code - KEY_FIRST ];
  1053. }
  1054. bool CInputSystem::IsKeyDown( KeyCode code )
  1055. {
  1056. return GetInputContext( m_hContext )->_keyDown[ code - KEY_FIRST ];
  1057. }
  1058. bool CInputSystem::WasKeyTyped( KeyCode code )
  1059. {
  1060. return GetInputContext( m_hContext )->_keyTyped[ code - KEY_FIRST ];
  1061. }
  1062. bool CInputSystem::WasKeyReleased( KeyCode code )
  1063. {
  1064. // changed from: only return true if the key was released and the passed in panel matches the keyFocus
  1065. return GetInputContext( m_hContext )->_keyReleased[ code - KEY_FIRST ];
  1066. }
  1067. //-----------------------------------------------------------------------------
  1068. // Cursor position; this is the current position read from the input queue.
  1069. // We need to set it because client code may read this during Mouse Pressed
  1070. // events, etc.
  1071. //-----------------------------------------------------------------------------
  1072. void CInputSystem::UpdateCursorPosInternal( int x, int y )
  1073. {
  1074. // Windows sends a CursorMoved message even when you haven't actually
  1075. // moved the cursor, this means we are going into this fxn just by clicking
  1076. // in the window. We only want to execute this code if we have actually moved
  1077. // the cursor while dragging. So this code has been added to check
  1078. // if we have actually moved from our previous position.
  1079. InputContext_t *pContext = GetInputContext( m_hContext );
  1080. if ( pContext->m_nCursorX == x && pContext->m_nCursorY == y )
  1081. return;
  1082. pContext->m_nCursorX = x;
  1083. pContext->m_nCursorY = y;
  1084. // Cursor has moved, so make sure the mouseFocus is current
  1085. UpdateMouseFocus( x, y );
  1086. }
  1087. //-----------------------------------------------------------------------------
  1088. // This is called by panels to teleport the cursor
  1089. //-----------------------------------------------------------------------------
  1090. void CInputSystem::SetCursorPos( int x, int y )
  1091. {
  1092. if ( IsDispatchingMessageQueue() )
  1093. {
  1094. InputContext_t *pContext = GetInputContext( m_hContext );
  1095. pContext->m_nExternallySetCursorX = x;
  1096. pContext->m_nExternallySetCursorY = y;
  1097. pContext->m_bSetCursorExplicitly = true;
  1098. }
  1099. else
  1100. {
  1101. SurfaceSetCursorPos( x, y );
  1102. }
  1103. }
  1104. void CInputSystem::GetCursorPos(int &x, int &y)
  1105. {
  1106. if ( IsDispatchingMessageQueue() )
  1107. {
  1108. GetCursorPosition( x, y );
  1109. }
  1110. else
  1111. {
  1112. SurfaceGetCursorPos( x, y );
  1113. }
  1114. }
  1115. // Here for backward compat
  1116. void CInputSystem::GetCursorPosition( int &x, int &y )
  1117. {
  1118. InputContext_t *pContext = GetInputContext( m_hContext );
  1119. x = pContext->m_nCursorX;
  1120. y = pContext->m_nCursorY;
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // Purpose: Converts a key code into a full key name
  1124. //-----------------------------------------------------------------------------
  1125. void CInputSystem::GetKeyCodeText(KeyCode code, char *buf, int buflen)
  1126. {
  1127. if (!buf)
  1128. return;
  1129. // copy text into buf up to buflen in length
  1130. // skip 2 in _keyTrans because the first two are for GetKeyCodeChar
  1131. for (int i = 0; i < buflen; i++)
  1132. {
  1133. char ch = _keyTrans[code][i+2];
  1134. buf[i] = ch;
  1135. if (ch == 0)
  1136. break;
  1137. }
  1138. }
  1139. //-----------------------------------------------------------------------------
  1140. // Low-level cursor getting/setting functions
  1141. //-----------------------------------------------------------------------------
  1142. void CInputSystem::SurfaceSetCursorPos(int x, int y)
  1143. {
  1144. if ( g_pSurface->HasCursorPosFunctions() ) // does the surface export cursor functions for us to use?
  1145. {
  1146. g_pSurface->SurfaceSetCursorPos(x,y);
  1147. }
  1148. else
  1149. {
  1150. // translate into coordinates relative to surface
  1151. int px, py, pw, pt;
  1152. g_pSurface->GetAbsoluteWindowBounds(px, py, pw, pt);
  1153. x += px;
  1154. y += py;
  1155. // set windows cursor pos
  1156. #ifdef WIN32
  1157. ::SetCursorPos(x, y);
  1158. #else
  1159. // From Alfred on 8/15/2012.
  1160. // For l4d2, the vguimatsurface/cursor.cpp functions fire in the engine, the vgui2 ones
  1161. // should be dormant (this isn't true for Steam however).
  1162. //
  1163. // If we ever do need to implement this, look at SDL_GetMouseState(), etc.
  1164. Assert( !"CInputSystem::SurfaceSetCursorPos NYI" );
  1165. #endif
  1166. }
  1167. }
  1168. void CInputSystem::SurfaceGetCursorPos( int &x, int &y )
  1169. {
  1170. #ifndef _X360 // X360TBD
  1171. if ( g_pSurface->HasCursorPosFunctions() ) // does the surface export cursor functions for us to use?
  1172. {
  1173. g_pSurface->SurfaceGetCursorPos( x,y );
  1174. }
  1175. else
  1176. {
  1177. #ifdef WIN32
  1178. // get mouse position in windows
  1179. POINT pnt;
  1180. VCRHook_GetCursorPos(&pnt);
  1181. x = pnt.x;
  1182. y = pnt.y;
  1183. // translate into coordinates relative to surface
  1184. int px, py, pw, pt;
  1185. g_pSurface->GetAbsoluteWindowBounds(px, py, pw, pt);
  1186. x -= px;
  1187. y -= py;
  1188. #else
  1189. // From Alfred on 8/15/2012.
  1190. // For l4d2, the vguimatsurface/cursor.cpp functions fire in the engine, the vgui2 ones
  1191. // should be dormant (this isn't true for Steam however).
  1192. Assert( !"CInputSystem::SurfaceGetCursorPos NYI" );
  1193. x = 0;
  1194. y = 0;
  1195. #endif
  1196. }
  1197. #else
  1198. x = 0;
  1199. y = 0;
  1200. #endif
  1201. }
  1202. void CInputSystem::SetCursorOveride(HCursor cursor)
  1203. {
  1204. _cursorOverride = cursor;
  1205. }
  1206. HCursor CInputSystem::GetCursorOveride()
  1207. {
  1208. return _cursorOverride;
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Called when we've detected cursor has moved via a windows message
  1212. //-----------------------------------------------------------------------------
  1213. bool CInputSystem::InternalCursorMoved(int x, int y)
  1214. {
  1215. g_pIVgui->PostMessage((VPANEL) MESSAGE_CURSOR_POS, new KeyValues("SetCursorPosInternal", "xpos", x, "ypos", y), NULL);
  1216. return true;
  1217. }
  1218. //-----------------------------------------------------------------------------
  1219. // Makes sure the windows cursor is in the right place after processing input
  1220. //-----------------------------------------------------------------------------
  1221. void CInputSystem::HandleExplicitSetCursor( )
  1222. {
  1223. InputContext_t *pContext = GetInputContext( m_hContext );
  1224. if ( pContext->m_bSetCursorExplicitly )
  1225. {
  1226. pContext->m_nCursorX = pContext->m_nExternallySetCursorX;
  1227. pContext->m_nCursorY = pContext->m_nExternallySetCursorY;
  1228. pContext->m_bSetCursorExplicitly = false;
  1229. // NOTE: This forces a cursor moved message to be posted next time
  1230. pContext->m_nLastPostedCursorX = pContext->m_nLastPostedCursorY = -9999;
  1231. SurfaceSetCursorPos( pContext->m_nCursorX, pContext->m_nCursorY );
  1232. UpdateMouseFocus( pContext->m_nCursorX, pContext->m_nCursorY );
  1233. }
  1234. }
  1235. //-----------------------------------------------------------------------------
  1236. // Called when we've detected cursor has moved via a windows message
  1237. //-----------------------------------------------------------------------------
  1238. void CInputSystem::PostCursorMessage( )
  1239. {
  1240. InputContext_t *pContext = GetInputContext( m_hContext );
  1241. if ( pContext->m_bSetCursorExplicitly )
  1242. {
  1243. // NOTE m_bSetCursorExplicitly will be reset to false in HandleExplicitSetCursor
  1244. pContext->m_nCursorX = pContext->m_nExternallySetCursorX;
  1245. pContext->m_nCursorY = pContext->m_nExternallySetCursorY;
  1246. }
  1247. if ( pContext->m_nLastPostedCursorX == pContext->m_nCursorX && pContext->m_nLastPostedCursorY == pContext->m_nCursorY )
  1248. return;
  1249. pContext->m_nLastPostedCursorX = pContext->m_nCursorX;
  1250. pContext->m_nLastPostedCursorY = pContext->m_nCursorY;
  1251. if ( pContext->_mouseCapture )
  1252. {
  1253. if (!IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
  1254. return;
  1255. // the panel with mouse capture gets all messages
  1256. g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("CursorMoved", "xpos", pContext->m_nCursorX, "ypos", pContext->m_nCursorY), NULL);
  1257. }
  1258. else if (pContext->_mouseFocus != NULL)
  1259. {
  1260. // mouse focus is current from UpdateMouse focus
  1261. // so the appmodal check has already been made.
  1262. g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("CursorMoved", "xpos", pContext->m_nCursorX, "ypos", pContext->m_nCursorY), NULL);
  1263. }
  1264. }
  1265. bool CInputSystem::InternalMousePressed(MouseCode code)
  1266. {
  1267. // True means we've processed the message and other code shouldn't see this message
  1268. bool bFilter = false;
  1269. InputContext_t *pContext = GetInputContext( m_hContext );
  1270. VPanel *pTargetPanel = pContext->_mouseOver;
  1271. if ( pContext->_mouseCapture && IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
  1272. {
  1273. // The faked mouse wheel button messages are specifically ignored by vgui
  1274. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1275. return true;
  1276. bFilter = true;
  1277. bool captureLost = code == pContext->m_MouseCaptureStartCode || pContext->m_MouseCaptureStartCode == (MouseCode)-1;
  1278. // the panel with mouse capture gets all messages
  1279. g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MousePressed", "code", code), NULL);
  1280. pTargetPanel = pContext->_mouseCapture;
  1281. if ( captureLost )
  1282. {
  1283. // this has to happen after MousePressed so the panel doesn't Think it got a mouse press after it lost capture
  1284. SetMouseCapture(NULL);
  1285. }
  1286. }
  1287. else if ( (pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus) )
  1288. {
  1289. // The faked mouse wheel button messages are specifically ignored by vgui
  1290. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1291. return true;
  1292. bFilter = true;
  1293. // tell the panel with the mouseFocus that the mouse was presssed
  1294. g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MousePressed", "code", code), NULL);
  1295. // g_pIVgui->DPrintf2("MousePressed: (%s, %s)\n", _mouseFocus->GetName(), _mouseFocus->GetClassName());
  1296. pTargetPanel = pContext->_mouseFocus;
  1297. }
  1298. else if ( pContext->m_pModalSubTree && pContext->m_pUnhandledMouseClickListener )
  1299. {
  1300. VPanel *p = GetMouseFocusIgnoringModalSubtree();
  1301. if ( p )
  1302. {
  1303. bool isChildOfModal = IsChildOfModalSubTree( (VPANEL)p );
  1304. bool isUnRestricted = !pContext->m_bRestrictMessagesToModalSubTree;
  1305. if ( isUnRestricted != isChildOfModal )
  1306. {
  1307. // The faked mouse wheel button messages are specifically ignored by vgui
  1308. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1309. return true;
  1310. g_pIVgui->PostMessage( ( VPANEL )pContext->m_pUnhandledMouseClickListener, new KeyValues( "UnhandledMouseClick", "code", code ), NULL );
  1311. pTargetPanel = pContext->m_pUnhandledMouseClickListener;
  1312. bFilter = true;
  1313. }
  1314. }
  1315. }
  1316. // check if we are in modal state,
  1317. // and if we are make sure this panel is a child of us.
  1318. if ( IsChildOfModalPanel( (VPANEL)pTargetPanel ) )
  1319. {
  1320. g_pSurface->SetTopLevelFocus( (VPANEL)pTargetPanel );
  1321. }
  1322. return bFilter;
  1323. }
  1324. bool CInputSystem::InternalMouseDoublePressed(MouseCode code)
  1325. {
  1326. // True means we've processed the message and other code shouldn't see this message
  1327. bool bFilter = false;
  1328. InputContext_t *pContext = GetInputContext( m_hContext );
  1329. VPanel *pTargetPanel = pContext->_mouseOver;
  1330. if ( pContext->_mouseCapture && IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
  1331. {
  1332. // The faked mouse wheel button messages are specifically ignored by vgui
  1333. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1334. return true;
  1335. // the panel with mouse capture gets all messages
  1336. g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MouseDoublePressed", "code", code), NULL);
  1337. pTargetPanel = pContext->_mouseCapture;
  1338. bFilter = true;
  1339. }
  1340. else if ( (pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
  1341. {
  1342. // The faked mouse wheel button messages are specifically ignored by vgui
  1343. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1344. return true;
  1345. // tell the panel with the mouseFocus that the mouse was double presssed
  1346. g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseDoublePressed", "code", code), NULL);
  1347. pTargetPanel = pContext->_mouseFocus;
  1348. bFilter = true;
  1349. }
  1350. // check if we are in modal state,
  1351. // and if we are make sure this panel is a child of us.
  1352. if (IsChildOfModalPanel((VPANEL)pTargetPanel))
  1353. {
  1354. g_pSurface->SetTopLevelFocus((VPANEL)pTargetPanel);
  1355. }
  1356. return bFilter;
  1357. }
  1358. bool CInputSystem::InternalMouseReleased( MouseCode code )
  1359. {
  1360. // True means we've processed the message and other code shouldn't see this message
  1361. bool bFilter = false;
  1362. InputContext_t *pContext = GetInputContext( m_hContext );
  1363. if (pContext->_mouseCapture && IsChildOfModalPanel((VPANEL)pContext->_mouseCapture))
  1364. {
  1365. // The faked mouse wheel button messages are specifically ignored by vgui
  1366. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1367. return true;
  1368. // the panel with mouse capture gets all messages
  1369. g_pIVgui->PostMessage((VPANEL)pContext->_mouseCapture, new KeyValues("MouseReleased", "code", code), NULL );
  1370. bFilter = true;
  1371. }
  1372. else if ((pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
  1373. {
  1374. // The faked mouse wheel button messages are specifically ignored by vgui
  1375. if ( code == MOUSE_WHEEL_DOWN || code == MOUSE_WHEEL_UP )
  1376. return true;
  1377. //tell the panel with the mouseFocus that the mouse was release
  1378. g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseReleased", "code", code), NULL );
  1379. bFilter = true;
  1380. }
  1381. return bFilter;
  1382. }
  1383. bool CInputSystem::InternalMouseWheeled(int delta)
  1384. {
  1385. // True means we've processed the message and other code shouldn't see this message
  1386. bool bFilter = false;
  1387. InputContext_t *pContext = GetInputContext( m_hContext );
  1388. if ((pContext->_mouseFocus != NULL) && IsChildOfModalPanel((VPANEL)pContext->_mouseFocus))
  1389. {
  1390. // the mouseWheel works with the mouseFocus, not the keyFocus
  1391. g_pIVgui->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseWheeled", "delta", delta), NULL);
  1392. bFilter = true;
  1393. }
  1394. return bFilter;
  1395. }
  1396. //-----------------------------------------------------------------------------
  1397. // Updates the internal key/mouse state associated with the current input context without sending messages
  1398. //-----------------------------------------------------------------------------
  1399. void CInputSystem::SetMouseCodeState( MouseCode code, MouseCodeState_t state )
  1400. {
  1401. if ( !IsMouseCode( code ) )
  1402. return;
  1403. InputContext_t *pContext = GetInputContext( m_hContext );
  1404. switch( state )
  1405. {
  1406. case BUTTON_RELEASED:
  1407. pContext->_mouseReleased[ code - MOUSE_FIRST ] = 1;
  1408. break;
  1409. case BUTTON_PRESSED:
  1410. pContext->_mousePressed[ code - MOUSE_FIRST ] = 1;
  1411. break;
  1412. case BUTTON_DOUBLECLICKED:
  1413. pContext->_mouseDoublePressed[ code - MOUSE_FIRST ] = 1;
  1414. break;
  1415. }
  1416. pContext->_mouseDown[ code - MOUSE_FIRST ] = ( state != BUTTON_RELEASED );
  1417. }
  1418. void CInputSystem::SetKeyCodeState( KeyCode code, bool bPressed )
  1419. {
  1420. if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
  1421. return;
  1422. InputContext_t *pContext = GetInputContext( m_hContext );
  1423. if ( bPressed )
  1424. {
  1425. //set key state
  1426. pContext->_keyPressed[ code - KEY_FIRST ] = 1;
  1427. }
  1428. else
  1429. {
  1430. // set key state
  1431. pContext->_keyReleased[ code - KEY_FIRST ] = 1;
  1432. }
  1433. pContext->_keyDown[ code - KEY_FIRST ] = bPressed;
  1434. }
  1435. void CInputSystem::UpdateButtonState( const InputEvent_t &event )
  1436. {
  1437. switch( event.m_nType )
  1438. {
  1439. case IE_ButtonPressed:
  1440. case IE_ButtonReleased:
  1441. case IE_ButtonDoubleClicked:
  1442. {
  1443. // NOTE: data2 is the virtual key code (data1 contains the scan-code one)
  1444. ButtonCode_t code = (ButtonCode_t)event.m_nData2;
  1445. // FIXME: Workaround hack
  1446. if ( IsKeyCode( code ) || IsJoystickCode( code ) )
  1447. {
  1448. SetKeyCodeState( code, ( event.m_nType != IE_ButtonReleased ) );
  1449. break;
  1450. }
  1451. if ( IsMouseCode( code ) )
  1452. {
  1453. MouseCodeState_t state;
  1454. state = ( event.m_nType == IE_ButtonReleased ) ? vgui::BUTTON_RELEASED : vgui::BUTTON_PRESSED;
  1455. if ( event.m_nType == IE_ButtonDoubleClicked )
  1456. {
  1457. state = vgui::BUTTON_DOUBLECLICKED;
  1458. }
  1459. SetMouseCodeState( code, state );
  1460. break;
  1461. }
  1462. }
  1463. break;
  1464. }
  1465. }
  1466. bool CInputSystem::InternalKeyCodePressed( KeyCode code )
  1467. {
  1468. InputContext_t *pContext = GetInputContext( m_hContext );
  1469. // mask out bogus keys
  1470. if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
  1471. return false;
  1472. bool bFilter = PostKeyMessage( new KeyValues("KeyCodePressed", "code", code ) );
  1473. if ( bFilter )
  1474. {
  1475. // Only notice the key down for repeating if we actually used the key
  1476. pContext->m_keyRepeater.KeyDown( code );
  1477. }
  1478. return bFilter;
  1479. }
  1480. void CInputSystem::InternalKeyCodeTyped( KeyCode code )
  1481. {
  1482. InputContext_t *pContext = GetInputContext( m_hContext );
  1483. // mask out bogus keys
  1484. if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
  1485. return;
  1486. // set key state
  1487. pContext->_keyTyped[ code - KEY_FIRST ] = 1;
  1488. // tell the current focused panel that a key was typed
  1489. PostKeyMessage(new KeyValues("KeyCodeTyped", "code", code));
  1490. }
  1491. void CInputSystem::InternalKeyTyped(wchar_t unichar)
  1492. {
  1493. InputContext_t *pContext = GetInputContext( m_hContext );
  1494. // set key state
  1495. if( unichar <= KEY_LAST )
  1496. {
  1497. pContext->_keyTyped[unichar]=1;
  1498. }
  1499. // tell the current focused panel that a key was typed
  1500. PostKeyMessage(new KeyValues("KeyTyped", "unichar", unichar));
  1501. }
  1502. bool CInputSystem::InternalKeyCodeReleased( KeyCode code )
  1503. {
  1504. InputContext_t *pContext = GetInputContext( m_hContext );
  1505. // mask out bogus keys
  1506. if ( !IsKeyCode( code ) && !IsJoystickCode( code ) )
  1507. return false;
  1508. pContext->m_keyRepeater.KeyUp( code );
  1509. return PostKeyMessage(new KeyValues("KeyCodeReleased", "code", code));
  1510. }
  1511. //-----------------------------------------------------------------------------
  1512. // Purpose: posts a message to the key focus if it's valid
  1513. //-----------------------------------------------------------------------------
  1514. bool CInputSystem::PostKeyMessage(KeyValues *message)
  1515. {
  1516. InputContext_t *pContext = GetInputContext( m_hContext );
  1517. if( (pContext->_keyFocus!= NULL) && IsChildOfModalPanel((VPANEL)pContext->_keyFocus))
  1518. {
  1519. #ifdef _X360
  1520. g_pIVgui->PostMessage((VPANEL) MESSAGE_CURRENT_KEYFOCUS, message, NULL );
  1521. #else
  1522. //tell the current focused panel that a key was released
  1523. g_pIVgui->PostMessage((VPANEL)pContext->_keyFocus, message, NULL );
  1524. #endif
  1525. return true;
  1526. }
  1527. message->deleteThis();
  1528. return false;
  1529. }
  1530. VPANEL CInputSystem::GetAppModalSurface()
  1531. {
  1532. InputContext_t *pContext = GetInputContext( m_hContext );
  1533. return (VPANEL)pContext->_appModalPanel;
  1534. }
  1535. void CInputSystem::SetAppModalSurface(VPANEL panel)
  1536. {
  1537. InputContext_t *pContext = GetInputContext( m_hContext );
  1538. pContext->_appModalPanel = (VPanel *)panel;
  1539. }
  1540. void CInputSystem::ReleaseAppModalSurface()
  1541. {
  1542. InputContext_t *pContext = GetInputContext( m_hContext );
  1543. pContext->_appModalPanel = NULL;
  1544. }
  1545. #ifdef DO_IME
  1546. enum LANGFLAG
  1547. {
  1548. ENGLISH,
  1549. TRADITIONAL_CHINESE,
  1550. JAPANESE,
  1551. KOREAN,
  1552. SIMPLIFIED_CHINESE,
  1553. UNKNOWN,
  1554. NUM_IMES_SUPPORTED
  1555. } LangFlag;
  1556. struct LanguageIds
  1557. {
  1558. // char const *idname;
  1559. unsigned short id;
  1560. int languageflag;
  1561. wchar_t const *shortcode;
  1562. wchar_t const *displayname;
  1563. bool invertcomposition;
  1564. };
  1565. LanguageIds g_LanguageIds[] =
  1566. {
  1567. { 0x0000, UNKNOWN, L"", L"Neutral" },
  1568. { 0x007f, UNKNOWN, L"", L"Invariant" },
  1569. { 0x0400, UNKNOWN, L"", L"User Default Language" },
  1570. { 0x0800, UNKNOWN, L"", L"System Default Language" },
  1571. { 0x0436, UNKNOWN, L"AF", L"Afrikaans" },
  1572. { 0x041c, UNKNOWN, L"SQ", L"Albanian" },
  1573. { 0x0401, UNKNOWN, L"AR", L"Arabic (Saudi Arabia)" },
  1574. { 0x0801, UNKNOWN, L"AR", L"Arabic (Iraq)" },
  1575. { 0x0c01, UNKNOWN, L"AR", L"Arabic (Egypt)" },
  1576. { 0x1001, UNKNOWN, L"AR", L"Arabic (Libya)" },
  1577. { 0x1401, UNKNOWN, L"AR", L"Arabic (Algeria)" },
  1578. { 0x1801, UNKNOWN, L"AR", L"Arabic (Morocco)" },
  1579. { 0x1c01, UNKNOWN, L"AR", L"Arabic (Tunisia)" },
  1580. { 0x2001, UNKNOWN, L"AR", L"Arabic (Oman)" },
  1581. { 0x2401, UNKNOWN, L"AR", L"Arabic (Yemen)" },
  1582. { 0x2801, UNKNOWN, L"AR", L"Arabic (Syria)" },
  1583. { 0x2c01, UNKNOWN, L"AR", L"Arabic (Jordan)" },
  1584. { 0x3001, UNKNOWN, L"AR", L"Arabic (Lebanon)" },
  1585. { 0x3401, UNKNOWN, L"AR", L"Arabic (Kuwait)" },
  1586. { 0x3801, UNKNOWN, L"AR", L"Arabic (U.A.E.)" },
  1587. { 0x3c01, UNKNOWN, L"AR", L"Arabic (Bahrain)" },
  1588. { 0x4001, UNKNOWN, L"AR", L"Arabic (Qatar)" },
  1589. { 0x042b, UNKNOWN, L"HY", L"Armenian" },
  1590. { 0x042c, UNKNOWN, L"AZ", L"Azeri (Latin)" },
  1591. { 0x082c, UNKNOWN, L"AZ", L"Azeri (Cyrillic)" },
  1592. { 0x042d, UNKNOWN, L"ES", L"Basque" },
  1593. { 0x0423, UNKNOWN, L"BE", L"Belarusian" },
  1594. { 0x0445, UNKNOWN, L"", L"Bengali (India)" },
  1595. { 0x141a, UNKNOWN, L"", L"Bosnian (Bosnia and Herzegovina)" },
  1596. { 0x0402, UNKNOWN, L"BG", L"Bulgarian" },
  1597. { 0x0455, UNKNOWN, L"", L"Burmese" },
  1598. { 0x0403, UNKNOWN, L"CA", L"Catalan" },
  1599. { 0x0404, TRADITIONAL_CHINESE, L"CHT", L"#IME_0404", true },
  1600. { 0x0804, SIMPLIFIED_CHINESE, L"CHS", L"#IME_0804", true },
  1601. { 0x0c04, UNKNOWN, L"CH", L"Chinese (Hong Kong SAR, PRC)" },
  1602. { 0x1004, UNKNOWN, L"CH", L"Chinese (Singapore)" },
  1603. { 0x1404, UNKNOWN, L"CH", L"Chinese (Macao SAR)" },
  1604. { 0x041a, UNKNOWN, L"HR", L"Croatian" },
  1605. { 0x101a, UNKNOWN, L"HR", L"Croatian (Bosnia and Herzegovina)" },
  1606. { 0x0405, UNKNOWN, L"CZ", L"Czech" },
  1607. { 0x0406, UNKNOWN, L"DK", L"Danish" },
  1608. { 0x0465, UNKNOWN, L"MV", L"Divehi" },
  1609. { 0x0413, UNKNOWN, L"NL", L"Dutch (Netherlands)" },
  1610. { 0x0813, UNKNOWN, L"BE", L"Dutch (Belgium)" },
  1611. { 0x0409, ENGLISH, L"EN", L"#IME_0409" },
  1612. { 0x0809, ENGLISH, L"EN", L"English (United Kingdom)" },
  1613. { 0x0c09, ENGLISH, L"EN", L"English (Australian)" },
  1614. { 0x1009, ENGLISH, L"EN", L"English (Canadian)" },
  1615. { 0x1409, ENGLISH, L"EN", L"English (New Zealand)" },
  1616. { 0x1809, ENGLISH, L"EN", L"English (Ireland)" },
  1617. { 0x1c09, ENGLISH, L"EN", L"English (South Africa)" },
  1618. { 0x2009, ENGLISH, L"EN", L"English (Jamaica)" },
  1619. { 0x2409, ENGLISH, L"EN", L"English (Caribbean)" },
  1620. { 0x2809, ENGLISH, L"EN", L"English (Belize)" },
  1621. { 0x2c09, ENGLISH, L"EN", L"English (Trinidad)" },
  1622. { 0x3009, ENGLISH, L"EN", L"English (Zimbabwe)" },
  1623. { 0x3409, ENGLISH, L"EN", L"English (Philippines)" },
  1624. { 0x0425, UNKNOWN, L"ET", L"Estonian" },
  1625. { 0x0438, UNKNOWN, L"FO", L"Faeroese" },
  1626. { 0x0429, UNKNOWN, L"FA", L"Farsi" },
  1627. { 0x040b, UNKNOWN, L"FI", L"Finnish" },
  1628. { 0x040c, UNKNOWN, L"FR", L"#IME_040c" },
  1629. { 0x080c, UNKNOWN, L"FR", L"French (Belgian)" },
  1630. { 0x0c0c, UNKNOWN, L"FR", L"French (Canadian)" },
  1631. { 0x100c, UNKNOWN, L"FR", L"French (Switzerland)" },
  1632. { 0x140c, UNKNOWN, L"FR", L"French (Luxembourg)" },
  1633. { 0x180c, UNKNOWN, L"FR", L"French (Monaco)" },
  1634. { 0x0456, UNKNOWN, L"GL", L"Galician" },
  1635. { 0x0437, UNKNOWN, L"KA", L"Georgian" },
  1636. { 0x0407, UNKNOWN, L"DE", L"#IME_0407" },
  1637. { 0x0807, UNKNOWN, L"DE", L"German (Switzerland)" },
  1638. { 0x0c07, UNKNOWN, L"DE", L"German (Austria)" },
  1639. { 0x1007, UNKNOWN, L"DE", L"German (Luxembourg)" },
  1640. { 0x1407, UNKNOWN, L"DE", L"German (Liechtenstein)" },
  1641. { 0x0408, UNKNOWN, L"GR", L"Greek" },
  1642. { 0x0447, UNKNOWN, L"IN", L"Gujarati" },
  1643. { 0x040d, UNKNOWN, L"HE", L"Hebrew" },
  1644. { 0x0439, UNKNOWN, L"HI", L"Hindi" },
  1645. { 0x040e, UNKNOWN, L"HU", L"Hungarian" },
  1646. { 0x040f, UNKNOWN, L"IS", L"Icelandic" },
  1647. { 0x0421, UNKNOWN, L"ID", L"Indonesian" },
  1648. { 0x0434, UNKNOWN, L"", L"isiXhosa/Xhosa (South Africa)" },
  1649. { 0x0435, UNKNOWN, L"", L"isiZulu/Zulu (South Africa)" },
  1650. { 0x0410, UNKNOWN, L"IT", L"#IME_0410" },
  1651. { 0x0810, UNKNOWN, L"IT", L"Italian (Switzerland)" },
  1652. { 0x0411, JAPANESE, L"JP", L"#IME_0411" },
  1653. { 0x044b, UNKNOWN, L"IN", L"Kannada" },
  1654. { 0x0457, UNKNOWN, L"IN", L"Konkani" },
  1655. { 0x0412, KOREAN, L"KR", L"#IME_0412" },
  1656. { 0x0812, UNKNOWN, L"KR", L"Korean (Johab)" },
  1657. { 0x0440, UNKNOWN, L"KZ", L"Kyrgyz." },
  1658. { 0x0426, UNKNOWN, L"LV", L"Latvian" },
  1659. { 0x0427, UNKNOWN, L"LT", L"Lithuanian" },
  1660. { 0x0827, UNKNOWN, L"LT", L"Lithuanian (Classic)" },
  1661. { 0x042f, UNKNOWN, L"MK", L"FYRO Macedonian" },
  1662. { 0x043e, UNKNOWN, L"MY", L"Malay (Malaysian)" },
  1663. { 0x083e, UNKNOWN, L"MY", L"Malay (Brunei Darussalam)" },
  1664. { 0x044c, UNKNOWN, L"IN", L"Malayalam (India)" },
  1665. { 0x0481, UNKNOWN, L"", L"Maori (New Zealand)" },
  1666. { 0x043a, UNKNOWN, L"", L"Maltese (Malta)" },
  1667. { 0x044e, UNKNOWN, L"IN", L"Marathi" },
  1668. { 0x0450, UNKNOWN, L"MN", L"Mongolian" },
  1669. { 0x0414, UNKNOWN, L"NO", L"Norwegian (Bokmal)" },
  1670. { 0x0814, UNKNOWN, L"NO", L"Norwegian (Nynorsk)" },
  1671. { 0x0415, UNKNOWN, L"PL", L"Polish" },
  1672. { 0x0416, UNKNOWN, L"PT", L"Portuguese (Brazil)" },
  1673. { 0x0816, UNKNOWN, L"PT", L"Portuguese (Portugal)" },
  1674. { 0x0446, UNKNOWN, L"IN", L"Punjabi" },
  1675. { 0x046b, UNKNOWN, L"", L"Quechua (Bolivia)" },
  1676. { 0x086b, UNKNOWN, L"", L"Quechua (Ecuador)" },
  1677. { 0x0c6b, UNKNOWN, L"", L"Quechua (Peru)" },
  1678. { 0x0418, UNKNOWN, L"RO", L"Romanian" },
  1679. { 0x0419, UNKNOWN, L"RU", L"#IME_0419" },
  1680. { 0x044f, UNKNOWN, L"IN", L"Sanskrit" },
  1681. { 0x043b, UNKNOWN, L"", L"Sami, Northern (Norway)" },
  1682. { 0x083b, UNKNOWN, L"", L"Sami, Northern (Sweden)" },
  1683. { 0x0c3b, UNKNOWN, L"", L"Sami, Northern (Finland)" },
  1684. { 0x103b, UNKNOWN, L"", L"Sami, Lule (Norway)" },
  1685. { 0x143b, UNKNOWN, L"", L"Sami, Lule (Sweden)" },
  1686. { 0x183b, UNKNOWN, L"", L"Sami, Southern (Norway)" },
  1687. { 0x1c3b, UNKNOWN, L"", L"Sami, Southern (Sweden)" },
  1688. { 0x203b, UNKNOWN, L"", L"Sami, Skolt (Finland)" },
  1689. { 0x243b, UNKNOWN, L"", L"Sami, Inari (Finland)" },
  1690. { 0x0c1a, UNKNOWN, L"SR", L"Serbian (Cyrillic)" },
  1691. { 0x1c1a, UNKNOWN, L"SR", L"Serbian (Cyrillic, Bosnia, and Herzegovina)" },
  1692. { 0x081a, UNKNOWN, L"SR", L"Serbian (Latin)" },
  1693. { 0x181a, UNKNOWN, L"SR", L"Serbian (Latin, Bosnia, and Herzegovina)" },
  1694. { 0x046c, UNKNOWN, L"", L"Sesotho sa Leboa/Northern Sotho (South Africa)" },
  1695. { 0x0432, UNKNOWN, L"", L"Setswana/Tswana (South Africa)" },
  1696. { 0x041b, UNKNOWN, L"SK", L"Slovak" },
  1697. { 0x0424, UNKNOWN, L"SI", L"Slovenian" },
  1698. { 0x040a, UNKNOWN, L"ES", L"#IME_040a" },
  1699. { 0x080a, UNKNOWN, L"ES", L"Spanish (Mexican)" },
  1700. { 0x0c0a, UNKNOWN, L"ES", L"Spanish (Spain, Modern Sort)" },
  1701. { 0x100a, UNKNOWN, L"ES", L"Spanish (Guatemala)" },
  1702. { 0x140a, UNKNOWN, L"ES", L"Spanish (Costa Rica)" },
  1703. { 0x180a, UNKNOWN, L"ES", L"Spanish (Panama)" },
  1704. { 0x1c0a, UNKNOWN, L"ES", L"Spanish (Dominican Republic)" },
  1705. { 0x200a, UNKNOWN, L"ES", L"Spanish (Venezuela)" },
  1706. { 0x240a, UNKNOWN, L"ES", L"Spanish (Colombia)" },
  1707. { 0x280a, UNKNOWN, L"ES", L"Spanish (Peru)" },
  1708. { 0x2c0a, UNKNOWN, L"ES", L"Spanish (Argentina)" },
  1709. { 0x300a, UNKNOWN, L"ES", L"Spanish (Ecuador)" },
  1710. { 0x340a, UNKNOWN, L"ES", L"Spanish (Chile)" },
  1711. { 0x380a, UNKNOWN, L"ES", L"Spanish (Uruguay)" },
  1712. { 0x3c0a, UNKNOWN, L"ES", L"Spanish (Paraguay)" },
  1713. { 0x400a, UNKNOWN, L"ES", L"Spanish (Bolivia)" },
  1714. { 0x440a, UNKNOWN, L"ES", L"Spanish (El Salvador)" },
  1715. { 0x480a, UNKNOWN, L"ES", L"Spanish (Honduras)" },
  1716. { 0x4c0a, UNKNOWN, L"ES", L"Spanish (Nicaragua)" },
  1717. { 0x500a, UNKNOWN, L"ES", L"Spanish (Puerto Rico)" },
  1718. { 0x0430, UNKNOWN, L"", L"Sutu" },
  1719. { 0x0441, UNKNOWN, L"KE", L"Swahili (Kenya)" },
  1720. { 0x041d, UNKNOWN, L"SV", L"Swedish" },
  1721. { 0x081d, UNKNOWN, L"SV", L"Swedish (Finland)" },
  1722. { 0x045a, UNKNOWN, L"SY", L"Syriac" },
  1723. { 0x0449, UNKNOWN, L"IN", L"Tamil" },
  1724. { 0x0444, UNKNOWN, L"RU", L"Tatar (Tatarstan)" },
  1725. { 0x044a, UNKNOWN, L"IN", L"Telugu" },
  1726. { 0x041e, UNKNOWN, L"TH", L"#IME_041e" },
  1727. { 0x041f, UNKNOWN, L"TR", L"Turkish" },
  1728. { 0x0422, UNKNOWN, L"UA", L"Ukrainian" },
  1729. { 0x0420, UNKNOWN, L"PK", L"Urdu (Pakistan)" },
  1730. { 0x0820, UNKNOWN, L"IN", L"Urdu (India)" },
  1731. { 0x0443, UNKNOWN, L"UZ", L"Uzbek (Latin)" },
  1732. { 0x0843, UNKNOWN, L"UZ", L"Uzbek (Cyrillic)" },
  1733. { 0x042a, UNKNOWN, L"VN", L"Vietnamese" },
  1734. { 0x0452, UNKNOWN, L"", L"Welsh (United Kingdom)" },
  1735. };
  1736. static LanguageIds *GetLanguageInfo( unsigned short id )
  1737. {
  1738. for ( int j = 0; j < sizeof( g_LanguageIds ) / sizeof( g_LanguageIds[ 0 ] ); ++j )
  1739. {
  1740. if ( g_LanguageIds[ j ].id == id )
  1741. {
  1742. return &g_LanguageIds[ j ];
  1743. break;
  1744. }
  1745. }
  1746. return NULL;
  1747. }
  1748. /////////////////////////////////////////////////////////////////////////////
  1749. // CIMEDlg message handlers
  1750. static bool IsIDInList( unsigned short id, int count, HKL *list )
  1751. {
  1752. for ( int i = 0; i < count; ++i )
  1753. {
  1754. if ( LOWORD( list[ i ] ) == id )
  1755. {
  1756. return true;
  1757. }
  1758. }
  1759. return false;
  1760. }
  1761. static const wchar_t *GetLanguageName( unsigned short id )
  1762. {
  1763. wchar_t const *name = L"???";
  1764. for ( int j = 0; j < sizeof( g_LanguageIds ) / sizeof( g_LanguageIds[ 0 ] ); ++j )
  1765. {
  1766. if ( g_LanguageIds[ j ].id == id )
  1767. {
  1768. name = g_LanguageIds[ j ].displayname;
  1769. break;
  1770. }
  1771. }
  1772. return name;
  1773. }
  1774. #endif // DO_IME
  1775. //-----------------------------------------------------------------------------
  1776. // Purpose:
  1777. // Input : *hwnd -
  1778. //-----------------------------------------------------------------------------
  1779. void CInputSystem::SetIMEWindow( void *hwnd )
  1780. {
  1781. #ifdef DO_IME
  1782. _imeWnd = hwnd;
  1783. #endif
  1784. }
  1785. //-----------------------------------------------------------------------------
  1786. // Purpose:
  1787. //-----------------------------------------------------------------------------
  1788. void *CInputSystem::GetIMEWindow()
  1789. {
  1790. #ifdef DO_IME
  1791. return _imeWnd;
  1792. #else
  1793. return NULL;
  1794. #endif
  1795. }
  1796. #ifdef DO_IME
  1797. static void SpewIMEInfo( int langid )
  1798. {
  1799. LanguageIds *info = GetLanguageInfo( langid );
  1800. if ( info )
  1801. {
  1802. wchar_t const *name = info->shortcode ? info->shortcode : L"???";
  1803. wchar_t outstr[ 512 ];
  1804. V_swprintf_safe( outstr, L"IME language changed to: %s", name );
  1805. OutputDebugStringW( outstr );
  1806. OutputDebugStringW( L"\n" );
  1807. }
  1808. }
  1809. #endif // DO_IME
  1810. // Change keyboard layout type
  1811. void CInputSystem::OnChangeIME( bool forward )
  1812. {
  1813. ASSERT_IF_IME_NYI();
  1814. #ifdef DO_IME
  1815. HKL currentKb = GetKeyboardLayout( 0 );
  1816. UINT numKBs = GetKeyboardLayoutList( 0, NULL );
  1817. if ( numKBs > 0 )
  1818. {
  1819. HKL *list = new HKL[ numKBs ];
  1820. GetKeyboardLayoutList( numKBs, list );
  1821. int oldKb = 0;
  1822. CUtlVector< HKL > selections;
  1823. for ( unsigned int i = 0; i < numKBs; ++i )
  1824. {
  1825. BOOL first = !IsIDInList( LOWORD( list[ i ] ), i, list );
  1826. if ( !first )
  1827. continue;
  1828. selections.AddToTail( list[ i ] );
  1829. if ( list[ i ] == currentKb )
  1830. {
  1831. oldKb = selections.Count() - 1;
  1832. }
  1833. }
  1834. oldKb += forward ? 1 : -1;
  1835. if ( oldKb < 0 )
  1836. {
  1837. oldKb = max( 0, selections.Count() - 1 );
  1838. }
  1839. else if ( oldKb >= selections.Count() )
  1840. {
  1841. oldKb = 0;
  1842. }
  1843. ActivateKeyboardLayout( selections[ oldKb ], 0 );
  1844. int langid = LOWORD( selections[ oldKb ] );
  1845. SpewIMEInfo( langid );
  1846. delete[] list;
  1847. }
  1848. #endif
  1849. }
  1850. int CInputSystem::GetCurrentIMEHandle()
  1851. {
  1852. ASSERT_IF_IME_NYI();
  1853. #ifdef DO_IME
  1854. HKL hkl = (HKL)GetKeyboardLayout( 0 );
  1855. return (int)hkl;
  1856. #else
  1857. return 0;
  1858. #endif
  1859. }
  1860. int CInputSystem::GetEnglishIMEHandle()
  1861. {
  1862. #ifdef DO_IME
  1863. HKL hkl = (HKL)0x04090409;
  1864. return (int)hkl;
  1865. #else
  1866. return 0;
  1867. #endif
  1868. }
  1869. void CInputSystem::OnChangeIMEByHandle( int handleValue )
  1870. {
  1871. ASSERT_IF_IME_NYI();
  1872. #ifdef DO_IME
  1873. HKL hkl = (HKL)handleValue;
  1874. ActivateKeyboardLayout( hkl, 0 );
  1875. int langid = LOWORD( hkl);
  1876. SpewIMEInfo( langid );
  1877. #endif
  1878. }
  1879. // Returns the Language Bar label (Chinese, Korean, Japanese, Russion, Thai, etc.)
  1880. void CInputSystem::GetIMELanguageName( wchar_t *buf, int unicodeBufferSizeInBytes )
  1881. {
  1882. ASSERT_IF_IME_NYI();
  1883. #ifdef DO_IME
  1884. wchar_t const *name = GetLanguageName( LOWORD( GetKeyboardLayout( 0 ) ) );
  1885. wcsncpy( buf, name, unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 );
  1886. buf[ unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 ] = L'\0';
  1887. #else
  1888. buf[0] = L'\0';
  1889. #endif
  1890. }
  1891. // Returns the short code for the language (EN, CH, KO, JP, RU, TH, etc. ).
  1892. void CInputSystem::GetIMELanguageShortCode( wchar_t *buf, int unicodeBufferSizeInBytes )
  1893. {
  1894. #ifdef DO_IME
  1895. LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
  1896. if ( !info )
  1897. {
  1898. buf[ 0 ] = L'\0';
  1899. }
  1900. else
  1901. {
  1902. wcsncpy( buf, info->shortcode, unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 );
  1903. buf[ unicodeBufferSizeInBytes / sizeof( wchar_t ) - 1 ] = L'\0';
  1904. }
  1905. #else
  1906. buf[0] = L'\0';
  1907. #endif
  1908. }
  1909. // Call with NULL dest to get item count
  1910. int CInputSystem::GetIMELanguageList( LanguageItem *dest, int destcount )
  1911. {
  1912. ASSERT_IF_IME_NYI();
  1913. #ifdef DO_IME
  1914. int iret = 0;
  1915. UINT numKBs = GetKeyboardLayoutList( 0, NULL );
  1916. if ( numKBs > 0 )
  1917. {
  1918. HKL *list = new HKL[ numKBs ];
  1919. GetKeyboardLayoutList( numKBs, list );
  1920. CUtlVector< HKL > selections;
  1921. for ( unsigned int i = 0; i < numKBs; ++i )
  1922. {
  1923. BOOL first = !IsIDInList( LOWORD( list[ i ] ), i, list );
  1924. if ( !first )
  1925. continue;
  1926. selections.AddToTail( list[ i ] );
  1927. }
  1928. iret = selections.Count();
  1929. if ( dest )
  1930. {
  1931. for ( int i = 0; i < min(iret,destcount); ++i )
  1932. {
  1933. HKL hkl = selections[ i ];
  1934. IInput::LanguageItem *p = &dest[ i ];
  1935. LanguageIds *info = GetLanguageInfo( LOWORD( hkl ) );
  1936. memset( p, 0, sizeof( IInput::LanguageItem ) );
  1937. wcsncpy( p->shortname, info->shortcode, sizeof( p->shortname ) / sizeof( wchar_t ) );
  1938. p->shortname[ sizeof( p->shortname ) / sizeof( wchar_t ) - 1 ] = L'\0';
  1939. wcsncpy( p->menuname, info->displayname, sizeof( p->menuname ) / sizeof( wchar_t ) );
  1940. p->menuname[ sizeof( p->menuname ) / sizeof( wchar_t ) - 1 ] = L'\0';
  1941. p->handleValue = (int)hkl;
  1942. p->active = ( hkl == GetKeyboardLayout( 0 ) ) ? true : false;
  1943. }
  1944. }
  1945. delete[] list;
  1946. }
  1947. return iret;
  1948. #else
  1949. return 0;
  1950. #endif
  1951. }
  1952. /*
  1953. // Flag for effective options in conversion mode
  1954. BOOL fConvMode[NUM_IMES_SUPPORTED][13] =
  1955. {
  1956. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // EN
  1957. {1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0}, // Trad CH
  1958. {1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1}, // Japanese
  1959. {1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // Kor
  1960. {1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0}, // Simp CH
  1961. {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // UNK(same as EN)
  1962. }
  1963. // Flag for effective options in sentence mode
  1964. BOOL fSentMode[NUM_IMES_SUPPORTED][6] =
  1965. {
  1966. {0, 0, 0, 0, 0, 0}, // EN
  1967. {0, 1, 0, 0, 0, 0}, // Trad CH
  1968. {1, 1, 1, 1, 1, 1}, // Japanese
  1969. {0, 0, 0, 0, 0, 0}, // Kor
  1970. {0, 0, 0, 0, 0, 0} // Simp CH
  1971. {0, 0, 0, 0, 0, 0}, // UNK(same as EN)
  1972. };
  1973. // Conversion mode message
  1974. DWORD dwConvModeMsg[13] = {
  1975. IME_CMODE_ALPHANUMERIC, IME_CMODE_NATIVE, IME_CMODE_KATAKANA,
  1976. IME_CMODE_LANGUAGE, IME_CMODE_FULLSHAPE, IME_CMODE_ROMAN,
  1977. IME_CMODE_CHARCODE, IME_CMODE_HANJACONVERT, IME_CMODE_SOFTKBD,
  1978. IME_CMODE_NOCONVERSION, IME_CMODE_EUDC, IME_CMODE_SYMBOL,
  1979. IME_CMODE_FIXED};
  1980. // Sentence mode message
  1981. DWORD dwSentModeMsg[6] = {
  1982. IME_SMODE_NONE, IME_SMODE_PLAURALCLAUSE, IME_SMODE_SINGLECONVERT,
  1983. IME_SMODE_AUTOMATIC, IME_SMODE_PHRASEPREDICT, IME_SMODE_CONVERSATION };
  1984. // ENGLISH,
  1985. // TRADITIONAL_CHINESE,
  1986. // JAPANESE,
  1987. // KOREAN,
  1988. // SIMPLIFIED_CHINESE,
  1989. // UNKNOWN,
  1990. */
  1991. #ifdef DO_IME
  1992. struct IMESettingsTransform
  1993. {
  1994. IMESettingsTransform( unsigned int cmr, unsigned int cma, unsigned int smr, unsigned int sma ) :
  1995. cmode_remove( cmr ),
  1996. cmode_add( cma ),
  1997. smode_remove( smr ),
  1998. smode_add( sma )
  1999. {
  2000. }
  2001. void Apply( HWND hwnd )
  2002. {
  2003. HIMC hImc = ImmGetContext( hwnd );
  2004. if ( hImc )
  2005. {
  2006. DWORD dwConvMode, dwSentMode;
  2007. ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
  2008. dwConvMode &= ~cmode_remove;
  2009. dwSentMode &= ~smode_remove;
  2010. ImmSetConversionStatus( hImc, dwConvMode, dwSentMode );
  2011. dwConvMode |= cmode_add;
  2012. dwSentMode |= smode_add;
  2013. ImmSetConversionStatus( hImc, dwConvMode, dwSentMode );
  2014. ImmReleaseContext( hwnd, hImc );
  2015. }
  2016. }
  2017. bool ConvMatches( DWORD convFlags )
  2018. {
  2019. // To match, the active flags have to have none of the remove flags and have to have all of the "add" flags
  2020. if ( convFlags & cmode_remove )
  2021. return false;
  2022. if ( ( convFlags & cmode_add ) == cmode_add )
  2023. {
  2024. return true;
  2025. }
  2026. return false;
  2027. }
  2028. bool SentMatches( DWORD sentFlags )
  2029. {
  2030. // To match, the active flags have to have none of the remove flags and have to have all of the "add" flags
  2031. if ( sentFlags & smode_remove )
  2032. return false;
  2033. if ( ( sentFlags & smode_add ) == smode_add )
  2034. {
  2035. return true;
  2036. }
  2037. return false;
  2038. }
  2039. unsigned int cmode_remove;
  2040. unsigned int cmode_add;
  2041. unsigned int smode_remove;
  2042. unsigned int smode_add;
  2043. };
  2044. static IMESettingsTransform g_ConversionMode_CHT_ToChinese(
  2045. IME_CMODE_ALPHANUMERIC,
  2046. IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
  2047. 0,
  2048. 0 );
  2049. static IMESettingsTransform g_ConversionMode_CHT_ToEnglish(
  2050. IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
  2051. IME_CMODE_ALPHANUMERIC,
  2052. 0,
  2053. 0 );
  2054. static IMESettingsTransform g_ConversionMode_CHS_ToChinese(
  2055. IME_CMODE_ALPHANUMERIC,
  2056. IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
  2057. 0,
  2058. 0 );
  2059. static IMESettingsTransform g_ConversionMode_CHS_ToEnglish(
  2060. IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
  2061. IME_CMODE_ALPHANUMERIC,
  2062. 0,
  2063. 0 );
  2064. static IMESettingsTransform g_ConversionMode_KO_ToKorean(
  2065. IME_CMODE_ALPHANUMERIC,
  2066. IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
  2067. 0,
  2068. 0 );
  2069. static IMESettingsTransform g_ConversionMode_KO_ToEnglish(
  2070. IME_CMODE_NATIVE | IME_CMODE_LANGUAGE,
  2071. IME_CMODE_ALPHANUMERIC,
  2072. 0,
  2073. 0 );
  2074. static IMESettingsTransform g_ConversionMode_JP_Hiragana(
  2075. IME_CMODE_ALPHANUMERIC | IME_CMODE_KATAKANA,
  2076. IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE,
  2077. 0,
  2078. 0 );
  2079. static IMESettingsTransform g_ConversionMode_JP_DirectInput(
  2080. IME_CMODE_NATIVE | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ) | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN,
  2081. IME_CMODE_ALPHANUMERIC,
  2082. 0,
  2083. 0 );
  2084. static IMESettingsTransform g_ConversionMode_JP_FullwidthKatakana(
  2085. IME_CMODE_ALPHANUMERIC,
  2086. IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN | IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE,
  2087. 0,
  2088. 0 );
  2089. static IMESettingsTransform g_ConversionMode_JP_HalfwidthKatakana(
  2090. IME_CMODE_ALPHANUMERIC | IME_CMODE_FULLSHAPE,
  2091. IME_CMODE_NATIVE | IME_CMODE_ROMAN | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ),
  2092. 0,
  2093. 0 );
  2094. static IMESettingsTransform g_ConversionMode_JP_FullwidthAlphanumeric(
  2095. IME_CMODE_NATIVE | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ),
  2096. IME_CMODE_ALPHANUMERIC | IME_CMODE_FULLSHAPE | IME_CMODE_ROMAN,
  2097. 0,
  2098. 0 );
  2099. static IMESettingsTransform g_ConversionMode_JP_HalfwidthAlphanumeric(
  2100. IME_CMODE_NATIVE | ( IME_CMODE_KATAKANA | IME_CMODE_LANGUAGE ) | IME_CMODE_FULLSHAPE,
  2101. IME_CMODE_ALPHANUMERIC | IME_CMODE_ROMAN,
  2102. 0,
  2103. 0 );
  2104. #endif // DO_IME
  2105. int CInputSystem::GetIMEConversionModes( ConversionModeItem *dest, int destcount )
  2106. {
  2107. ASSERT_IF_IME_NYI();
  2108. #ifdef DO_IME
  2109. if ( dest )
  2110. {
  2111. memset( dest, 0, destcount * sizeof( ConversionModeItem ) );
  2112. }
  2113. DWORD dwConvMode = 0, dwSentMode = 0;
  2114. HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
  2115. if ( hImc )
  2116. {
  2117. ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
  2118. ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
  2119. }
  2120. LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
  2121. switch ( info->languageflag )
  2122. {
  2123. default:
  2124. return 0;
  2125. case TRADITIONAL_CHINESE:
  2126. // This is either native or alphanumeric
  2127. if ( dest )
  2128. {
  2129. ConversionModeItem *item;
  2130. int i = 0;
  2131. item = &dest[ i++ ];
  2132. wcsncpy( item->menuname, L"#IME_Chinese", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2133. item->handleValue = (int)&g_ConversionMode_CHT_ToChinese;
  2134. item->active = g_ConversionMode_CHT_ToChinese.ConvMatches( dwConvMode );
  2135. item = &dest[ i++ ];
  2136. wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2137. item->handleValue = (int)&g_ConversionMode_CHT_ToEnglish;
  2138. item->active = g_ConversionMode_CHT_ToEnglish.ConvMatches( dwConvMode );
  2139. }
  2140. return 2;
  2141. case JAPANESE:
  2142. // There are 6 Japanese modes
  2143. if ( dest )
  2144. {
  2145. ConversionModeItem *item;
  2146. int i = 0;
  2147. item = &dest[ i++ ];
  2148. wcsncpy( item->menuname, L"#IME_Hiragana", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2149. item->handleValue = (int)&g_ConversionMode_JP_Hiragana;
  2150. item->active = g_ConversionMode_JP_Hiragana.ConvMatches( dwConvMode );
  2151. item = &dest[ i++ ];
  2152. wcsncpy( item->menuname, L"#IME_FullWidthKatakana", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2153. item->handleValue = (int)&g_ConversionMode_JP_FullwidthKatakana;
  2154. item->active = g_ConversionMode_JP_FullwidthKatakana.ConvMatches( dwConvMode );
  2155. item = &dest[ i++ ];
  2156. wcsncpy( item->menuname, L"#IME_FullWidthAlphanumeric", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2157. item->handleValue = (int)&g_ConversionMode_JP_FullwidthAlphanumeric;
  2158. item->active = g_ConversionMode_JP_FullwidthAlphanumeric.ConvMatches( dwConvMode );
  2159. item = &dest[ i++ ];
  2160. wcsncpy( item->menuname, L"#IME_HalfWidthKatakana", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2161. item->handleValue = (int)&g_ConversionMode_JP_HalfwidthKatakana;
  2162. item->active = g_ConversionMode_JP_HalfwidthKatakana.ConvMatches( dwConvMode );
  2163. item = &dest[ i++ ];
  2164. wcsncpy( item->menuname, L"#IME_HalfWidthAlphanumeric", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2165. item->handleValue = (int)&g_ConversionMode_JP_HalfwidthAlphanumeric;
  2166. item->active = g_ConversionMode_JP_HalfwidthAlphanumeric.ConvMatches( dwConvMode );
  2167. item = &dest[ i++ ];
  2168. wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2169. item->handleValue = (int)&g_ConversionMode_JP_DirectInput;
  2170. item->active = g_ConversionMode_JP_DirectInput.ConvMatches( dwConvMode );
  2171. }
  2172. return 6;
  2173. case KOREAN:
  2174. // This is either native or alphanumeric
  2175. if ( dest )
  2176. {
  2177. ConversionModeItem *item;
  2178. int i = 0;
  2179. item = &dest[ i++ ];
  2180. wcsncpy( item->menuname, L"#IME_Korean", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2181. item->handleValue = (int)&g_ConversionMode_KO_ToKorean;
  2182. item->active = g_ConversionMode_KO_ToKorean.ConvMatches( dwConvMode );
  2183. item = &dest[ i++ ];
  2184. wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2185. item->handleValue = (int)&g_ConversionMode_KO_ToEnglish;
  2186. item->active = g_ConversionMode_KO_ToEnglish.ConvMatches( dwConvMode );
  2187. }
  2188. return 2;
  2189. case SIMPLIFIED_CHINESE:
  2190. // This is either native or alphanumeric
  2191. if ( dest )
  2192. {
  2193. ConversionModeItem *item;
  2194. int i = 0;
  2195. item = &dest[ i++ ];
  2196. wcsncpy( item->menuname, L"#IME_Chinese", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2197. item->handleValue = (int)&g_ConversionMode_CHS_ToChinese;
  2198. item->active = g_ConversionMode_CHS_ToChinese.ConvMatches( dwConvMode );
  2199. item = &dest[ i++ ];
  2200. wcsncpy( item->menuname, L"#IME_English", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2201. item->handleValue = (int)&g_ConversionMode_CHS_ToChinese;
  2202. item->active = g_ConversionMode_CHS_ToChinese.ConvMatches( dwConvMode );
  2203. }
  2204. return 2;
  2205. }
  2206. #endif
  2207. return 0;
  2208. }
  2209. #ifdef DO_IME
  2210. static IMESettingsTransform g_SentenceMode_JP_None(
  2211. 0,
  2212. 0,
  2213. IME_SMODE_PLAURALCLAUSE | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_PHRASEPREDICT | IME_SMODE_CONVERSATION,
  2214. IME_SMODE_NONE );
  2215. static IMESettingsTransform g_SentenceMode_JP_General(
  2216. 0,
  2217. 0,
  2218. IME_SMODE_NONE | IME_SMODE_PLAURALCLAUSE | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_CONVERSATION,
  2219. IME_SMODE_PHRASEPREDICT
  2220. );
  2221. static IMESettingsTransform g_SentenceMode_JP_BiasNames(
  2222. 0,
  2223. 0,
  2224. IME_SMODE_NONE | IME_SMODE_PHRASEPREDICT | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_CONVERSATION,
  2225. IME_SMODE_PLAURALCLAUSE
  2226. );
  2227. static IMESettingsTransform g_SentenceMode_JP_BiasSpeech(
  2228. 0,
  2229. 0,
  2230. IME_SMODE_NONE | IME_SMODE_PHRASEPREDICT | IME_SMODE_SINGLECONVERT | IME_SMODE_AUTOMATIC | IME_SMODE_PLAURALCLAUSE,
  2231. IME_SMODE_CONVERSATION
  2232. );
  2233. #endif // _X360
  2234. int CInputSystem::GetIMESentenceModes( SentenceModeItem *dest, int destcount )
  2235. {
  2236. ASSERT_IF_IME_NYI();
  2237. #ifdef DO_IME
  2238. if ( dest )
  2239. {
  2240. memset( dest, 0, destcount * sizeof( SentenceModeItem ) );
  2241. }
  2242. DWORD dwConvMode = 0, dwSentMode = 0;
  2243. HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
  2244. if ( hImc )
  2245. {
  2246. ImmGetConversionStatus( hImc, &dwConvMode, &dwSentMode );
  2247. ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
  2248. }
  2249. LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
  2250. switch ( info->languageflag )
  2251. {
  2252. default:
  2253. return 0;
  2254. // case TRADITIONAL_CHINESE:
  2255. // break;
  2256. case JAPANESE:
  2257. // There are 4 Japanese sentence modes
  2258. if ( dest )
  2259. {
  2260. SentenceModeItem *item;
  2261. int i = 0;
  2262. item = &dest[ i++ ];
  2263. wcsncpy( item->menuname, L"#IME_General", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2264. item->handleValue = (int)&g_SentenceMode_JP_General;
  2265. item->active = g_SentenceMode_JP_General.SentMatches( dwSentMode );
  2266. item = &dest[ i++ ];
  2267. wcsncpy( item->menuname, L"#IME_BiasNames", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2268. item->handleValue = (int)&g_SentenceMode_JP_BiasNames;
  2269. item->active = g_SentenceMode_JP_BiasNames.SentMatches( dwSentMode );
  2270. item = &dest[ i++ ];
  2271. wcsncpy( item->menuname, L"#IME_BiasSpeech", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2272. item->handleValue = (int)&g_SentenceMode_JP_BiasSpeech;
  2273. item->active = g_SentenceMode_JP_BiasSpeech.SentMatches( dwSentMode );
  2274. item = &dest[ i++ ];
  2275. wcsncpy( item->menuname, L"#IME_NoConversion", sizeof( item->menuname ) / sizeof( wchar_t ) );
  2276. item->handleValue = (int)&g_SentenceMode_JP_None;
  2277. item->active = g_SentenceMode_JP_None.SentMatches( dwSentMode );
  2278. }
  2279. return 4;
  2280. }
  2281. #endif
  2282. return 0;
  2283. }
  2284. void CInputSystem::OnChangeIMEConversionModeByHandle( int handleValue )
  2285. {
  2286. ASSERT_IF_IME_NYI();
  2287. #ifdef DO_IME
  2288. if ( handleValue == 0 )
  2289. return;
  2290. IMESettingsTransform *txform = ( IMESettingsTransform * )handleValue;
  2291. txform->Apply( (HWND)GetIMEWindow() );
  2292. #endif
  2293. }
  2294. void CInputSystem::OnChangeIMESentenceModeByHandle( int handleValue )
  2295. {
  2296. }
  2297. void CInputSystem::OnInputLanguageChanged()
  2298. {
  2299. }
  2300. void CInputSystem::OnIMEStartComposition()
  2301. {
  2302. }
  2303. #ifdef DO_IME
  2304. void DescribeIMEFlag( char const *string, bool value )
  2305. {
  2306. if ( value )
  2307. {
  2308. Msg( " %s\n", string );
  2309. }
  2310. }
  2311. #define IMEDesc( x ) DescribeIMEFlag( #x, flags & x );
  2312. #endif // DO_IME
  2313. void CInputSystem::OnIMEComposition( int flags )
  2314. {
  2315. ASSERT_IF_IME_NYI();
  2316. #ifdef DO_IME
  2317. /*
  2318. Msg( "OnIMEComposition\n" );
  2319. IMEDesc( VGUI_GCS_COMPREADSTR );
  2320. IMEDesc( VGUI_GCS_COMPREADATTR );
  2321. IMEDesc( VGUI_GCS_COMPREADCLAUSE );
  2322. IMEDesc( VGUI_GCS_COMPSTR );
  2323. IMEDesc( VGUI_GCS_COMPATTR );
  2324. IMEDesc( VGUI_GCS_COMPCLAUSE );
  2325. IMEDesc( VGUI_GCS_CURSORPOS );
  2326. IMEDesc( VGUI_GCS_DELTASTART );
  2327. IMEDesc( VGUI_GCS_RESULTREADSTR );
  2328. IMEDesc( VGUI_GCS_RESULTREADCLAUSE );
  2329. IMEDesc( VGUI_GCS_RESULTSTR );
  2330. IMEDesc( VGUI_GCS_RESULTCLAUSE );
  2331. IMEDesc( VGUI_CS_INSERTCHAR );
  2332. IMEDesc( VGUI_CS_NOMOVECARET );
  2333. */
  2334. HIMC hIMC = ImmGetContext( ( HWND )GetIMEWindow() );
  2335. if ( hIMC )
  2336. {
  2337. if ( flags & VGUI_GCS_RESULTSTR )
  2338. {
  2339. wchar_t tempstr[ 32 ];
  2340. int len = ImmGetCompositionStringW( hIMC, GCS_RESULTSTR, (LPVOID)tempstr, sizeof( tempstr ) );
  2341. if ( len > 0 )
  2342. {
  2343. if ((len % 2) != 0)
  2344. len++;
  2345. int numchars = len / sizeof( wchar_t );
  2346. for ( int i = 0; i < numchars; ++i )
  2347. {
  2348. InternalKeyTyped( tempstr[ i ] );
  2349. }
  2350. }
  2351. }
  2352. if ( flags & VGUI_GCS_COMPSTR )
  2353. {
  2354. wchar_t tempstr[ 256 ];
  2355. int len = ImmGetCompositionStringW( hIMC, GCS_COMPSTR, (LPVOID)tempstr, sizeof( tempstr ) );
  2356. if ( len > 0 )
  2357. {
  2358. if ((len % 2) != 0)
  2359. len++;
  2360. int numchars = len / sizeof( wchar_t );
  2361. tempstr[ numchars ] = L'\0';
  2362. InternalSetCompositionString( tempstr );
  2363. }
  2364. }
  2365. ImmReleaseContext( ( HWND )GetIMEWindow(), hIMC );
  2366. }
  2367. #endif
  2368. }
  2369. void CInputSystem::OnIMEEndComposition()
  2370. {
  2371. InputContext_t *pContext = GetInputContext( m_hContext );
  2372. if ( pContext )
  2373. {
  2374. // tell the current focused panel that a key was typed
  2375. PostKeyMessage( new KeyValues( "DoCompositionString", "string", L"" ) );
  2376. }
  2377. }
  2378. void CInputSystem::DestroyCandidateList()
  2379. {
  2380. #ifdef DO_IME
  2381. if ( _imeCandidates )
  2382. {
  2383. delete[] (char *)_imeCandidates;
  2384. _imeCandidates = null;
  2385. }
  2386. #endif
  2387. }
  2388. void CInputSystem::OnIMEShowCandidates()
  2389. {
  2390. ASSERT_IF_IME_NYI();
  2391. #ifdef DO_IME
  2392. DestroyCandidateList();
  2393. CreateNewCandidateList();
  2394. InternalShowCandidateWindow();
  2395. #endif
  2396. }
  2397. void CInputSystem::OnIMECloseCandidates()
  2398. {
  2399. ASSERT_IF_IME_NYI();
  2400. #ifdef DO_IME
  2401. InternalHideCandidateWindow();
  2402. DestroyCandidateList();
  2403. #endif
  2404. }
  2405. void CInputSystem::OnIMEChangeCandidates()
  2406. {
  2407. ASSERT_IF_IME_NYI();
  2408. #ifdef DO_IME
  2409. DestroyCandidateList();
  2410. CreateNewCandidateList();
  2411. InternalUpdateCandidateWindow();
  2412. #endif
  2413. }
  2414. void CInputSystem::CreateNewCandidateList()
  2415. {
  2416. ASSERT_IF_IME_NYI();
  2417. #ifdef DO_IME
  2418. Assert( !_imeCandidates );
  2419. HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
  2420. if ( hImc )
  2421. {
  2422. DWORD numCandidates = 0;
  2423. DWORD bytes = ImmGetCandidateListCountW( hImc, &numCandidates );
  2424. if ( numCandidates > 0 )
  2425. {
  2426. DWORD buflen = bytes + 1;
  2427. char *buf = new char[ buflen ];
  2428. Q_memset( buf, 0, buflen );
  2429. CANDIDATELIST *list = ( CANDIDATELIST *)buf;
  2430. DWORD copyBytes = ImmGetCandidateListW( hImc, 0, list, buflen );
  2431. if ( copyBytes > 0 )
  2432. {
  2433. _imeCandidates = list;
  2434. }
  2435. else
  2436. {
  2437. delete[] buf;
  2438. }
  2439. }
  2440. ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
  2441. }
  2442. #endif
  2443. }
  2444. int CInputSystem::GetCandidateListCount()
  2445. {
  2446. ASSERT_IF_IME_NYI();
  2447. #ifdef DO_IME
  2448. if ( !_imeCandidates )
  2449. return 0;
  2450. return (int)_imeCandidates->dwCount;
  2451. #else
  2452. return 0;
  2453. #endif
  2454. }
  2455. void CInputSystem::GetCandidate( int num, wchar_t *dest, int destSizeBytes )
  2456. {
  2457. ASSERT_IF_IME_NYI();
  2458. dest[ 0 ] = L'\0';
  2459. #ifdef DO_IME
  2460. if ( num < 0 || num >= (int)_imeCandidates->dwCount )
  2461. {
  2462. return;
  2463. }
  2464. DWORD offset = *( DWORD *)( (char *)( _imeCandidates->dwOffset + num ) );
  2465. wchar_t *s = ( wchar_t *)( (char *)_imeCandidates + offset );
  2466. wcsncpy( dest, s, destSizeBytes / sizeof( wchar_t ) - 1 );
  2467. dest[ destSizeBytes / sizeof( wchar_t ) - 1 ] = L'\0';
  2468. #endif
  2469. }
  2470. int CInputSystem::GetCandidateListSelectedItem()
  2471. {
  2472. ASSERT_IF_IME_NYI();
  2473. #ifdef DO_IME
  2474. if ( !_imeCandidates )
  2475. return 0;
  2476. return (int)_imeCandidates->dwSelection;
  2477. #else
  2478. return 0;
  2479. #endif
  2480. }
  2481. int CInputSystem::GetCandidateListPageSize()
  2482. {
  2483. ASSERT_IF_IME_NYI();
  2484. #ifdef DO_IME
  2485. if ( !_imeCandidates )
  2486. return 0;
  2487. return (int)_imeCandidates->dwPageSize;
  2488. #else
  2489. return 0;
  2490. #endif
  2491. }
  2492. int CInputSystem::GetCandidateListPageStart()
  2493. {
  2494. ASSERT_IF_IME_NYI();
  2495. #ifdef DO_IME
  2496. if ( !_imeCandidates )
  2497. return 0;
  2498. return (int)_imeCandidates->dwPageStart;
  2499. #else
  2500. return 0;
  2501. #endif
  2502. }
  2503. void CInputSystem::SetCandidateListPageStart( int start )
  2504. {
  2505. ASSERT_IF_IME_NYI();
  2506. #ifdef DO_IME
  2507. HIMC hImc = ImmGetContext( ( HWND )GetIMEWindow() );
  2508. if ( hImc )
  2509. {
  2510. ImmNotifyIME( hImc, NI_SETCANDIDATE_PAGESTART, 0, start );
  2511. ImmReleaseContext( ( HWND )GetIMEWindow(), hImc );
  2512. }
  2513. #endif
  2514. }
  2515. void CInputSystem::OnIMERecomputeModes()
  2516. {
  2517. }
  2518. //-----------------------------------------------------------------------------
  2519. // Purpose:
  2520. // Output : Returns true on success, false on failure.
  2521. //-----------------------------------------------------------------------------
  2522. bool CInputSystem::CandidateListStartsAtOne()
  2523. {
  2524. ASSERT_IF_IME_NYI();
  2525. #ifdef DO_IME
  2526. DWORD prop = ImmGetProperty( GetKeyboardLayout( 0 ), IGP_PROPERTY );
  2527. if ( prop & IME_PROP_CANDLIST_START_FROM_1 )
  2528. {
  2529. return true;
  2530. }
  2531. #endif
  2532. return false;
  2533. }
  2534. void CInputSystem::SetCandidateWindowPos( int x, int y )
  2535. {
  2536. ASSERT_IF_IME_NYI();
  2537. #ifdef DO_IME
  2538. POINT point;
  2539. CANDIDATEFORM Candidate;
  2540. point.x = x;
  2541. point.y = y;
  2542. HIMC hIMC = ImmGetContext( ( HWND )GetIMEWindow() );
  2543. if ( hIMC )
  2544. {
  2545. // Set candidate window position near caret position
  2546. Candidate.dwIndex = 0;
  2547. Candidate.dwStyle = CFS_FORCE_POSITION;
  2548. Candidate.ptCurrentPos.x = point.x;
  2549. Candidate.ptCurrentPos.y = point.y;
  2550. ImmSetCandidateWindow( hIMC, &Candidate );
  2551. ImmReleaseContext( ( HWND )GetIMEWindow(),hIMC );
  2552. }
  2553. #endif
  2554. }
  2555. void CInputSystem::InternalSetCompositionString( const wchar_t *compstr )
  2556. {
  2557. InputContext_t *pContext = GetInputContext( m_hContext );
  2558. if ( pContext )
  2559. {
  2560. // tell the current focused panel that a key was typed
  2561. PostKeyMessage( new KeyValues( "DoCompositionString", "string", compstr ) );
  2562. }
  2563. }
  2564. void CInputSystem::InternalShowCandidateWindow()
  2565. {
  2566. InputContext_t *pContext = GetInputContext( m_hContext );
  2567. if ( pContext )
  2568. {
  2569. PostKeyMessage( new KeyValues( "DoShowIMECandidates" ) );
  2570. }
  2571. }
  2572. void CInputSystem::InternalHideCandidateWindow()
  2573. {
  2574. InputContext_t *pContext = GetInputContext( m_hContext );
  2575. if ( pContext )
  2576. {
  2577. PostKeyMessage( new KeyValues( "DoHideIMECandidates" ) );
  2578. }
  2579. }
  2580. void CInputSystem::InternalUpdateCandidateWindow()
  2581. {
  2582. InputContext_t *pContext = GetInputContext( m_hContext );
  2583. if ( pContext )
  2584. {
  2585. PostKeyMessage( new KeyValues( "DoUpdateIMECandidates" ) );
  2586. }
  2587. }
  2588. bool CInputSystem::GetShouldInvertCompositionString()
  2589. {
  2590. #ifdef DO_IME
  2591. LanguageIds *info = GetLanguageInfo( LOWORD( GetKeyboardLayout( 0 ) ) );
  2592. if ( !info )
  2593. return false;
  2594. // Only Chinese (simplified and traditional)
  2595. return info->invertcomposition;
  2596. #else
  2597. return false;
  2598. #endif
  2599. }
  2600. void CInputSystem::RegisterKeyCodeUnhandledListener( VPANEL panel )
  2601. {
  2602. if ( !panel )
  2603. return;
  2604. InputContext_t *pContext = GetInputContext(m_hContext);
  2605. if ( !pContext )
  2606. return;
  2607. VPanel *listener = (VPanel *)panel;
  2608. if ( pContext->m_KeyCodeUnhandledListeners.Find( listener ) == pContext->m_KeyCodeUnhandledListeners.InvalidIndex() )
  2609. {
  2610. pContext->m_KeyCodeUnhandledListeners.AddToTail( listener );
  2611. }
  2612. }
  2613. void CInputSystem::UnregisterKeyCodeUnhandledListener( VPANEL panel )
  2614. {
  2615. if ( !panel )
  2616. return;
  2617. InputContext_t *pContext = GetInputContext(m_hContext);
  2618. if ( !pContext )
  2619. return;
  2620. VPanel *listener = (VPanel *)panel;
  2621. pContext->m_KeyCodeUnhandledListeners.FindAndRemove( listener );
  2622. }
  2623. // Posts unhandled message to all interested panels
  2624. void CInputSystem::OnKeyCodeUnhandled( int keyCode )
  2625. {
  2626. InputContext_t *pContext = GetInputContext(m_hContext);
  2627. if ( !pContext )
  2628. return;
  2629. int c = pContext->m_KeyCodeUnhandledListeners.Count();
  2630. for ( int i = 0; i < c; ++i )
  2631. {
  2632. VPanel *listener = pContext->m_KeyCodeUnhandledListeners[ i ];
  2633. g_pIVgui->PostMessage((VPANEL)listener, new KeyValues( "KeyCodeUnhandled", "code", keyCode ), NULL );
  2634. }
  2635. }
  2636. void CInputSystem::PostModalSubTreeMessage( VPanel *subTree, bool state )
  2637. {
  2638. InputContext_t *pContext = GetInputContext( m_hContext );
  2639. if( pContext->m_pModalSubTree == NULL )
  2640. return;
  2641. //tell the current focused panel that a key was released
  2642. KeyValues *kv = new KeyValues( "ModalSubTree", "state", state ? 1 : 0 );
  2643. g_pIVgui->PostMessage( (VPANEL)pContext->m_pModalSubTree, kv, NULL );
  2644. }
  2645. // Assumes subTree is a child panel of the root panel for the vgui contect
  2646. // if restrictMessagesToSubTree is true, then mouse and kb messages are only routed to the subTree and it's children and mouse/kb focus
  2647. // can only be on one of the subTree children, if a mouse click occurs outside of the subtree, and "UnhandledMouseClick" message is sent to unhandledMouseClickListener panel
  2648. // if it's set
  2649. // if restrictMessagesToSubTree is false, then mouse and kb messages are routed as normal except that they are not routed down into the subtree
  2650. // however, if a mouse click occurs outside of the subtree, and "UnhandleMouseClick" message is sent to unhandledMouseClickListener panel
  2651. // if it's set
  2652. void CInputSystem::SetModalSubTree( VPANEL subTree, VPANEL unhandledMouseClickListener, bool restrictMessagesToSubTree /*= true*/ )
  2653. {
  2654. InputContext_t *pContext = GetInputContext(m_hContext);
  2655. if ( !pContext )
  2656. return;
  2657. if ( pContext->m_pModalSubTree &&
  2658. pContext->m_pModalSubTree != (VPanel *)subTree )
  2659. {
  2660. ReleaseModalSubTree();
  2661. }
  2662. if ( !subTree )
  2663. return;
  2664. pContext->m_pModalSubTree = (VPanel *)subTree;
  2665. pContext->m_pUnhandledMouseClickListener = (VPanel *)unhandledMouseClickListener;
  2666. pContext->m_bRestrictMessagesToModalSubTree = restrictMessagesToSubTree;
  2667. PostModalSubTreeMessage( pContext->m_pModalSubTree, true );
  2668. }
  2669. void CInputSystem::ReleaseModalSubTree()
  2670. {
  2671. InputContext_t *pContext = GetInputContext(m_hContext);
  2672. if ( !pContext )
  2673. return;
  2674. if ( pContext->m_pModalSubTree )
  2675. {
  2676. PostModalSubTreeMessage( pContext->m_pModalSubTree, false );
  2677. }
  2678. pContext->m_pModalSubTree = NULL;
  2679. pContext->m_pUnhandledMouseClickListener = NULL;
  2680. pContext->m_bRestrictMessagesToModalSubTree = false;
  2681. }
  2682. VPANEL CInputSystem::GetModalSubTree()
  2683. {
  2684. InputContext_t *pContext = GetInputContext(m_hContext);
  2685. if ( !pContext )
  2686. return 0;
  2687. return (VPANEL)pContext->m_pModalSubTree;
  2688. }
  2689. // These toggle whether the modal subtree is exclusively receiving messages or conversely whether it's being excluded from receiving messages
  2690. void CInputSystem::SetModalSubTreeReceiveMessages( bool state )
  2691. {
  2692. InputContext_t *pContext = GetInputContext(m_hContext);
  2693. if ( !pContext )
  2694. return;
  2695. Assert( pContext->m_pModalSubTree );
  2696. if ( !pContext->m_pModalSubTree )
  2697. return;
  2698. pContext->m_bRestrictMessagesToModalSubTree = state;
  2699. }
  2700. bool CInputSystem::ShouldModalSubTreeReceiveMessages() const
  2701. {
  2702. InputContext_t *pContext = const_cast< CInputSystem * >( this )->GetInputContext(m_hContext);
  2703. if ( !pContext )
  2704. return true;
  2705. return pContext->m_bRestrictMessagesToModalSubTree;
  2706. }