IMEManager.cpp 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. //----------------------------------------------------------------------------
  24. //
  25. // Westwood Studios Pacific.
  26. //
  27. // Confidential Information
  28. // Copyright (C) 2001 - All Rights Reserved
  29. //
  30. //----------------------------------------------------------------------------
  31. //
  32. // Project: Ganerals
  33. //
  34. // Module: IME
  35. //
  36. // File name: IMEManager.cpp
  37. //
  38. // Created: 11/14/01 TR
  39. //
  40. //----------------------------------------------------------------------------
  41. //----------------------------------------------------------------------------
  42. // Includes
  43. //----------------------------------------------------------------------------
  44. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  45. #include "Windows.h"
  46. #include "mbstring.h"
  47. #include "Common/Debug.h"
  48. #include "Common/Language.h"
  49. #include "Common/UnicodeString.h"
  50. #include "GameClient/Display.h"
  51. #include "GameClient/GameWindow.h"
  52. #include "GameClient/GameWindowManager.h"
  53. #include "GameClient/GadgetListBox.h"
  54. #include "GameClient/IMEManager.h"
  55. #include "GameClient/Mouse.h"
  56. #include "GameClient/Color.h"
  57. #include "Common/NameKeyGenerator.h"
  58. #ifdef _INTERNAL
  59. // for occasional debugging...
  60. //#pragma optimize("", off)
  61. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  62. #endif
  63. //----------------------------------------------------------------------------
  64. // Externals
  65. //----------------------------------------------------------------------------
  66. extern HWND ApplicationHWnd; ///< our application window handle
  67. extern Int IMECandidateWindowLineSpacing;
  68. //----------------------------------------------------------------------------
  69. // Defines
  70. //----------------------------------------------------------------------------
  71. //#define DEBUG_IME
  72. //----------------------------------------------------------------------------
  73. // Private Types
  74. //----------------------------------------------------------------------------
  75. //===============================
  76. // IMEManager
  77. //===============================
  78. class IMEManager : public IMEManagerInterface
  79. {
  80. public:
  81. IMEManager();
  82. ~IMEManager();
  83. virtual void init( void );
  84. virtual void reset( void );
  85. virtual void update( void );
  86. virtual void attach( GameWindow *window ); ///< attach IME to specified window
  87. virtual void detatch( void ); ///< detatch IME from current window
  88. virtual void enable( void ); ///< Enable IME
  89. virtual void disable( void ); ///< Disable IME
  90. virtual Bool isEnabled( void ); ///< Is IME enabled
  91. virtual Bool isAttachedTo( GameWindow *window ); ///< Is the manager attached toa window
  92. virtual GameWindow* getWindow( void ); ///< Returns the window we are currently attached to
  93. virtual Bool isComposing( void ); ///< Manager is currently composing new input string
  94. virtual void getCompositionString( UnicodeString &string ); ///< Return the current composition string
  95. virtual Int getCompositionCursorPosition( void ); ///< Returns the composition cursor position
  96. virtual Int getIndexBase( void ); ///< Get index base for candidate list
  97. virtual Int getCandidateCount(); ///< Returns the total number of candidates
  98. virtual UnicodeString*getCandidate( Int index ); ///< Returns the candidate string
  99. virtual Int getSelectedCandidateIndex(); ///< Returns the indexed of the currently selected candidate
  100. virtual Int getCandidatePageSize(); ///< Returns the page size for the candidates list
  101. virtual Int getCandidatePageStart(); ///< Returns the index of the first visibel candidate
  102. /// Checks for and services IME messages. Returns TRUE if message serviced
  103. virtual Bool serviceIMEMessage( void *windowsHandle,
  104. UnsignedInt message,
  105. Int wParam,
  106. Int lParam );
  107. virtual Int result( void ); ///< result return value of last serviced IME message
  108. protected:
  109. enum
  110. {
  111. MAX_COMPSTRINGLEN = 2*1024
  112. };
  113. struct MessageInfo
  114. {
  115. Char *name;
  116. Int value;
  117. };
  118. Int m_result; ///< last IME message's winProc return code
  119. GameWindow *m_window; ///< window we are accepting input for
  120. HIMC m_context; ///< Imput Manager Context
  121. HIMC m_oldContext; ///< Previous IME comtext
  122. Int m_disabled; ///< IME disable count 0 = enabled
  123. Bool m_composing; ///< Are we currently composing a new string
  124. WideChar m_compositionString[MAX_COMPSTRINGLEN+1];
  125. WideChar m_resultsString[MAX_COMPSTRINGLEN+1];
  126. Int m_compositionCursorPos;
  127. Int m_compositionStringLength;
  128. Int m_indexBase;
  129. Int m_pageStart; ///< index of first visible candidate
  130. Int m_pageSize; ///< Number of candidate per page
  131. Int m_selectedIndex; ///< Index of the currently selected candidate
  132. Int m_candidateCount; ///< Total number of candidate strings
  133. UnicodeString *m_candidateString; ///< table of canidate strings
  134. Bool m_unicodeIME; ///< Is this an unicode IME
  135. Int m_compositionCharsDisplayed; ///< number of temporary composition characters displayed that need to be replaced with result string.
  136. WideChar convertCharToWide( WPARAM mbchar ); ///< Convert multibyte character to wide
  137. void updateCompositionString( void ); ///< Update the context of the composition string from the IMM
  138. void getResultsString( void ); ///< Get the final composition string result
  139. void updateProperties( void ); ///< Read the current IME properties
  140. void openCandidateList( Int candidateFlags ); ///< open candidate window
  141. void closeCandidateList( Int candidateFlags ); ///< Close candidate window
  142. void updateCandidateList( Int candidateFlags ); ///< Update candidate window
  143. void updateListBox( CANDIDATELIST *candidateList ); ///< Update candidate list box gadget
  144. void convertToUnicode( Char *mbcs, UnicodeString &unicode );
  145. void resizeCandidateWindow( Int pageSize );
  146. void openStatusWindow( void );
  147. void closeStatusWindow( void );
  148. void updateStatusWindow( void );
  149. GameWindow *m_candidateWindow; ///< IME candidate window interface
  150. GameWindow *m_statusWindow; ///< IME status window interface
  151. GameWindow *m_candidateTextArea; ///< list box area
  152. GameWindow *m_candidateUpArrow; ///< up arrow
  153. GameWindow *m_candidateDownArrow; ///< down arrow
  154. #ifdef DEBUG_IME
  155. static MessageInfo m_mainMessageInfo[];
  156. static MessageInfo m_notifyInfo[];
  157. static MessageInfo m_requestInfo[];
  158. static MessageInfo m_controlInfo[];
  159. static MessageInfo m_setContextInfo[];
  160. static MessageInfo m_setCmodeInfo[];
  161. static MessageInfo m_setSmodeInfo[];
  162. Char* getMessageName( MessageInfo *msgTable, Int value );
  163. void buildFlagsString( IMEManager::MessageInfo *msgTable, Int value, AsciiString &string );
  164. void printMessageInfo( Int message, Int wParam, Int lParam );
  165. void printConversionStatus( void );
  166. void printSentenceStatus( void );
  167. #endif
  168. };
  169. //----------------------------------------------------------------------------
  170. // Private Data
  171. //----------------------------------------------------------------------------
  172. #ifdef DEBUG_IME
  173. IMEManager::MessageInfo IMEManager::m_mainMessageInfo[] =
  174. {
  175. { "WM_IME_SETCONTEXT" , WM_IME_SETCONTEXT },
  176. { "WM_IME_NOTIFY" , WM_IME_NOTIFY },
  177. { "WM_IME_CONTROL" , WM_IME_CONTROL },
  178. { "WM_IME_COMPOSITIONFULL" , WM_IME_COMPOSITIONFULL },
  179. { "WM_IME_SELECT" , WM_IME_SELECT },
  180. { "WM_IME_CHAR" , WM_IME_CHAR },
  181. #ifdef WM_IME_REQUST
  182. { "WM_IME_REQUEST" , WM_IME_REQUEST },
  183. #endif
  184. { "WM_IME_KEYDOWN" , WM_IME_KEYDOWN },
  185. { "WM_IME_KEYUP" , WM_IME_KEYUP },
  186. { "WM_IME_STARTCOMPOSITION" , WM_IME_STARTCOMPOSITION},
  187. { "WM_IME_ENDCOMPOSITION" , WM_IME_ENDCOMPOSITION },
  188. { "WM_IME_COMPOSITION" , WM_IME_COMPOSITION },
  189. { "WM_IME_KEYLAST" , WM_IME_KEYLAST },
  190. { NULL, 0 }
  191. };
  192. IMEManager::MessageInfo IMEManager::m_notifyInfo[] =
  193. {
  194. { "IMN_CLOSESTATUSWINDOW" , IMN_CLOSESTATUSWINDOW },
  195. { "IMN_OPENSTATUSWINDOW" , IMN_OPENSTATUSWINDOW },
  196. { "IMN_CHANGECANDIDATE" , IMN_CHANGECANDIDATE },
  197. { "IMN_CLOSECANDIDATE" , IMN_CLOSECANDIDATE },
  198. { "IMN_OPENCANDIDATE" , IMN_OPENCANDIDATE },
  199. { "IMN_SETCONVERSIONMODE" , IMN_SETCONVERSIONMODE },
  200. { "IMN_SETSENTENCEMODE" , IMN_SETSENTENCEMODE },
  201. { "IMN_SETOPENSTATUS" , IMN_SETOPENSTATUS },
  202. { "IMN_SETCANDIDATEPOS" , IMN_SETCANDIDATEPOS },
  203. { "IMN_SETCOMPOSITIONFONT" , IMN_SETCOMPOSITIONFONT },
  204. { "IMN_SETCOMPOSITIONWINDOW" , IMN_SETCOMPOSITIONWINDOW},
  205. { "IMN_SETSTATUSWINDOWPOS" , IMN_SETSTATUSWINDOWPOS },
  206. { "IMN_GUIDELINE" , IMN_GUIDELINE },
  207. { "IMN_PRIVATE" , IMN_PRIVATE },
  208. { NULL, 0 }
  209. };
  210. IMEManager::MessageInfo IMEManager::m_requestInfo[] =
  211. {
  212. #ifdef WM_IME_REQUST
  213. { "IMR_COMPOSITIONWINDOW" , IMR_COMPOSITIONWINDOW },
  214. { "IMR_CANDIDATEWINDOW" , IMR_CANDIDATEWINDOW },
  215. { "IMR_COMPOSITIONFONT" , IMR_COMPOSITIONFONT },
  216. { "IMR_RECONVERTSTRING" , IMR_RECONVERTSTRING },
  217. { "IMR_CONFIRMRECONVERTSTRING" , IMR_CONFIRMRECONVERTSTRING},
  218. #endif
  219. { NULL, 0 }
  220. };
  221. IMEManager::MessageInfo IMEManager::m_controlInfo[] =
  222. {
  223. { "IMC_GETCANDIDATEPOS" , IMC_GETCANDIDATEPOS },
  224. { "IMC_SETCANDIDATEPOS " , IMC_SETCANDIDATEPOS },
  225. { "IMC_GETCOMPOSITIONFONT" , IMC_GETCOMPOSITIONFONT },
  226. { "IMC_SETCOMPOSITIONFONT" , IMC_SETCOMPOSITIONFONT },
  227. { "IMC_GETCOMPOSITIONWINDOW" , IMC_GETCOMPOSITIONWINDOW},
  228. { "IMC_SETCOMPOSITIONWINDOW" , IMC_SETCOMPOSITIONWINDOW},
  229. { "IMC_GETSTATUSWINDOWPOS" , IMC_GETSTATUSWINDOWPOS },
  230. { "IMC_SETSTATUSWINDOWPOS" , IMC_SETSTATUSWINDOWPOS },
  231. { "IMC_CLOSESTATUSWINDOW" , IMC_CLOSESTATUSWINDOW },
  232. { "IMC_OPENSTATUSWINDOW" , IMC_OPENSTATUSWINDOW },
  233. { NULL, 0 }
  234. };
  235. IMEManager::MessageInfo IMEManager::m_setContextInfo[] =
  236. {
  237. { "CANDIDATEWINDOW1" , ISC_SHOWUICANDIDATEWINDOW },
  238. { "CANDIDATEWINDOW2" , ISC_SHOWUICANDIDATEWINDOW<<1 },
  239. { "CANDIDATEWINDOW3" , ISC_SHOWUICANDIDATEWINDOW<<2 },
  240. { "CANDIDATEWINDOW4" , ISC_SHOWUICANDIDATEWINDOW<<3 },
  241. { "COMPOSITIONWINDOW" , ISC_SHOWUICOMPOSITIONWINDOW },
  242. { "GUIDELINE" , ISC_SHOWUIGUIDELINE },
  243. { NULL, 0 }
  244. };
  245. IMEManager::MessageInfo IMEManager::m_setCmodeInfo[] =
  246. {
  247. { "ALPHANUMERIC" , IME_CMODE_ALPHANUMERIC},
  248. { "NATIVE" , IME_CMODE_NATIVE },
  249. { "KATAKANA" , IME_CMODE_KATAKANA },
  250. { "LANGUAGE" , IME_CMODE_LANGUAGE },
  251. { "FULLSHAPE" , IME_CMODE_FULLSHAPE },
  252. { "ROMAN" , IME_CMODE_ROMAN },
  253. { "CHARCODE" , IME_CMODE_CHARCODE },
  254. { "HANJACONVERT" , IME_CMODE_HANJACONVERT},
  255. { "SOFTKBD" , IME_CMODE_SOFTKBD },
  256. { "NOCONVERSION" , IME_CMODE_NOCONVERSION},
  257. { "EUDC" , IME_CMODE_EUDC },
  258. { "SYMBOL" , IME_CMODE_SYMBOL },
  259. { "FIXED" , IME_CMODE_FIXED },
  260. { NULL, 0 }
  261. };
  262. IMEManager::MessageInfo IMEManager::m_setSmodeInfo[] =
  263. {
  264. { "NONE" , IME_SMODE_NONE },
  265. { "PLAURALCLAUSE" , IME_SMODE_PLAURALCLAUSE},
  266. { "SINGLECONVERT" , IME_SMODE_SINGLECONVERT},
  267. { "AUTOMATIC" , IME_SMODE_AUTOMATIC },
  268. { "PHRASEPREDICT" , IME_SMODE_PHRASEPREDICT},
  269. { "CONVERSATION" , IME_SMODE_CONVERSATION },
  270. { NULL, 0 }
  271. };
  272. #endif
  273. //----------------------------------------------------------------------------
  274. // Public Data
  275. //----------------------------------------------------------------------------
  276. IMEManagerInterface *TheIMEManager = NULL;
  277. //----------------------------------------------------------------------------
  278. // Private Prototypes
  279. //----------------------------------------------------------------------------
  280. //----------------------------------------------------------------------------
  281. // Private Functions
  282. //----------------------------------------------------------------------------
  283. #ifdef DEBUG_IME
  284. //============================================================================
  285. // IMEManager::getMessageName
  286. //============================================================================
  287. Char* IMEManager::getMessageName( IMEManager::MessageInfo *msgTable, Int value )
  288. {
  289. Char *name = NULL;
  290. if ( msgTable )
  291. {
  292. while ( msgTable->name )
  293. {
  294. if ( msgTable->value == value )
  295. {
  296. name = msgTable->name;
  297. break;
  298. }
  299. msgTable++;
  300. }
  301. }
  302. return name;
  303. }
  304. //============================================================================
  305. // IMEManager::buildFlagsString
  306. //============================================================================
  307. void IMEManager::buildFlagsString( IMEManager::MessageInfo *msgTable, Int value, AsciiString &string )
  308. {
  309. string.clear();
  310. Bool first = TRUE;
  311. if ( msgTable )
  312. {
  313. while ( msgTable->name )
  314. {
  315. if ( msgTable->value & value )
  316. {
  317. if ( !first )
  318. {
  319. string.concat( "|" );
  320. first = FALSE;
  321. }
  322. string.concat( msgTable->name );
  323. }
  324. msgTable++;
  325. }
  326. }
  327. }
  328. //============================================================================
  329. // IMEManager::printMessageInfo
  330. //============================================================================
  331. void IMEManager::printMessageInfo( Int message, Int wParam, Int lParam )
  332. {
  333. Char *messageText = getMessageName( m_mainMessageInfo, message);
  334. switch( message )
  335. {
  336. case WM_IME_NOTIFY:
  337. {
  338. Char *notifyName = getMessageName( m_notifyInfo, wParam );
  339. if ( notifyName == NULL ) notifyName = "unknown";
  340. DEBUG_LOG(( "IMM: %s(0x%04x) - %s(0x%04x) - 0x%08x\n", messageText, message, notifyName, wParam, lParam ));
  341. break;
  342. }
  343. case WM_IME_CONTROL:
  344. {
  345. Char *controlName = getMessageName( m_controlInfo, wParam );
  346. if ( controlName == NULL ) controlName = "unknown";
  347. DEBUG_LOG(( "IMM: %s(0x%04x) - %s(0x%04x) - 0x%08x\n", messageText, message, controlName, wParam, lParam ));
  348. break;
  349. }
  350. #ifdef WM_IME_REQUEST
  351. case WM_IME_REQUEST:
  352. {
  353. Char *requestName = getMessageName( m_requestInfo, wParam );
  354. if ( requestName == NULL ) requestName = "unknown";
  355. DEBUG_LOG(( "IMM: %s(0x%04x) - %s(0x%04x) - 0x%08x\n", messageText, message, requestName, wParam, lParam ));
  356. break;
  357. }
  358. #endif
  359. case WM_IME_SETCONTEXT:
  360. {
  361. AsciiString flags;
  362. buildFlagsString( m_setContextInfo, lParam, flags );
  363. DEBUG_LOG(( "IMM: %s(0x%04x) - 0x%08x - %s(0x%04x)\n", messageText, message, wParam, flags.str(), lParam ));
  364. break;
  365. }
  366. default:
  367. if ( messageText )
  368. {
  369. DEBUG_LOG(( "IMM: %s(0x%04x) - 0x%08x - 0x%08x\n", messageText, message, wParam, lParam ));
  370. }
  371. break;
  372. }
  373. }
  374. //============================================================================
  375. // IMEManager::printConversionStatus
  376. //============================================================================
  377. void IMEManager::printConversionStatus( void )
  378. {
  379. DWORD mode;
  380. if ( m_context )
  381. {
  382. ImmGetConversionStatus( m_context, &mode, NULL );
  383. AsciiString flags;
  384. buildFlagsString( m_setCmodeInfo, mode, flags );
  385. DEBUG_LOG(( "IMM: Conversion mode = (%s)\n", flags.str()));
  386. }
  387. }
  388. //============================================================================
  389. // IMEManager::printSentenceStatus
  390. //============================================================================
  391. void IMEManager::printSentenceStatus( void )
  392. {
  393. DWORD mode;
  394. if ( m_context )
  395. {
  396. ImmGetConversionStatus( m_context, NULL, &mode );
  397. AsciiString flags;
  398. buildFlagsString( m_setSmodeInfo, mode, flags );
  399. DEBUG_LOG(( "IMM: Sentence mode = (%s)\n", flags.str()));
  400. }
  401. }
  402. #endif // DEBUG_IME
  403. //----------------------------------------------------------------------------
  404. // Public Functions
  405. //----------------------------------------------------------------------------
  406. //============================================================================
  407. // *CreateIMEManagerInterface
  408. //============================================================================
  409. IMEManagerInterface *CreateIMEManagerInterface( void )
  410. {
  411. return NEW IMEManager;
  412. }
  413. //============================================================================
  414. // IMEManager::IMEManager
  415. //============================================================================
  416. IMEManager::IMEManager()
  417. : m_window(NULL),
  418. m_context(NULL),
  419. m_candidateWindow(NULL),
  420. m_statusWindow(NULL),
  421. m_candidateCount(0),
  422. m_candidateString(NULL),
  423. m_compositionStringLength(0),
  424. m_composing(FALSE),
  425. m_disabled(0),
  426. m_result(0),
  427. m_indexBase(1),
  428. //Added By Sadullah Nader
  429. //Initializations missing and needed
  430. m_compositionCharsDisplayed(0),
  431. m_candidateDownArrow(NULL),
  432. m_candidateTextArea(NULL),
  433. m_candidateUpArrow(NULL),
  434. m_compositionCursorPos(0),
  435. m_pageSize(0),
  436. m_pageStart(0),
  437. m_selectedIndex(0),
  438. m_unicodeIME(FALSE)
  439. //
  440. {
  441. }
  442. //============================================================================
  443. // IMEManager::~IMEManager
  444. //============================================================================
  445. IMEManager::~IMEManager()
  446. {
  447. if ( m_candidateWindow )
  448. {
  449. TheWindowManager->winDestroy( m_candidateWindow );
  450. }
  451. if ( m_statusWindow )
  452. {
  453. TheWindowManager->winDestroy( m_statusWindow );
  454. }
  455. if ( m_candidateString )
  456. {
  457. delete [] m_candidateString;
  458. }
  459. detatch();
  460. ImmAssociateContext( ApplicationHWnd, m_oldContext );
  461. ImmReleaseContext( ApplicationHWnd, m_oldContext );
  462. if ( m_context )
  463. {
  464. ImmDestroyContext( m_context );
  465. }
  466. }
  467. //============================================================================
  468. // IMEManager::init
  469. //============================================================================
  470. void IMEManager::init( void )
  471. {
  472. //HWND ImeWindow = ImmGetDefaultIMEWnd(ApplicationHWnd);
  473. // if(ImeWindow)
  474. // {
  475. // DestroyWindow(ImeWindow);
  476. // }
  477. m_context = ImmCreateContext();
  478. m_oldContext = ImmGetContext( ApplicationHWnd );
  479. m_disabled = 0;
  480. m_candidateWindow = TheWindowManager->winCreateFromScript( AsciiString("IMECandidateWindow.wnd"));
  481. m_candidateWindow->winSetStatus(WIN_STATUS_ABOVE);
  482. if ( m_candidateWindow )
  483. {
  484. m_candidateWindow->winHide( TRUE );
  485. // find text area window
  486. NameKeyType id = TheNameKeyGenerator->nameToKey( AsciiString( "IMECandidateWindow.wnd:TextArea" ) );
  487. m_candidateTextArea = TheWindowManager->winGetWindowFromId(m_candidateWindow, id);
  488. // find arrows
  489. id = TheNameKeyGenerator->nameToKey( AsciiString( "IMECandidateWindow.wnd:UpArrow" ) );
  490. m_candidateUpArrow = TheWindowManager->winGetWindowFromId(m_candidateWindow, id);
  491. id = TheNameKeyGenerator->nameToKey( AsciiString( "IMECandidateWindow.wnd:DownArrow" ) );
  492. m_candidateDownArrow = TheWindowManager->winGetWindowFromId(m_candidateWindow, id);
  493. if ( m_candidateTextArea == NULL )
  494. {
  495. TheWindowManager->winDestroy( m_candidateWindow );
  496. m_candidateWindow = NULL;
  497. }
  498. }
  499. m_statusWindow = TheWindowManager->winCreateFromScript( AsciiString("IMEStatusWindow.wnd"));
  500. if ( m_statusWindow )
  501. {
  502. m_statusWindow->winHide( TRUE );
  503. }
  504. // attach IMEManager to each window
  505. if ( m_candidateWindow != NULL )
  506. {
  507. m_candidateWindow->winSetUserData( TheIMEManager );
  508. m_candidateTextArea->winSetUserData( TheIMEManager );
  509. }
  510. detatch();
  511. enable();
  512. }
  513. //============================================================================
  514. // IMEManager::reset
  515. //============================================================================
  516. void IMEManager::reset( void )
  517. {
  518. }
  519. //============================================================================
  520. // IMEManager::update
  521. //============================================================================
  522. void IMEManager::update( void )
  523. {
  524. }
  525. //============================================================================
  526. // IMEManager::attach
  527. //============================================================================
  528. void IMEManager::attach( GameWindow *window )
  529. {
  530. if ( m_window != window )
  531. {
  532. detatch();
  533. if ( m_disabled == 0 )
  534. {
  535. ImmAssociateContext( ApplicationHWnd, m_context );
  536. updateStatusWindow();
  537. //openStatusWindow();
  538. }
  539. m_window = window;
  540. }
  541. }
  542. //============================================================================
  543. // IMEManager::detatch
  544. //============================================================================
  545. void IMEManager::detatch( void )
  546. {
  547. //ImmAssociateContext( ApplicationHWnd, NULL );
  548. m_window = NULL;
  549. }
  550. //============================================================================
  551. // IMEManager::serviceIMEMessage
  552. //============================================================================
  553. Bool IMEManager::serviceIMEMessage( void *windowsHandle, UnsignedInt message, Int wParam, Int lParam )
  554. {
  555. DEBUG_ASSERTCRASH( windowsHandle == ApplicationHWnd, ("Unexpected window handle for IMEManager") );
  556. #ifdef DEBUG_IME
  557. printMessageInfo( message, wParam, lParam );
  558. #endif
  559. switch(message){
  560. // --------------------------------------------------------------------
  561. case WM_IME_CHAR:
  562. {
  563. WideChar wchar = convertCharToWide(wParam);
  564. #ifdef DEBUG_IME
  565. DEBUG_LOG(("IMM: WM_IME_CHAR - '%hc'0x%04x\n", wchar, wchar ));
  566. #endif
  567. if ( m_window && (wchar > 32 || wchar == VK_RETURN ))
  568. {
  569. TheWindowManager->winSendInputMsg( m_window, GWM_IME_CHAR, (wParam & 0xffff), lParam );
  570. m_result = 0;
  571. return TRUE;
  572. }
  573. return FALSE;
  574. }
  575. // --------------------------------------------------------------------
  576. case WM_CHAR:
  577. {
  578. WideChar wchar = (WideChar) (wParam & 0xffff);
  579. #ifdef DEBUG_IME
  580. DEBUG_LOG(("IMM: WM_CHAR - '%hc'0x%04x\n", wchar, wchar ));
  581. #endif
  582. if ( m_window && (wchar >= 32 || wchar == VK_RETURN) )
  583. {
  584. TheWindowManager->winSendInputMsg( m_window, GWM_IME_CHAR, (wParam & 0xffff), lParam );
  585. m_result = 0;
  586. return TRUE;
  587. }
  588. return FALSE;
  589. }
  590. // --------------------------------------------------------------------
  591. case WM_IME_SELECT:
  592. DEBUG_LOG(("IMM: WM_IME_SELECT\n"));
  593. return FALSE;
  594. case WM_IME_STARTCOMPOSITION:
  595. //The WM_IME_STARTCOMPOSITION message is sent immediately before an
  596. //IME generates a composition string as a result of a user's keystroke.
  597. //
  598. m_composing = TRUE;
  599. m_compositionCharsDisplayed = 0;
  600. updateCompositionString();
  601. m_result = 1;
  602. return TRUE;
  603. // --------------------------------------------------------------------
  604. case WM_IME_ENDCOMPOSITION:
  605. {
  606. //First remove the composition characters
  607. m_composing = FALSE;
  608. while (m_compositionCharsDisplayed > 0)
  609. { //if cursor has moved since start of composition, we need to move it back using backspace message
  610. TheWindowManager->winSendInputMsg( m_window, GWM_CHAR, KEY_BACKSPACE, KEY_STATE_DOWN);
  611. m_compositionCharsDisplayed--;
  612. }
  613. closeCandidateList(0);
  614. return TRUE;
  615. // I removed the rest of this message handler because we update
  616. // the strings real time inside WM_IME_COMPOSITION
  617. // instead of waiting for user to enter separator. -MW
  618. //IMEs send this message to the application when the IMEs' composition
  619. //windows have closed. Applications that display their own composition
  620. //characters should process this message. Other applications should
  621. //send the message to the application IME window or to DefWindowProc,
  622. //which will pass the message to the default IME window.
  623. //
  624. m_composing = FALSE; // reset this flag before calling GWM_IME_CHAR
  625. if ( m_window )
  626. {
  627. WideChar *ch = m_resultsString;
  628. getResultsString();
  629. while ( *ch )
  630. {
  631. TheWindowManager->winSendInputMsg( m_window, GWM_IME_CHAR, *ch, 0 );
  632. ch++;
  633. }
  634. }
  635. m_result = 1;
  636. return TRUE;
  637. }
  638. // --------------------------------------------------------------------
  639. case WM_IME_COMPOSITION:
  640. {
  641. //IMEs send this message to the application when they change composition
  642. //status in response to a keystroke. Applications that display their own
  643. //composition characters should process this message by calling
  644. //ImmGetCompositionString. Other applications should send the message to
  645. //the application IME window or to DefWindowProc, which will pass the
  646. //message to the default IME window.
  647. //
  648. //The WM_IME_COMPOSITION message is sent to an application when the IME
  649. //changes composition status as a result of a keystroke. An application
  650. //should process this message if it displays composition characters itself.
  651. //Otherwise, it should send the message to the IME window. This message
  652. //has no return value. wParam = DBCS character. lParam = change indicator.
  653. //
  654. if (lParam & GCS_RESULTSTR) //added to show instant updates as soon as a character is translated. -MW
  655. {
  656. if ( m_window )
  657. {
  658. m_composing = FALSE; // reset this flag before calling GWM_IME_CHAR
  659. while (m_compositionCharsDisplayed > 0)
  660. { //if cursor has moved since start of composition, we need to move it back using backspace message
  661. TheWindowManager->winSendInputMsg( m_window, GWM_CHAR, KEY_BACKSPACE, KEY_STATE_DOWN);
  662. m_compositionCharsDisplayed--;
  663. }
  664. WideChar *ch = m_resultsString;
  665. getResultsString();
  666. while ( *ch )
  667. {
  668. TheWindowManager->winSendInputMsg( m_window, GWM_IME_CHAR, *ch, 0 );
  669. ch++;
  670. }
  671. }
  672. m_compositionCharsDisplayed = 0;
  673. }
  674. else
  675. if (lParam & CS_INSERTCHAR && lParam & CS_NOMOVECARET)
  676. { //we are supposed to display the composition character without moving the cursor. (it's a candidate).
  677. if (m_window)
  678. {
  679. m_composing = FALSE; // reset this flag before calling GWM_IME_CHAR
  680. while (m_compositionCharsDisplayed > 0)
  681. { //if cursor has moved since start of composition, we need to move it back using backspace message
  682. TheWindowManager->winSendInputMsg( m_window, GWM_CHAR, KEY_BACKSPACE, KEY_STATE_DOWN);
  683. m_compositionCharsDisplayed--;
  684. }
  685. WideChar *ch = m_compositionString;
  686. updateCompositionString();
  687. while (*ch)
  688. {
  689. TheWindowManager->winSendInputMsg(m_window, GWM_IME_CHAR, *ch, 0 );
  690. ch++;
  691. m_compositionCharsDisplayed++;
  692. }
  693. m_composing = TRUE; // reset this flag before calling GWM_IME_CHAR
  694. }
  695. }
  696. else
  697. if (lParam & GCS_COMPSTR)
  698. { //we are supposed to display the composition character without moving the cursor. (it's a candidate).
  699. if (m_window)
  700. {
  701. m_composing = FALSE; // reset this flag before calling GWM_IME_CHAR
  702. while (m_compositionCharsDisplayed > 0)
  703. { //if cursor has moved since start of composition, we need to move it back using backspace message
  704. TheWindowManager->winSendInputMsg( m_window, GWM_CHAR, KEY_BACKSPACE, KEY_STATE_DOWN);
  705. m_compositionCharsDisplayed--;
  706. }
  707. WideChar *ch = m_compositionString;
  708. updateCompositionString();
  709. while (*ch)
  710. {
  711. TheWindowManager->winSendInputMsg(m_window, GWM_IME_CHAR, *ch, 0 );
  712. ch++;
  713. m_compositionCharsDisplayed++;
  714. }
  715. m_composing = TRUE; // reset this flag before calling GWM_IME_CHAR
  716. }
  717. }
  718. m_result = 1;
  719. return TRUE;
  720. }
  721. // --------------------------------------------------------------------
  722. case WM_IME_SETCONTEXT:
  723. {
  724. //The system sends this message to an application when one of the
  725. //application's windows is activated. Applications should respond by
  726. //calling ImmGetContext.
  727. //
  728. updateProperties();
  729. //ignore for now
  730. m_result = 0;
  731. return FALSE;
  732. }
  733. // --------------------------------------------------------------------
  734. case WM_IME_NOTIFY:
  735. {
  736. //IMEs generate this message to notify the application or the IME window
  737. //that the IME status has changed. The wParam value is a submessage that
  738. //specifies the nature of the change.
  739. //
  740. switch(wParam)
  741. {
  742. case IMN_OPENCANDIDATE:
  743. {
  744. //This message is sent to the application when an IME is about to
  745. //open the candidate window. An application should process this
  746. //message if it displays candidates. The application can retrieve
  747. //a list of candidates to display by using theImmGetCandidateList
  748. //function. The application receives this notification message through
  749. //the WM_IME_NOTIFY message.
  750. //
  751. // open candidate window
  752. openCandidateList( lParam );
  753. m_result = 1;
  754. return TRUE;
  755. }
  756. case IMN_CLOSECANDIDATE:
  757. {
  758. //This message is sent to the application when an IME is about to
  759. //close the candidate window. An application should process this
  760. //message if it displays candidates. The application receives this
  761. //notification message through the WM_IME_NOTIFY message.
  762. //
  763. closeCandidateList( lParam );
  764. m_result = 1;
  765. return TRUE;
  766. }
  767. case IMN_CHANGECANDIDATE:
  768. {
  769. //This message is sent to the application when an IME is about to
  770. //change the content of the candidate window. An application should
  771. //process this notification message if it displays candidates itself.
  772. //The application receives this notification message through the
  773. //WM_IME_NOTIFY message.
  774. //
  775. updateCandidateList( lParam );
  776. m_result = 1;
  777. return TRUE;
  778. }
  779. case IMN_GUIDELINE: //This message is sent when an IME is about to show an error message or other data.
  780. {
  781. // display error message
  782. m_result = 1;
  783. return FALSE;
  784. }
  785. case IMN_SETCONVERSIONMODE: //This message is sent when the conversion mode of the input context is updated.
  786. {
  787. #ifdef DEBUG_IME
  788. printConversionStatus();
  789. #endif
  790. return FALSE;
  791. }
  792. case IMN_SETSENTENCEMODE: //This message is sent when the sentence mode of the input context is updated.
  793. {
  794. #ifdef DEBUG_IME
  795. printSentenceStatus();
  796. #endif
  797. return FALSE;
  798. }
  799. /*
  800. // pass the reset on through to the installed IME
  801. case IMN_SETCANDIDATEPOS: //This message is sent when the IME is about to move the candidate window.
  802. case IMN_SETSTATUSWINDOWPOS: //This message is sent when the status window position in the input context is updated.
  803. return FALSE;
  804. case IMN_OPENSTATUSWINDOW: //This message is sent when an IME is about to create the status window.
  805. DEBUG_LOG(("Open Status Window"));
  806. return FALSE;
  807. case IMN_CLOSESTATUSWINDOW: //This message is sent to the application when an input method editor (IME) is about to close the status window.
  808. DEBUG_LOG(("Close Status Window"));
  809. return FALSE;
  810. case IMN_SETOPENSTATUS: //This message is sent when the open status of the input context is updated.
  811. case IMN_SETCOMPOSITIONFONT: //This message is sent when the font of the input context is updated.
  812. case IMN_SETCOMPOSITIONWINDOW: //This message is sent when the style or position of the composition window is updated.
  813. case IMN_PRIVATE: //This message is for your own use, it seems.
  814. */ default:
  815. m_result = 1;
  816. return TRUE;
  817. }
  818. break;
  819. }
  820. // --------------------------------------------------------------------
  821. case WM_IME_COMPOSITIONFULL:
  822. {
  823. //IMEs send this message to the application when they are unable to
  824. //extend the composition window to accommodate any more characters.
  825. //Applications should tell IMEs how to display the composition window
  826. //using the IMC_SETCOMPOSITIONWINDOW message.
  827. //
  828. //I'm not sure what to do here.
  829. m_result = 1;
  830. return TRUE;
  831. }
  832. }
  833. return FALSE;
  834. }
  835. //============================================================================
  836. // IMEManager::result
  837. //============================================================================
  838. Int IMEManager::result( void )
  839. {
  840. return m_result;
  841. }
  842. //============================================================================
  843. // IMEManager::enable
  844. //============================================================================
  845. void IMEManager::enable( void )
  846. {
  847. if ( --m_disabled <= 0 )
  848. {
  849. m_disabled = 0;
  850. ImmAssociateContext( ApplicationHWnd, m_context );
  851. }
  852. }
  853. //============================================================================
  854. // IMEManager::disable
  855. //============================================================================
  856. void IMEManager::disable( void )
  857. {
  858. m_disabled++;
  859. ImmAssociateContext( ApplicationHWnd, NULL );
  860. }
  861. //============================================================================
  862. // IMEManager::isEnabled
  863. //============================================================================
  864. Bool IMEManager::isEnabled( void )
  865. {
  866. return m_context != NULL && m_disabled == 0;
  867. }
  868. //============================================================================
  869. // IMEManager::isAttached
  870. //============================================================================
  871. Bool IMEManager::isAttachedTo( GameWindow *window )
  872. {
  873. return m_window == window;
  874. }
  875. //============================================================================
  876. // IMEManager::getWindow
  877. //============================================================================
  878. GameWindow* IMEManager::getWindow( void )
  879. {
  880. return m_window;
  881. }
  882. //============================================================================
  883. // IMEManager::convertChartoWide
  884. //============================================================================
  885. WideChar IMEManager::convertCharToWide( WPARAM wParam )
  886. {
  887. char dcbsString[3];
  888. if ( wParam&0xff00 )
  889. {
  890. dcbsString[0] = (wParam>>8)&0xff;
  891. dcbsString[1] = wParam&0xff;
  892. dcbsString[2] = 0;
  893. }
  894. else
  895. {
  896. dcbsString[0] = wParam&0xff;
  897. dcbsString[1] = 0;
  898. }
  899. WideChar uniString[2];
  900. if ( MultiByteToWideChar( CP_ACP, 0, dcbsString, strlen( dcbsString ), uniString, 1 ) == 1 )
  901. {
  902. return uniString[0];
  903. }
  904. return 0;
  905. }
  906. //============================================================================
  907. // IMEManager::isComposing
  908. //============================================================================
  909. Bool IMEManager::isComposing( void )
  910. {
  911. return m_composing;
  912. }
  913. void IMEManager::getCompositionString ( UnicodeString &string )
  914. {
  915. string.set(m_compositionString);
  916. }
  917. //============================================================================
  918. // IMEManager::getCompositionCursorPosition
  919. //============================================================================
  920. Int IMEManager::getCompositionCursorPosition( void )
  921. {
  922. return 0;//m_compositionCursorPos;
  923. }
  924. //============================================================================
  925. // IMEManager::updateCompositionString
  926. //============================================================================
  927. void IMEManager::updateCompositionString( void )
  928. {
  929. char tempBuf[ (MAX_COMPSTRINGLEN+1)*2];
  930. m_compositionCursorPos = 0;
  931. m_compositionString[0] = 0;
  932. m_compositionStringLength = 0;
  933. if ( m_context )
  934. {
  935. // try reading unicode directy
  936. LONG result = ImmGetCompositionStringW( m_context, GCS_COMPSTR, m_compositionString, MAX_COMPSTRINGLEN );
  937. if ( result >= 0 )
  938. {
  939. m_compositionStringLength = result/2;
  940. m_compositionCursorPos = (ImmGetCompositionStringW( m_context, GCS_CURSORPOS, NULL, 0) & 0xffff );
  941. }
  942. else
  943. {
  944. // read MBCS instead
  945. result = ImmGetCompositionStringA( m_context, GCS_COMPSTR, tempBuf, MAX_COMPSTRINGLEN*2);
  946. if ( result > 0 )
  947. {
  948. tempBuf[ result ] = '\0';
  949. int convRes = MultiByteToWideChar( CP_ACP, 0, tempBuf, -1, m_compositionString, MAX_COMPSTRINGLEN );
  950. GameArrayEnd(m_compositionString);
  951. if ( convRes < 0)
  952. {
  953. convRes = 0;
  954. }
  955. else
  956. {
  957. m_compositionCursorPos = (ImmGetCompositionString( m_context, GCS_CURSORPOS, NULL, 0) & 0xffff );
  958. convRes = GameStrlen ( m_compositionString );
  959. }
  960. // m_compositionCursorPos is in DBCS characters, need to convert it to Wide characters
  961. //msg_assert ( (int)strlen(tempBuf) >= convRes ,("bad DBCS string: DBCS = %d chars, Wide = %d chars", strlen(tempBuf), convRes));
  962. m_compositionCursorPos = _mbsnccnt ( (unsigned char *) tempBuf, m_compositionCursorPos );
  963. m_compositionString[convRes] = 0;
  964. m_compositionStringLength = convRes;
  965. if ( m_compositionCursorPos > convRes )
  966. {
  967. m_compositionCursorPos = convRes;
  968. }
  969. else if ( m_compositionCursorPos < 0 )
  970. {
  971. m_compositionCursorPos = 0;
  972. }
  973. }
  974. }
  975. }
  976. DEBUG_ASSERTCRASH( m_compositionStringLength < MAX_COMPSTRINGLEN, ("composition string too large"));
  977. m_compositionString[m_compositionStringLength] = 0;
  978. GameArrayEnd(m_compositionString);
  979. }
  980. //============================================================================
  981. // IMEManager::getResultsString
  982. //============================================================================
  983. void IMEManager::getResultsString ( void )
  984. {
  985. Int stringLen = 0;
  986. m_resultsString[0] = 0;
  987. if ( m_context )
  988. {
  989. // try reading unicode directy
  990. LONG result = ImmGetCompositionStringW( m_context, GCS_RESULTSTR, m_resultsString, MAX_COMPSTRINGLEN );
  991. if ( result >= 0 )
  992. {
  993. stringLen = result/2;
  994. }
  995. else
  996. {
  997. char tempBuf[ (MAX_COMPSTRINGLEN+1)*2];
  998. // read MBCS instead
  999. result = ImmGetCompositionStringA( m_context, GCS_RESULTSTR, tempBuf, MAX_COMPSTRINGLEN*2);
  1000. if ( result > 0 )
  1001. {
  1002. tempBuf[ result ] = '\0';
  1003. int convRes = MultiByteToWideChar( CP_ACP, 0, tempBuf, strlen(tempBuf), m_resultsString, MAX_COMPSTRINGLEN );
  1004. if ( convRes < 0)
  1005. {
  1006. convRes = 0;
  1007. }
  1008. stringLen = convRes;
  1009. }
  1010. }
  1011. }
  1012. DEBUG_ASSERTCRASH( stringLen < MAX_COMPSTRINGLEN, ("results string too large"));
  1013. m_resultsString[stringLen] = 0;
  1014. GameArrayEnd(m_resultsString);
  1015. }
  1016. //============================================================================
  1017. // IMEManager::convertToUnicode
  1018. //============================================================================
  1019. void IMEManager::convertToUnicode ( Char *mbcs, UnicodeString &unicode )
  1020. {
  1021. int size = MultiByteToWideChar( CP_ACP, 0, mbcs, strlen(mbcs), NULL, 0 );
  1022. unicode.clear();
  1023. if ( size <= 0 )
  1024. {
  1025. return;
  1026. }
  1027. WideChar *buffer = NEW WideChar[ size + 1 ];
  1028. if ( buffer )
  1029. {
  1030. size = MultiByteToWideChar( CP_ACP, 0, mbcs, strlen(mbcs), buffer, size );
  1031. if ( size <= 0 )
  1032. {
  1033. unicode.clear();
  1034. }
  1035. else
  1036. {
  1037. buffer[size] = 0;
  1038. unicode = buffer;
  1039. }
  1040. delete [] buffer;
  1041. }
  1042. }
  1043. //============================================================================
  1044. // IMEManager::openCandidateList
  1045. //============================================================================
  1046. void IMEManager::openCandidateList( Int candidateFlags )
  1047. {
  1048. if ( m_candidateWindow == NULL )
  1049. {
  1050. return;
  1051. }
  1052. // first get lastest candidate list info
  1053. updateCandidateList( candidateFlags );
  1054. resizeCandidateWindow( m_pageSize );
  1055. m_candidateWindow->winHide( FALSE );
  1056. m_candidateWindow->winBringToTop();
  1057. TheWindowManager->winSetModal( m_candidateWindow );
  1058. Int wx, wy, wwidth, wheight, wcursorx, wcursory;
  1059. Int cx, cy, cwidth, cheight;
  1060. Int textHeight = 20;
  1061. if ( m_window )
  1062. {
  1063. m_window->winGetScreenPosition( &wx, &wy);
  1064. m_window->winGetSize( &wwidth, &wheight );
  1065. m_window->winGetCursorPosition( &wcursorx, &wcursory );
  1066. GameFont *font = m_window->winGetFont();
  1067. if ( font )
  1068. {
  1069. textHeight = font->height;
  1070. }
  1071. }
  1072. else
  1073. {
  1074. wx = wy = 0;
  1075. wwidth = 10;
  1076. wheight = 10;
  1077. wcursorx = 0;
  1078. wcursory = 0;
  1079. }
  1080. m_candidateWindow->winGetSize( &cwidth, &cheight );
  1081. // // try putting the candidate list above the text
  1082. // cx = wx + wcursorx;
  1083. // cy = wy - cheight;
  1084. //
  1085. // if ( cx + cwidth > (Int) TheDisplay->getWidth())
  1086. // {
  1087. // cx = cx - cwidth;
  1088. // }
  1089. // if( cx < 0 )
  1090. // cx = 0;
  1091. // if ( cy < 0 )
  1092. // {
  1093. // // place list below text
  1094. // cy = wy + textHeight + textHeight/2;
  1095. // }
  1096. // if( cy + cheight > TheDisplay->getHeight())
  1097. // cy = 0;
  1098. cx = TheDisplay->getWidth() - cwidth;
  1099. cy = 0;
  1100. updateProperties();
  1101. m_candidateWindow->winSetPosition( cx, cy );
  1102. }
  1103. //============================================================================
  1104. // IMEManager::closeCandidateList
  1105. //============================================================================
  1106. void IMEManager::closeCandidateList( Int candidateFlags )
  1107. {
  1108. if ( m_candidateWindow != NULL )
  1109. {
  1110. m_candidateWindow->winHide( TRUE );
  1111. TheWindowManager->winUnsetModal( m_candidateWindow );
  1112. }
  1113. if ( m_candidateString )
  1114. {
  1115. delete [] m_candidateString;
  1116. m_candidateString = NULL;
  1117. }
  1118. m_candidateCount = 0;
  1119. }
  1120. //============================================================================
  1121. // IMEManager::updateCandidateList
  1122. //============================================================================
  1123. void IMEManager::updateCandidateList( Int candidateFlags )
  1124. {
  1125. if ( m_candidateString )
  1126. {
  1127. delete [] m_candidateString;
  1128. m_candidateString = NULL;
  1129. }
  1130. m_pageSize = 10;
  1131. m_candidateCount = 0;
  1132. m_pageStart = 0;
  1133. m_selectedIndex = 0;
  1134. if ( m_candidateWindow == NULL ||
  1135. m_context == NULL ||
  1136. candidateFlags == 0)
  1137. {
  1138. return;
  1139. }
  1140. for( Int i = 0, candidate = 1; i < 32; i++, candidate = candidate << 1 )
  1141. {
  1142. if ( candidateFlags & candidate )
  1143. {
  1144. Bool unicode = TRUE;
  1145. unsigned long listCount = 0;
  1146. Int size = ImmGetCandidateListCountW( m_context, &listCount );
  1147. if ( size <= 0 )
  1148. {
  1149. unicode = FALSE;
  1150. size = ImmGetCandidateListCountA( m_context, &listCount );
  1151. if ( size <= 0 )
  1152. {
  1153. return;
  1154. }
  1155. }
  1156. // create a temporary buffer for reading the candidate list
  1157. Char *buffer = NEW Char[size];
  1158. if ( buffer == NULL )
  1159. {
  1160. return;
  1161. }
  1162. memset( buffer, 0, size );
  1163. CANDIDATELIST *clist = (CANDIDATELIST*) buffer;
  1164. Bool ok = TRUE ;
  1165. Int bytesCopied;
  1166. if ( unicode )
  1167. {
  1168. bytesCopied = ImmGetCandidateListW( m_context, i, (CANDIDATELIST*) clist, size );
  1169. }
  1170. else
  1171. {
  1172. bytesCopied = ImmGetCandidateListA( m_context, i, (CANDIDATELIST*) clist, size );
  1173. }
  1174. if ( bytesCopied == 0 || bytesCopied > size )
  1175. {
  1176. DEBUG_ASSERTCRASH(bytesCopied < size,("IME candidate buffer overrun"));
  1177. ok = FALSE;
  1178. }
  1179. if ( ok && clist->dwStyle != IME_CAND_UNKNOWN && clist->dwStyle != IME_CAND_CODE )
  1180. {
  1181. //Apparently there is an "IME98 bug" (IME bug under Windows 98?) that
  1182. //causes you to have to execute the following code.
  1183. if(( clist->dwPageStart > clist->dwSelection) ||
  1184. (clist->dwSelection >= clist->dwPageStart + clist->dwPageSize))
  1185. {
  1186. clist->dwPageStart = (clist->dwSelection / clist->dwPageSize) * clist->dwPageSize;
  1187. }
  1188. m_pageSize = clist->dwPageSize;
  1189. m_candidateCount = clist->dwCount;
  1190. m_pageStart = clist->dwPageStart;
  1191. m_selectedIndex = clist->dwSelection;
  1192. #ifdef DEBUG_IME
  1193. DEBUG_LOG(("IME: Candidate Update: Candidates = %d, pageSize = %d pageStart = %d, selected = %d\n", m_candidateCount, m_pageStart, m_pageSize, m_selectedIndex ));
  1194. #endif
  1195. if ( m_candidateUpArrow )
  1196. {
  1197. m_candidateUpArrow->winHide( m_pageStart == 0 );
  1198. }
  1199. if ( m_candidateDownArrow )
  1200. {
  1201. m_candidateDownArrow->winHide( m_candidateCount - m_pageStart <= m_pageSize );
  1202. }
  1203. if ( m_candidateCount > 0 )
  1204. {
  1205. m_candidateString = NEW UnicodeString[m_candidateCount];
  1206. if ( m_candidateString )
  1207. {
  1208. Int i;
  1209. for( i=0; i < m_candidateCount; i++ )
  1210. {
  1211. Char *string = (Char*) ((UnsignedInt) clist + (UnsignedInt) clist->dwOffset[i]);
  1212. if ( unicode )
  1213. {
  1214. m_candidateString[i].set( (WideChar *) string);
  1215. }
  1216. else
  1217. {
  1218. convertToUnicode( string, m_candidateString[i] );
  1219. }
  1220. }
  1221. }
  1222. }
  1223. }
  1224. delete [] buffer;
  1225. return;
  1226. }
  1227. }
  1228. }
  1229. //============================================================================
  1230. // IMEManager::updateProperties
  1231. //============================================================================
  1232. void IMEManager::updateProperties( void )
  1233. {
  1234. HKL kb = GetKeyboardLayout( 0 );
  1235. Int prop = ImmGetProperty( kb, IGP_PROPERTY );
  1236. m_indexBase = prop & IME_PROP_CANDLIST_START_FROM_1 ? 1 : 0 ;
  1237. m_unicodeIME = (prop & IME_PROP_UNICODE) != 0 ;
  1238. }
  1239. //============================================================================
  1240. // IMEManager::getIndexBase
  1241. //============================================================================
  1242. Int IMEManager::getIndexBase( void )
  1243. {
  1244. return m_indexBase;
  1245. }
  1246. //============================================================================
  1247. // IMEManager::resizeCandidateWindow
  1248. //============================================================================
  1249. void IMEManager::resizeCandidateWindow( Int pageSize )
  1250. {
  1251. if ( m_candidateWindow == NULL )
  1252. {
  1253. return;
  1254. }
  1255. GameFont *font = m_candidateTextArea->winGetFont();
  1256. if ( font == NULL )
  1257. {
  1258. return;
  1259. }
  1260. Int newh = pageSize * (font->height + IMECandidateWindowLineSpacing);
  1261. Int w, h;
  1262. m_candidateTextArea->winGetSize( &w, &h );
  1263. Int dif = newh - h;
  1264. m_candidateTextArea->winSetSize( w, newh );
  1265. m_candidateWindow->winGetSize( &w, &h );
  1266. h += dif;
  1267. m_candidateWindow->winSetSize( w, h );
  1268. if ( m_candidateDownArrow )
  1269. {
  1270. Int x, y;
  1271. m_candidateDownArrow->winGetPosition( &x, &y );
  1272. y += dif;
  1273. m_candidateDownArrow->winSetPosition( x, y );
  1274. }
  1275. }
  1276. //============================================================================
  1277. // IMEManager::getCandidateCount
  1278. //============================================================================
  1279. Int IMEManager::getCandidateCount()
  1280. {
  1281. return m_candidateCount;
  1282. }
  1283. //============================================================================
  1284. // IMEManager::getCandidate
  1285. //============================================================================
  1286. UnicodeString* IMEManager::getCandidate( Int index )
  1287. {
  1288. if ( m_candidateString != NULL && index >=0 && index < m_candidateCount )
  1289. {
  1290. return &m_candidateString[index];
  1291. }
  1292. return &UnicodeString::TheEmptyString;
  1293. }
  1294. //============================================================================
  1295. // IMEManager::getSelectedCandidateIndex
  1296. //============================================================================
  1297. Int IMEManager::getSelectedCandidateIndex()
  1298. {
  1299. return m_selectedIndex;
  1300. }
  1301. //============================================================================
  1302. // IMEManager::getCandidatePageSize
  1303. //============================================================================
  1304. Int IMEManager::getCandidatePageSize()
  1305. {
  1306. return m_pageSize;
  1307. }
  1308. //============================================================================
  1309. // IMEManager::getStartCandidateIndex
  1310. //============================================================================
  1311. Int IMEManager::getCandidatePageStart()
  1312. {
  1313. return m_pageStart;
  1314. }
  1315. //============================================================================
  1316. // IMEManager::openStatusWindow
  1317. //============================================================================
  1318. void IMEManager::openStatusWindow( void )
  1319. {
  1320. if ( m_statusWindow == NULL )
  1321. {
  1322. return;
  1323. }
  1324. m_statusWindow->winHide( FALSE );
  1325. }
  1326. //============================================================================
  1327. // IMEManager::closeStatusWindow
  1328. //============================================================================
  1329. void IMEManager::closeStatusWindow( void )
  1330. {
  1331. if ( m_statusWindow == NULL )
  1332. {
  1333. return;
  1334. }
  1335. m_statusWindow->winHide( TRUE );
  1336. }
  1337. //============================================================================
  1338. // IMEManager::updateStatusWindow
  1339. //============================================================================
  1340. void IMEManager::updateStatusWindow( void )
  1341. {
  1342. }