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.

608 lines
16 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: clwinnls.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains all the code for the NT 3.x IMM API functions.
  7. *
  8. * History:
  9. * 11-Jan-1995 wkwok Created.
  10. * 07-May-1996 takaok Cleaned up.
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. BOOL CheckCountry();
  15. BOOL ImmEnableIME( HWND hwnd, BOOL fEnable );
  16. BOOL IMPGetIMEWorker( HKL hkl, LPIMEPROW lpImeProW );
  17. VOID ConvertImeProWtoA( LPIMEPROA lpImeProA, LPIMEPROW lpImeProW );
  18. LRESULT SendIMEMessageAll( HWND hwndApp, HANDLE lParam, BOOL fAnsi );
  19. BOOL ImmWINNLSEnableIME(
  20. HWND hwndApp,
  21. BOOL bFlag)
  22. {
  23. if ( ! CheckCountry() ) {
  24. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  25. return FALSE;
  26. }
  27. return ImmEnableIME( hwndApp, bFlag );
  28. }
  29. //
  30. // returns the "enable/disable" state of the
  31. // caller thread's default input context.
  32. //
  33. BOOL ImmWINNLSGetEnableStatus(
  34. HWND hwndApp)
  35. {
  36. if ( ! CheckCountry() ) {
  37. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  38. return FALSE;
  39. }
  40. return (ImmGetSaveContext(hwndApp, IGSC_WINNLSCHECK) != NULL_HIMC);
  41. }
  42. UINT WINAPI ImmWINNLSGetIMEHotkey(
  43. HWND hwndIme)
  44. {
  45. UNREFERENCED_PARAMETER(hwndIme);
  46. //
  47. // Win95/NT3.51 behavior, i.e. always return 0.
  48. //
  49. return 0;
  50. }
  51. /***************************************************************************\
  52. *
  53. * IME APIs
  54. *
  55. \***************************************************************************/
  56. LRESULT WINAPI ImmSendIMEMessageExW(
  57. HWND hwndApp,
  58. LPARAM lParam)
  59. {
  60. return SendIMEMessageAll( hwndApp, (HANDLE)lParam, FALSE );
  61. }
  62. LRESULT WINAPI ImmSendIMEMessageExA(
  63. HWND hwndApp,
  64. LPARAM lParam)
  65. {
  66. return SendIMEMessageAll( hwndApp, (HANDLE)lParam, TRUE );
  67. }
  68. LRESULT SendIMEMessageAll(
  69. HWND hwndApp,
  70. HANDLE hMemImeStruct,
  71. BOOL fAnsi )
  72. {
  73. HWND hWnd;
  74. LPIMESTRUCT lpIme;
  75. LRESULT lResult;
  76. #ifdef LATER
  77. // Need for MSTEST30a(32bit)...
  78. // If different process of hWnd in SendIMEMessageEx, then we should be inter-send messag
  79. on this.
  80. if (PtiCurrent() != pti) {
  81. HWND hDefIMEWnd = ImmGetDefaultIMEWnd(hWnd);
  82. if (hDefIMEWnd)
  83. return SendMessage(hDefIMEWnd,WM_CONVERTREQUESTEX,(WPARAM)hWnd,lParam);
  84. }
  85. #endif
  86. //
  87. // the passed handle must be the handle of
  88. // global memory block.
  89. //
  90. lpIme = (LPIMESTRUCT)GlobalLock( hMemImeStruct );
  91. if ( lpIme == NULL ) {
  92. return (FALSE);
  93. }
  94. if ( ! CheckCountry( ) ) {
  95. lpIme->wParam = IME_RS_INVALID;
  96. GlobalUnlock( hMemImeStruct );
  97. return (FALSE);
  98. }
  99. //
  100. // We don't need to handle if it's non-IME layout
  101. //
  102. if ( ! ImmIsIME( GetKeyboardLayout(0) ) ) {
  103. lpIme->wParam = IME_RS_INVALID;
  104. GlobalUnlock( hMemImeStruct );
  105. return (FALSE);
  106. }
  107. //
  108. // check if the initialize of IMM has been done.
  109. //
  110. if ( !IsWindow(ImmGetDefaultIMEWnd(hwndApp)) ) {
  111. //
  112. // for Win3.1/Win95 compatibility
  113. // we need to return TRUE here.
  114. //
  115. // PPT4 calls SendImeMessage at the very
  116. // early stage of initialization. If we
  117. // return FALSE here, it thinks IME is
  118. // not available.
  119. //
  120. if ( lpIme->fnc == 0x07 ) // IME_GETVERSION
  121. //
  122. // Excel5.0J calls this function at the early stage
  123. // and we need to return version number.
  124. //
  125. lResult = IMEVER_31;
  126. else
  127. lResult = TRUE;
  128. GlobalUnlock( hMemImeStruct );
  129. return lResult;
  130. }
  131. //
  132. // caller may give us NULL window handle...
  133. //
  134. if ( !IsWindow(hwndApp) ) {
  135. hWnd = GetFocus();
  136. } else {
  137. hWnd = hwndApp;
  138. }
  139. lResult = TranslateIMESubFunctions( hWnd, lpIme, fAnsi );
  140. GlobalUnlock( hMemImeStruct );
  141. return lResult;
  142. }
  143. /***************************************************************************\
  144. *
  145. * IMP APIs
  146. *
  147. \***************************************************************************/
  148. BOOL WINAPI ImmIMPGetIMEW(
  149. HWND hwndApp,
  150. LPIMEPROW lpImeProW)
  151. {
  152. UNREFERENCED_PARAMETER(hwndApp);
  153. if ( ! CheckCountry() ) {
  154. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  155. return FALSE;
  156. }
  157. return IMPGetIMEWorker( GetKeyboardLayout(0), lpImeProW );
  158. }
  159. BOOL WINAPI ImmIMPGetIMEA(
  160. HWND hwndApp,
  161. LPIMEPROA lpImeProA)
  162. {
  163. IMEPROW ImeProW;
  164. UNREFERENCED_PARAMETER(hwndApp);
  165. if ( ! CheckCountry() ) {
  166. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  167. return FALSE;
  168. }
  169. if ( IMPGetIMEWorker( GetKeyboardLayout(0), &ImeProW ) ) {
  170. ConvertImeProWtoA( lpImeProA, &ImeProW );
  171. return TRUE;
  172. }
  173. return FALSE;
  174. }
  175. VOID ConvertImeProWtoA( LPIMEPROA lpImeProA, LPIMEPROW lpImeProW )
  176. {
  177. lpImeProA->hWnd = lpImeProW->hWnd;
  178. lpImeProA->InstDate = lpImeProW->InstDate;
  179. lpImeProA->wVersion = lpImeProW->wVersion;
  180. WideCharToMultiByte( CP_ACP, 0,
  181. lpImeProW->szDescription, -1,
  182. lpImeProA->szDescription, sizeof(lpImeProA->szDescription),
  183. NULL, NULL );
  184. WideCharToMultiByte( CP_ACP, 0,
  185. lpImeProW->szName, -1,
  186. lpImeProA->szName, sizeof(lpImeProA->szName),
  187. NULL, NULL );
  188. lpImeProA->szOptions[0] = '\0';
  189. }
  190. DATETIME CleanDate = {0};
  191. BOOL IMPGetIMEWorker( HKL hkl, LPIMEPROW lpImeProW )
  192. {
  193. IMEINFOEX iiex;
  194. if ( ImmGetImeInfoEx( &iiex, ImeInfoExKeyboardLayout, (PVOID)&hkl) ) {
  195. lpImeProW->hWnd = NULL;
  196. lpImeProW->InstDate = CleanDate;
  197. lpImeProW->wVersion = iiex.dwImeWinVersion;
  198. lstrcpynW( lpImeProW->szDescription, iiex.wszImeDescription, 50 );
  199. lstrcpynW( lpImeProW->szName, iiex.wszImeFile, 80 );
  200. lstrcpynW( lpImeProW->szOptions, TEXT(""), 1 );
  201. return TRUE;
  202. }
  203. return FALSE;
  204. }
  205. BOOL WINAPI ImmIMPQueryIMEW(
  206. LPIMEPROW lpImeProW)
  207. {
  208. BOOL fResult = FALSE;
  209. INT numLayouts = 0;
  210. HKL *phklRoot = NULL;
  211. HKL *phkl = NULL;
  212. if ( ! CheckCountry() ) {
  213. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  214. return FALSE;
  215. }
  216. //
  217. // get the number of keyboard layouts available
  218. //
  219. numLayouts = GetKeyboardLayoutList( 0, NULL );
  220. if ( numLayouts > 0 ) {
  221. //
  222. // allocate the buffer for the array of layouts.
  223. // +1 for a NULL sentinel
  224. //
  225. phklRoot = ImmLocalAlloc( 0, (numLayouts+1) * sizeof(HKL) );
  226. if ( phklRoot != NULL ) {
  227. //
  228. // get the keyboard layouts
  229. //
  230. if ( GetKeyboardLayoutList( numLayouts, phklRoot ) == numLayouts ) {
  231. //
  232. // put a NULL sentinel at the end of the buffer
  233. //
  234. *(phklRoot+numLayouts) = (HKL)NULL;
  235. if ( lpImeProW->szName[0] == L'\0' ) {
  236. //
  237. // This is the first call of IMPQueryIME
  238. // We will start at the first layout.
  239. //
  240. phkl = phklRoot;
  241. } else {
  242. //
  243. // The caller specifies the name of IME.
  244. // We will start at the next layout.
  245. // Note this assumes that the order of keyboard layouts
  246. // returned by GetKeyboardLayoutList() is not changed
  247. // between calls. ( Though actually there is no such
  248. // guarantee, we ignore the chance of the changing
  249. // the list of keyboard layouts for now. )
  250. //
  251. IMEINFOEX iiex;
  252. //
  253. // Let's retrieve the corresponding hkl
  254. // from the IME filename specified by the caller.
  255. //
  256. if ( ImmGetImeInfoEx( &iiex,
  257. ImeInfoExImeFileName,
  258. (PVOID)lpImeProW->szName ) ) {
  259. //
  260. // let phkl point to the next hkl
  261. //
  262. phkl = phklRoot;
  263. while ( *phkl != NULL ) {
  264. if ( *phkl++ == iiex.hkl ) {
  265. break;
  266. }
  267. }
  268. }
  269. }
  270. if ( phkl != NULL ) {
  271. while ( *phkl != NULL ) {
  272. //
  273. // IMPGetIMEWorker will return FALSE if
  274. // the hkl specified is a non-IME layout.
  275. //
  276. if ( fResult = IMPGetIMEWorker(*phkl++, lpImeProW) ) {
  277. break;
  278. }
  279. }
  280. }
  281. }
  282. ImmLocalFree( phklRoot );
  283. }
  284. }
  285. return fResult;
  286. }
  287. BOOL WINAPI ImmIMPQueryIMEA(
  288. LPIMEPROA lpImeProA)
  289. {
  290. IMEPROW ImeProW;
  291. if ( ! CheckCountry() ) {
  292. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  293. return FALSE;
  294. }
  295. if ( lpImeProA->szName[0] != '\0' ) {
  296. //
  297. // Convert MultiByteString(szName) to UnicodeString
  298. //
  299. INT i;
  300. i = MultiByteToWideChar( CP_ACP, (DWORD)MB_PRECOMPOSED,
  301. lpImeProA->szName,
  302. -1,
  303. ImeProW.szName,
  304. (INT)sizeof(ImeProW.szName)/sizeof(WCHAR));
  305. if ( i == 0 ) {
  306. return FALSE;
  307. }
  308. } else {
  309. ImeProW.szName[0] = L'\0';
  310. }
  311. if ( ImmIMPQueryIMEW( &ImeProW ) ) {
  312. ConvertImeProWtoA( lpImeProA, &ImeProW );
  313. return TRUE;
  314. }
  315. return FALSE;
  316. }
  317. BOOL WINAPI ImmIMPSetIMEW(
  318. HWND hwndApp,
  319. LPIMEPROW lpImeProW)
  320. {
  321. IMEINFOEX iiex;
  322. HKL hkl = NULL;
  323. UNREFERENCED_PARAMETER(hwndApp);
  324. if ( ! CheckCountry() ) {
  325. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  326. return FALSE;
  327. }
  328. if ( lpImeProW->szName[0] != L'\0' ) {
  329. //
  330. // IME name is specified. Switch to the IME specified.
  331. //
  332. if ( ImmGetImeInfoEx(&iiex,ImeInfoExImeFileName,(PVOID)lpImeProW->szName) ) {
  333. hkl = iiex.hkl;
  334. }
  335. } else {
  336. //
  337. // IME name is not specified. Switch to a non-IME layout
  338. //
  339. INT numLayouts;
  340. HKL *phkl;
  341. HKL *phklRoot;
  342. numLayouts = GetKeyboardLayoutList( 0, NULL );
  343. if ( numLayouts > 0 ) {
  344. phkl = phklRoot = ImmLocalAlloc( 0, (numLayouts + 1) * sizeof(HKL) );
  345. if ( phkl != NULL ) {
  346. if ( GetKeyboardLayoutList( numLayouts, phkl ) == numLayouts ) {
  347. *(phklRoot+numLayouts) = (HKL)NULL;
  348. while ( *phkl != NULL ) {
  349. if ( ! ImmIsIME( *phkl ) ) {
  350. hkl = *phkl;
  351. break;
  352. }
  353. phkl++;
  354. }
  355. }
  356. ImmLocalFree( phklRoot );
  357. }
  358. }
  359. }
  360. if ( hkl != NULL && GetKeyboardLayout(0) != hkl ) {
  361. HWND hwndFocus;
  362. hwndFocus = GetFocus();
  363. if ( hwndFocus != NULL ) {
  364. PostMessage( hwndFocus,
  365. WM_INPUTLANGCHANGEREQUEST,
  366. DEFAULT_CHARSET,
  367. (LPARAM)hkl);
  368. return TRUE;
  369. }
  370. }
  371. return FALSE;
  372. }
  373. BOOL WINAPI ImmIMPSetIMEA(
  374. HWND hwndApp,
  375. LPIMEPROA lpImeProA)
  376. {
  377. IMEPROW ImeProW;
  378. UNREFERENCED_PARAMETER(hwndApp);
  379. if ( ! CheckCountry() ) {
  380. SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
  381. return FALSE;
  382. }
  383. if ( lpImeProA->szName[0] != '\0' ) {
  384. //
  385. // Convert MultiByteString(szName) to UnicodeString
  386. //
  387. INT i;
  388. i = MultiByteToWideChar( CP_ACP, (DWORD)MB_PRECOMPOSED,
  389. lpImeProA->szName,
  390. -1,
  391. ImeProW.szName,
  392. (INT)sizeof(ImeProW.szName)/sizeof(WCHAR));
  393. if ( i == 0 ) {
  394. return FALSE;
  395. }
  396. } else {
  397. ImeProW.szName[0] = L'\0';
  398. }
  399. return ImmIMPSetIMEW(hwndApp, &ImeProW);
  400. }
  401. //
  402. // if the "enable/disable" state of the default input context
  403. // of the caller thread is same as the state specified by
  404. // fEnalble parameter, this function does nothing but returns
  405. // the current "enable/disable" state.
  406. //
  407. // if fEnable is FALSE, this function disables the default
  408. // input context of caller thread.
  409. //
  410. // if fEnable is TRUE, this function enables the default
  411. // input context of caller thread.
  412. //
  413. //
  414. BOOL ImmEnableIME(
  415. HWND hwnd,
  416. BOOL fEnable
  417. )
  418. {
  419. HIMC hImc;
  420. PCLIENTIMC pClientImc;
  421. BOOL fCurrentState;
  422. HWND hwndFocus;
  423. BOOL fImeInitialized;
  424. //
  425. // Get the caller thread's default input context
  426. //
  427. hImc = (HIMC)NtUserGetThreadState(UserThreadStateDefaultInputContext);
  428. if ( hImc == NULL_HIMC ) {
  429. return FALSE;
  430. }
  431. pClientImc = ImmLockClientImc( hImc );
  432. if ( pClientImc == NULL ) {
  433. return FALSE;
  434. }
  435. //
  436. // we will return the curren t"enable/disable" state of the input context
  437. //
  438. fCurrentState = TestICF(pClientImc, IMCF_WINNLSDISABLE) ? FALSE : TRUE;
  439. //
  440. // if the current thread (caller thread) doesn't have the focus window,
  441. // UI windows will not be updated. When we're called later, we will end
  442. // up to just return the fCurrentState without calling ImmSetActiveContext.
  443. // To avoid that, the "same status" check below is disabled...
  444. if ( (fCurrentState && fEnable) || (!fCurrentState && !fEnable) ) {
  445. ImmUnlockClientImc( pClientImc );
  446. //
  447. // nothing has been changed. return the current state
  448. //
  449. return fCurrentState;
  450. }
  451. if ( ! IsWindow(hwnd) ) {
  452. hwndFocus = GetFocus();
  453. } else {
  454. hwndFocus = hwnd;
  455. }
  456. //
  457. // check if the initialize of IMM has been done.
  458. //
  459. if ( IsWindow(ImmGetDefaultIMEWnd(hwndFocus)) ) {
  460. fImeInitialized = TRUE;
  461. } else {
  462. fImeInitialized = FALSE;
  463. }
  464. if ( fImeInitialized ) {
  465. if ( ! fEnable ) {
  466. //
  467. // we're going to disable the target IMC
  468. //
  469. //
  470. // make the target IMC non-active
  471. //
  472. ImmSetActiveContext( hwndFocus, hImc, FALSE );
  473. } else {
  474. //
  475. // we're going to enable the target IMC
  476. //
  477. //
  478. // make NULL context non-active
  479. //
  480. ImmSetActiveContext( hwndFocus, NULL_HIMC, FALSE );
  481. }
  482. }
  483. //
  484. // update the state of the input context
  485. //
  486. if ( fEnable )
  487. ClrICF( pClientImc, IMCF_WINNLSDISABLE );
  488. else
  489. SetICF( pClientImc, IMCF_WINNLSDISABLE );
  490. ImmUnlockClientImc( pClientImc );
  491. if ( fImeInitialized ) {
  492. if ( fEnable ) {
  493. //
  494. // we're going to enable the target IMC
  495. //
  496. //
  497. // make the target IMC active
  498. //
  499. ImmSetActiveContext( hwndFocus, hImc, TRUE );
  500. } else {
  501. //
  502. // we're going to disable the target IMC
  503. //
  504. //
  505. // make NULL context active
  506. //
  507. ImmSetActiveContext( hwndFocus, NULL_HIMC, TRUE );
  508. }
  509. }
  510. //
  511. // the return value is previous state
  512. //
  513. return fCurrentState;
  514. }
  515. BOOL CheckCountry()
  516. {
  517. WORD LangId;
  518. LangId = PRIMARYLANGID(LANGIDFROMLCID(GetSystemDefaultLCID()));
  519. if ( LangId == LANG_JAPANESE || LangId == LANG_KOREAN ) {
  520. return TRUE;
  521. }
  522. return FALSE;
  523. }