Leaked source code of windows server 2003
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.

554 lines
18 KiB

  1. /**************************************************************************\
  2. * Module Name: hotkey.c (corresponds to Win95 hotkey.c)
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * IME hot key management routines for imm32 dll
  7. *
  8. * History:
  9. * 03-Jan-1996 wkwok Created
  10. \**************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // internal functions
  15. //
  16. BOOL CIMENonIMEToggle(HIMC hIMC, HKL hKL, HWND hWnd, LANGID langTarget);
  17. BOOL IMENonIMEToggle( HIMC hIMC, HKL hKL, HWND hWnd, BOOL fIME, LANGID langTarget);
  18. BOOL JCloseOpen( HIMC hIMC, HKL hKL, HWND hWnd);
  19. BOOL CSymbolToggle(HIMC hIMC, HKL hKL, HWND hWnd);
  20. BOOL TShapeToggle(HIMC hIMC, HKL hKL, HWND hWnd);
  21. BOOL KEnglishHangul( HIMC hIMC);
  22. BOOL KShapeToggle( HIMC hIMC);
  23. BOOL KHanjaConvert( HIMC hIMC);
  24. /***************************************************************************\
  25. * ImmGetHotKey()
  26. *
  27. * Private API for IMEs and the control panel. The caller specifies
  28. * the IME hotkey ID:dwID. If a hotkey is registered with the specified
  29. * ID, this function returns the modifiers, vkey and hkl of the hotkey.
  30. *
  31. * History:
  32. * 25-Mar-1996 TakaoK Created
  33. \***************************************************************************/
  34. BOOL WINAPI ImmGetHotKey(
  35. DWORD dwID,
  36. PUINT puModifiers,
  37. PUINT puVKey,
  38. HKL *phkl)
  39. {
  40. if (puModifiers == NULL || puVKey == NULL) {
  41. return FALSE;
  42. }
  43. return NtUserGetImeHotKey( dwID, puModifiers, puVKey, phkl );
  44. }
  45. /**********************************************************************/
  46. /* ImmSimulateHotKey() */
  47. /* Return Value: */
  48. /* TRUE - successful, FALSE - failure */
  49. /**********************************************************************/
  50. BOOL WINAPI ImmSimulateHotKey( // simulate the functionality of that hot key
  51. HWND hAppWnd, // application window handle
  52. DWORD dwHotKeyID)
  53. {
  54. HIMC hImc;
  55. HKL hKL;
  56. BOOL fReturn;
  57. hImc = ImmGetContext( hAppWnd );
  58. hKL = GetKeyboardLayout( GetWindowThreadProcessId(hAppWnd, NULL) );
  59. fReturn = HotKeyIDDispatcher( hAppWnd, hImc, hKL, dwHotKeyID);
  60. ImmReleaseContext( hAppWnd, hImc );
  61. return fReturn;
  62. }
  63. /***************************************************************************\
  64. * SaveImeHotKey()
  65. *
  66. * Put/Remove the specified IME hotkey entry from the registry
  67. *
  68. * History:
  69. * 25-Mar-1996 TakaoK Created
  70. \***************************************************************************/
  71. /**********************************************************************/
  72. /* HotKeyIDDispatcher */
  73. /* Return Value: */
  74. /* TRUE - a hot key processed, FALSE - not processed */
  75. /**********************************************************************/
  76. BOOL HotKeyIDDispatcher( HWND hWnd, HIMC hImc, HKL hKlCurrent, DWORD dwHotKeyID )
  77. {
  78. /*
  79. * Dispatch the IME hotkey event for the specified hImc
  80. * only if the calling thread owns the hImc.
  81. */
  82. if (hImc != NULL_HIMC &&
  83. GetInputContextThread(hImc) != GetCurrentThreadId()) {
  84. return FALSE;
  85. }
  86. switch ( dwHotKeyID ) {
  87. case IME_CHOTKEY_IME_NONIME_TOGGLE:
  88. return CIMENonIMEToggle(hImc, hKlCurrent, hWnd, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED));
  89. case IME_THOTKEY_IME_NONIME_TOGGLE:
  90. return CIMENonIMEToggle(hImc, hKlCurrent, hWnd, MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL));
  91. case IME_CHOTKEY_SYMBOL_TOGGLE:
  92. case IME_THOTKEY_SYMBOL_TOGGLE:
  93. return CSymbolToggle( hImc, hKlCurrent, hWnd);
  94. case IME_JHOTKEY_CLOSE_OPEN:
  95. return JCloseOpen( hImc, hKlCurrent, hWnd);
  96. case IME_KHOTKEY_ENGLISH: // VK_HANGUL : English/Hangul mode
  97. return KEnglishHangul( hImc );
  98. case IME_KHOTKEY_SHAPE_TOGGLE: // VK_JUNJA : full/half width
  99. return KShapeToggle( hImc );
  100. case IME_KHOTKEY_HANJACONVERT: // VK_HANJA : convert hangul to hanja
  101. return KHanjaConvert( hImc );
  102. case IME_CHOTKEY_SHAPE_TOGGLE:
  103. case IME_THOTKEY_SHAPE_TOGGLE:
  104. return TShapeToggle( hImc, hKlCurrent, hWnd);
  105. default:
  106. /*
  107. * Direct swithing hotkey should have been handled in the kernel side.
  108. */
  109. ImmAssert(dwHotKeyID < IME_HOTKEY_DSWITCH_FIRST || dwHotKeyID > IME_HOTKEY_DSWITCH_LAST);
  110. if ( dwHotKeyID >= IME_HOTKEY_PRIVATE_FIRST &&
  111. dwHotKeyID <= IME_HOTKEY_PRIVATE_LAST ) {
  112. PIMEDPI pImeDpi;
  113. BOOL bRet = FALSE;
  114. if ( (pImeDpi = ImmLockImeDpi(hKlCurrent)) != NULL ) {
  115. bRet = (BOOL)(*pImeDpi->pfn.ImeEscape)( hImc,
  116. IME_ESC_PRIVATE_HOTKEY,
  117. (PVOID)&dwHotKeyID );
  118. ImmUnlockImeDpi(pImeDpi);
  119. return bRet;
  120. }
  121. }
  122. }
  123. return (FALSE);
  124. }
  125. /**********************************************************************/
  126. /* JCloseOpen() */
  127. /* Return Value: */
  128. /* TRUE - a hot key processed, FALSE - not processed */
  129. /**********************************************************************/
  130. BOOL JCloseOpen( // open/close toggle
  131. HIMC hIMC,
  132. HKL hCurrentKL,
  133. HWND hWnd)
  134. {
  135. if (ImmIsIME(hCurrentKL) &&
  136. LOWORD(HandleToUlong(hCurrentKL)) == MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT)) {
  137. //
  138. // If current KL is IME and its language is Japanese,
  139. // we only have to switch the open/close status.
  140. //
  141. ImmSetOpenStatus( hIMC, !ImmGetOpenStatus(hIMC) );
  142. } else {
  143. //
  144. // If current KL is not IME or its language is not Japanese,
  145. // we should find the Japanese IME and set it open.
  146. //
  147. if (IMENonIMEToggle(hIMC, hCurrentKL, hWnd, FALSE, MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT))) {
  148. //
  149. // Mark it so that later we can initialize the fOpen
  150. // as expected.
  151. //
  152. PINPUTCONTEXT pInputContext = ImmLockIMC(hIMC);
  153. if (pInputContext) {
  154. pInputContext->fdwDirty |= IMSS_INIT_OPEN;
  155. ImmUnlockIMC(hIMC);
  156. }
  157. }
  158. }
  159. return TRUE;
  160. #if 0 // for your reference : old code ported from Win95
  161. LPINPUTCONTEXT pInputContext;
  162. PIMEDPI pImeDpi;
  163. if ( (pInputContext = ImmLockIMC( hIMC )) == NULL ) {
  164. //
  165. // The return value is same as Win95.
  166. // Not happens so often any way.
  167. //
  168. return TRUE;
  169. }
  170. pImeDpi = ImmLockImeDpi( hCurrentKL );
  171. if ( pImeDpi != NULL ) {
  172. //
  173. // update Input Context
  174. //
  175. pInputContext->fOpen = !pInputContext->fOpen;
  176. //
  177. // notify IME
  178. //
  179. (*pImeDpi->pfn.NotifyIME)( hIMC,
  180. NI_CONTEXTUPDATED,
  181. 0L,
  182. IMC_SETOPENSTATUS );
  183. //
  184. // inform UI
  185. //
  186. SendMessage(hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0L);
  187. SendMessage(hWnd, WM_IME_SYSTEM, IMS_SETOPENSTATUS, 0L);
  188. ImmUnlockIMC( hIMC );
  189. ImmUnlockImeDpi(pImeDpi);
  190. return TRUE;
  191. } else {
  192. if ( !pInputContext->fOpen ) {
  193. pInputContext->fOpen = TRUE;
  194. SendMessage(hWnd, WM_IME_NOTIFY, IMN_SETOPENSTATUS, 0L);
  195. SendMessage(hWnd, WM_IME_SYSTEM, IMS_SETOPENSTATUS, 0L);
  196. }
  197. ImmUnlockIMC( hIMC );
  198. return IMENonIMEToggle(hIMC, hCurrentKL, hWnd, FALSE);
  199. }
  200. #endif
  201. }
  202. /***************************************************************************\
  203. * HotkeyImmIsIME
  204. *
  205. * Checks whether the specified hKL is a HKL of an IME or not.
  206. *
  207. \***************************************************************************/
  208. BOOL HotkeyImmIsIME(
  209. HKL hKL)
  210. {
  211. #if defined(CUAS_ENABLE)
  212. if (!IS_IME_KBDLAYOUT(hKL))
  213. return FALSE;
  214. #else
  215. if (!ImmIsIME(hKL))
  216. return FALSE;
  217. #endif
  218. return TRUE;
  219. }
  220. /**********************************************************************/
  221. /* CIMENonIMEToggle() */
  222. /* Return Value: */
  223. /* TRUE - a hot key processed, FALSE - not processed */
  224. /**********************************************************************/
  225. BOOL CIMENonIMEToggle( // non-IME and IME toggle
  226. HIMC hIMC,
  227. HKL hKlCurrent,
  228. HWND hWnd,
  229. LANGID langId)
  230. {
  231. if (hWnd == NULL)
  232. return(FALSE);
  233. if (!HotkeyImmIsIME(hKlCurrent) || LOWORD(HandleToUlong(hKlCurrent)) != langId)
  234. {
  235. //
  236. // Current keyboard layout is not IME or its language does not match.
  237. // Let's try to switch to our IME.
  238. //
  239. IMENonIMEToggle(hIMC, hKlCurrent, hWnd, FALSE, langId);
  240. return TRUE;
  241. } else {
  242. LPINPUTCONTEXT pInputContext = ImmLockIMC( hIMC );
  243. if ( pInputContext == NULL ) {
  244. //
  245. // returning TRUE even if we didn't change
  246. //
  247. return TRUE;
  248. }
  249. if (!pInputContext->fOpen) {
  250. //
  251. // toggle close to open
  252. //
  253. ImmSetOpenStatus(hIMC, TRUE);
  254. ImmUnlockIMC(hIMC);
  255. return TRUE;
  256. } else {
  257. ImmUnlockIMC(hIMC);
  258. IMENonIMEToggle(hIMC, hKlCurrent, hWnd, TRUE, 0);
  259. return TRUE;
  260. }
  261. }
  262. }
  263. /**********************************************************************/
  264. /* IMENonIMEToggle() */
  265. /* Return Value: */
  266. /* TRUE - a hot key processed, FALSE - not processed */
  267. /**********************************************************************/
  268. BOOL IMENonIMEToggle(
  269. HIMC hIMC,
  270. HKL hCurrentKL,
  271. HWND hWnd,
  272. BOOL fCurrentIsIME,
  273. LANGID langTarget)
  274. {
  275. HKL hEnumKL[32], hTargetKL;
  276. UINT nLayouts, i;
  277. HKL hPrevKL;
  278. UNREFERENCED_PARAMETER(hIMC);
  279. hPrevKL = (HKL)NtUserGetThreadState( UserThreadStatePreviousKeyboardLayout );
  280. //
  281. // If we find the same layout in the layout list, let's switch to
  282. // the layout. If we fail, let's switch to a first-found good
  283. // layout.
  284. //
  285. hTargetKL = NULL;
  286. nLayouts = GetKeyboardLayoutList(sizeof(hEnumKL)/sizeof(HKL), hEnumKL);
  287. // LATER:
  288. // Hmm, looks like we can't simply rely on hPrevKL on multiple lanugage
  289. // environment..
  290. //
  291. if (hPrevKL != NULL) {
  292. if (langTarget == 0 || LOWORD(HandleToUlong(hPrevKL)) == langTarget) {
  293. //
  294. // If langtarget is not specified, or
  295. // if it matches the previous langauge.
  296. //
  297. for (i = 0; i < nLayouts; i++) {
  298. // valid target HKL
  299. if (hEnumKL[i] == hPrevKL) {
  300. hTargetKL = hPrevKL;
  301. break;
  302. }
  303. }
  304. }
  305. }
  306. if (hTargetKL == NULL) {
  307. for (i = 0; i < nLayouts; i++) {
  308. // find a valid target HKL
  309. if (fCurrentIsIME ^ HotkeyImmIsIME(hEnumKL[i])) {
  310. if (langTarget != 0 && LOWORD(HandleToUlong(hEnumKL[i])) != langTarget) {
  311. // If the target language is specified, check it
  312. continue;
  313. }
  314. hTargetKL = hEnumKL[i];
  315. break;
  316. }
  317. }
  318. }
  319. if (hTargetKL != NULL && hCurrentKL != hTargetKL) {
  320. // depends on multilingual message and how to get the base charset
  321. // wait for confirmation of multiingual spec - tmp solution
  322. PostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, DEFAULT_CHARSET, (LPARAM)hTargetKL);
  323. }
  324. //
  325. // returning TRUE, even if we failed to switch
  326. //
  327. return HotkeyImmIsIME(hTargetKL);
  328. }
  329. /**********************************************************************/
  330. /* CSymbolToggle() */
  331. /* Return Value: */
  332. /* TRUE - a hot key processed, FALSE - not processed */
  333. /**********************************************************************/
  334. BOOL CSymbolToggle( // symbol & non symbol toggle
  335. HIMC hIMC,
  336. HKL hKL,
  337. HWND hWnd)
  338. {
  339. LPINPUTCONTEXT pInputContext;
  340. //
  341. // Return TRUE even no layout switching - Win95 behavior
  342. //
  343. if (hWnd == NULL)
  344. return(FALSE);
  345. if ( ! HotkeyImmIsIME( hKL ) ) {
  346. return (FALSE);
  347. }
  348. if ( (pInputContext = ImmLockIMC( hIMC )) == NULL ) {
  349. //
  350. // The return value is same as Win95.
  351. // Not happens so often any way.
  352. //
  353. return TRUE;
  354. }
  355. if (pInputContext->fOpen) {
  356. //
  357. // toggle the symbol mode
  358. //
  359. ImmSetConversionStatus(hIMC,
  360. pInputContext->fdwConversion ^ IME_CMODE_SYMBOL,
  361. pInputContext->fdwSentence);
  362. }
  363. else {
  364. //
  365. // change close -> open
  366. //
  367. ImmSetOpenStatus(hIMC, TRUE);
  368. }
  369. ImmUnlockIMC(hIMC);
  370. return (TRUE);
  371. }
  372. /**********************************************************************/
  373. /* TShapeToggle() */
  374. /* Return Value: */
  375. /* TRUE - a hot key processed, FALSE - not processed */
  376. /**********************************************************************/
  377. BOOL TShapeToggle( // fullshape & halfshape toggle
  378. HIMC hIMC,
  379. HKL hKL,
  380. HWND hWnd)
  381. {
  382. LPINPUTCONTEXT pInputContext;
  383. //
  384. // Return TRUE even no layout switching - Win95 behavior
  385. //
  386. if (hWnd == NULL)
  387. return(FALSE);
  388. if ( ! HotkeyImmIsIME( hKL ) ) {
  389. return (FALSE);
  390. }
  391. if ( (pInputContext = ImmLockIMC( hIMC )) == NULL ) {
  392. //
  393. // The return value is same as Win95.
  394. // Not happens so often any way.
  395. //
  396. return TRUE;
  397. }
  398. if (pInputContext->fOpen) {
  399. //
  400. // toggle the symbol mode
  401. //
  402. ImmSetConversionStatus(hIMC,
  403. pInputContext->fdwConversion ^ IME_CMODE_FULLSHAPE,
  404. pInputContext->fdwSentence);
  405. }
  406. else {
  407. //
  408. // change close -> open
  409. //
  410. ImmSetOpenStatus(hIMC, TRUE);
  411. }
  412. ImmUnlockIMC(hIMC);
  413. return (TRUE);
  414. }
  415. /**********************************************************************/
  416. /* KEnglishHangul() - Egnlish & Hangeul toggle */
  417. /* Return Value: */
  418. /* TRUE - a hot key processed, FALSE - not processed */
  419. /**********************************************************************/
  420. BOOL KEnglishHangul( HIMC hImc )
  421. {
  422. PINPUTCONTEXT pInputContext;
  423. if ((pInputContext = ImmLockIMC(hImc)) != NULL) {
  424. ImmSetConversionStatus(hImc,
  425. pInputContext->fdwConversion ^ IME_CMODE_HANGEUL,
  426. pInputContext->fdwSentence);
  427. if ((pInputContext->fdwConversion & IME_CMODE_HANGEUL) ||
  428. (pInputContext->fdwConversion & IME_CMODE_FULLSHAPE)) {
  429. ImmSetOpenStatus(hImc, TRUE);
  430. } else {
  431. ImmSetOpenStatus(hImc, FALSE);
  432. }
  433. ImmUnlockIMC(hImc);
  434. return TRUE;
  435. }
  436. return FALSE;
  437. }
  438. /**********************************************************************/
  439. /* KShapeToggle() - Fullshape & Halfshape toggle */
  440. /* Return Value: */
  441. /* TRUE - a hot key processed, FALSE - not processed */
  442. /**********************************************************************/
  443. BOOL KShapeToggle( HIMC hImc )
  444. {
  445. PINPUTCONTEXT pInputContext;
  446. if ( (pInputContext = ImmLockIMC( hImc )) != NULL ) {
  447. ImmSetConversionStatus(hImc,
  448. pInputContext->fdwConversion ^ IME_CMODE_FULLSHAPE,
  449. pInputContext->fdwSentence);
  450. if ((pInputContext->fdwConversion & IME_CMODE_HANGEUL)
  451. || (pInputContext->fdwConversion & IME_CMODE_FULLSHAPE))
  452. ImmSetOpenStatus(hImc, TRUE);
  453. else
  454. ImmSetOpenStatus(hImc, FALSE);
  455. ImmUnlockIMC(hImc);
  456. return TRUE;
  457. }
  458. return FALSE;
  459. }
  460. /**********************************************************************/
  461. /* KHanjaConvert() - Hanja conversion toggle */
  462. /* Return Value: */
  463. /* TRUE - a hot key processed, FALSE - not processed */
  464. /**********************************************************************/
  465. BOOL KHanjaConvert( HIMC hImc )
  466. {
  467. PINPUTCONTEXT pInputContext;
  468. if ( (pInputContext = ImmLockIMC( hImc )) != NULL ) {
  469. ImmSetConversionStatus( hImc,
  470. pInputContext->fdwConversion ^ IME_CMODE_HANJACONVERT,
  471. pInputContext->fdwSentence );
  472. ImmUnlockIMC( hImc );
  473. return TRUE;
  474. }
  475. return FALSE;
  476. }