IMECandidate.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. /*
  2. ** Command & Conquer Renegade(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. * FILE
  21. * $Archive: /Commando/Code/wwui/IMECandidate.cpp $
  22. *
  23. * DESCRIPTION
  24. *
  25. * PROGRAMMER
  26. * $Author: Denzil_l $
  27. *
  28. * VERSION INFO
  29. * $Revision: 4 $
  30. * $Modtime: 1/12/02 9:43p $
  31. *
  32. ******************************************************************************/
  33. #include "IMECandidate.h"
  34. #include "WWDebug.h"
  35. namespace IME {
  36. /******************************************************************************
  37. *
  38. * NAME
  39. * IMECandidate::IMECandidate
  40. *
  41. * DESCRIPTION
  42. * Default constructor
  43. *
  44. * INPUTS
  45. * NONE
  46. *
  47. * RESULT
  48. * NONE
  49. *
  50. ******************************************************************************/
  51. IMECandidate::IMECandidate() :
  52. mCandidateSize(0),
  53. mCandidates(NULL)
  54. {
  55. Close();
  56. }
  57. /******************************************************************************
  58. *
  59. * NAME
  60. * IMECandidate::~IMECandidate
  61. *
  62. * DESCRIPTION
  63. * Destructor
  64. *
  65. * INPUTS
  66. * NONE
  67. *
  68. * RESULT
  69. * NONE
  70. *
  71. ******************************************************************************/
  72. IMECandidate::~IMECandidate()
  73. {
  74. if (mCandidates)
  75. {
  76. delete[] mCandidates;
  77. }
  78. }
  79. /******************************************************************************
  80. *
  81. * NAME
  82. * IMECandidate::Open
  83. *
  84. * DESCRIPTION
  85. *
  86. * INPUTS
  87. * Index - Candidate Index ID
  88. * HWND - Window IME is associated with
  89. * CodePage - Code page for current input mode.
  90. * Unicode - If true, process IME as unicode; if false, process as MBCS
  91. * StartFrom1 - If true, candidates should be displayed starting from 1
  92. *
  93. * RESULT
  94. * NONE
  95. *
  96. ******************************************************************************/
  97. void IMECandidate::Open(int id, HWND hwnd, UINT codepage, bool unicode, bool startFrom1)
  98. {
  99. mIndex = id;
  100. mHWND = hwnd;
  101. mCodePage = codepage;
  102. mUseUnicode = unicode;
  103. mStartFrom1 = startFrom1;
  104. }
  105. /******************************************************************************
  106. *
  107. * NAME
  108. * IMECandidate::Read
  109. *
  110. * DESCRIPTION
  111. * Read the candidate list from IMM
  112. *
  113. * INPUTS
  114. * NONE
  115. *
  116. * RESULT
  117. * NONE
  118. *
  119. ******************************************************************************/
  120. void IMECandidate::Read(void)
  121. {
  122. HIMC imc = ImmGetContext(mHWND);
  123. if (imc)
  124. {
  125. DWORD size = 0;
  126. // Get the size of the candidate list
  127. if (mUseUnicode)
  128. {
  129. size = ImmGetCandidateListW(imc, mIndex, NULL, 0);
  130. }
  131. else
  132. {
  133. size = ImmGetCandidateList(imc, mIndex, NULL, 0);
  134. }
  135. // Allocate space to hold candidates
  136. if ((mCandidates == NULL) || (size > mCandidateSize))
  137. {
  138. // Free the existing candidate buffer
  139. if (mCandidates != NULL)
  140. {
  141. delete[] mCandidates;
  142. }
  143. // Allocate a new buffer to hold the candidates
  144. mCandidates = (CANDIDATELIST*)(new unsigned char[size]);
  145. mCandidateSize = size;
  146. }
  147. if (mCandidates != NULL)
  148. {
  149. if (mUseUnicode)
  150. {
  151. ImmGetCandidateListW(imc, mIndex, mCandidates, mCandidateSize);
  152. }
  153. else
  154. {
  155. ImmGetCandidateList(imc, mIndex, mCandidates, mCandidateSize);
  156. }
  157. WWDEBUG_SAY(("IMECandidate: Index %d, Style %08lX, Selection %d, PageStart %d, PageSize %d, Count %d\n",
  158. mIndex, GetStyle(), GetSelection(), GetPageStart(), GetPageSize(), GetCount()));
  159. }
  160. ImmReleaseContext(mHWND, imc);
  161. }
  162. }
  163. /******************************************************************************
  164. *
  165. * NAME
  166. * IMECandidate::Close
  167. *
  168. * DESCRIPTION
  169. * Close the candidate.
  170. *
  171. * INPUTS
  172. * NONE
  173. *
  174. * RESULT
  175. * NONE
  176. *
  177. ******************************************************************************/
  178. void IMECandidate::Close(void)
  179. {
  180. mIndex = -1;
  181. mHWND = NULL;
  182. mCodePage = CP_ACP;
  183. mUseUnicode = true;
  184. mStartFrom1 = true;
  185. if (mCandidates)
  186. {
  187. memset(mCandidates, 0, sizeof(CANDIDATELIST));
  188. }
  189. }
  190. /******************************************************************************
  191. *
  192. * NAME
  193. * IMECandidate::IsValid
  194. *
  195. * DESCRIPTION
  196. * Check if the candidate data is valid.
  197. *
  198. * INPUTS
  199. * NONE
  200. *
  201. * RESULT
  202. * True if valid
  203. *
  204. ******************************************************************************/
  205. bool IMECandidate::IsValid(void) const
  206. {
  207. return ((-1 != mIndex) && (mCandidates != NULL));
  208. }
  209. /******************************************************************************
  210. *
  211. * NAME
  212. * IMECandidate::GetIndex
  213. *
  214. * DESCRIPTION
  215. * Get the candidate index ID
  216. *
  217. * INPUTS
  218. * NONE
  219. *
  220. * RESULT
  221. * Candidate index ID
  222. *
  223. ******************************************************************************/
  224. int IMECandidate::GetIndex(void) const
  225. {
  226. return mIndex;
  227. }
  228. /******************************************************************************
  229. *
  230. * NAME
  231. * IMECandidate::GetStyle
  232. *
  233. * DESCRIPTION
  234. *
  235. * INPUTS
  236. * NONE
  237. *
  238. * RESULT
  239. *
  240. ******************************************************************************/
  241. unsigned long IMECandidate::GetStyle(void) const
  242. {
  243. WWASSERT(mCandidates != NULL);
  244. return mCandidates->dwStyle;
  245. }
  246. /******************************************************************************
  247. *
  248. * NAME
  249. * IMECandidate::GetPageStart
  250. *
  251. * DESCRIPTION
  252. *
  253. * INPUTS
  254. *
  255. * RESULT
  256. *
  257. ******************************************************************************/
  258. unsigned long IMECandidate::GetPageStart(void) const
  259. {
  260. WWASSERT(mCandidates != NULL);
  261. return mCandidates->dwPageStart;
  262. }
  263. /******************************************************************************
  264. *
  265. * NAME
  266. * IMECandidate::SetPageStart
  267. *
  268. * DESCRIPTION
  269. *
  270. * INPUTS
  271. *
  272. * RESULT
  273. * NONE
  274. *
  275. ******************************************************************************/
  276. void IMECandidate::SetPageStart(unsigned long start)
  277. {
  278. WWASSERT((start >=0) && (start < GetCount()));
  279. if ((start >=0) && (start < GetCount()))
  280. {
  281. HIMC imc = ImmGetContext(mHWND);
  282. if (imc)
  283. {
  284. // The IMM documentation says that the candidate list index must
  285. // be in the range of 0 - 3 for NI_SETCANDIDATE_PAGESTART
  286. WWASSERT((mIndex >= 0 && mIndex <= 3) && "IMM parameter error");
  287. ImmNotifyIME(imc, NI_SETCANDIDATE_PAGESTART, mIndex, start);
  288. ImmReleaseContext(mHWND, imc);
  289. }
  290. }
  291. }
  292. /******************************************************************************
  293. *
  294. * NAME
  295. * IMECandidate::GetPageSize
  296. *
  297. * DESCRIPTION
  298. * Get the number of candidates per page.
  299. *
  300. * INPUTS
  301. * NONE
  302. *
  303. * RESULT
  304. *
  305. ******************************************************************************/
  306. unsigned long IMECandidate::GetPageSize(void) const
  307. {
  308. WWASSERT(mCandidates != NULL);
  309. return mCandidates->dwPageSize;
  310. }
  311. /******************************************************************************
  312. *
  313. * NAME
  314. * IMECandidate::GetCount
  315. *
  316. * DESCRIPTION
  317. * Get the total number of candidates.
  318. *
  319. * INPUTS
  320. * NONE
  321. *
  322. * RESULT
  323. *
  324. ******************************************************************************/
  325. // Get the number of candidates in the list.
  326. unsigned long IMECandidate::GetCount(void) const
  327. {
  328. if (mCandidates)
  329. {
  330. return mCandidates->dwCount;
  331. }
  332. return 0;
  333. }
  334. /******************************************************************************
  335. *
  336. * NAME
  337. * IMECandidate::GetSelection
  338. *
  339. * DESCRIPTION
  340. * Get the index of the currently selected candidate.
  341. *
  342. * INPUTS
  343. * NONE
  344. *
  345. * RESULT
  346. *
  347. ******************************************************************************/
  348. unsigned long IMECandidate::GetSelection(void) const
  349. {
  350. WWASSERT(mCandidates != NULL);
  351. return mCandidates->dwSelection;
  352. }
  353. /******************************************************************************
  354. *
  355. * NAME
  356. * IMECandidate::IsStartFrom1
  357. *
  358. * DESCRIPTION
  359. * Check if the candidates should be listed as starting from 1 or 0
  360. *
  361. * INPUTS
  362. * NONE
  363. *
  364. * RESULT
  365. *
  366. ******************************************************************************/
  367. bool IMECandidate::IsStartFrom1(void) const
  368. {
  369. return mStartFrom1;
  370. }
  371. /******************************************************************************
  372. *
  373. * NAME
  374. * IMECandidate::GetCandidate
  375. *
  376. * DESCRIPTION
  377. * Get a candidate string.
  378. *
  379. * INPUTS
  380. * Index of the candidate string to get.
  381. *
  382. * RESULT
  383. * String
  384. *
  385. ******************************************************************************/
  386. const wchar_t* IMECandidate::GetCandidate(unsigned long index)
  387. {
  388. if (index < GetCount())
  389. {
  390. // For the IME_CAND_CODE style, the candidate list has a special structure
  391. // depending on the value of the dwCount member. If dwCount is 1, the dwOffset
  392. // member contains a single DBCS character rather than an offset, and no
  393. // candidate string is provided. If the dwCount member is greater than 1,
  394. // the dwOffset member contains valid offsets, and the candidate strings are
  395. // text representations of individual DBCS character values in hexadecimal notation.
  396. if ((IME_CAND_CODE == GetStyle()) && (1 == GetCount()))
  397. {
  398. unsigned long dbcs = mCandidates->dwOffset[0];
  399. // If this char has a lead byte then it is double byte. Swap the bytes
  400. // for generate string order
  401. if (dbcs & 0xFF00)
  402. {
  403. dbcs = (((dbcs & 0xFF) << 8) | (dbcs >> 8));
  404. }
  405. // Convert char to unicode
  406. MultiByteToWideChar(mCodePage, 0, (const char*)&dbcs, -1, mTempString, 1);
  407. mTempString[1] = 0;
  408. return mTempString;
  409. }
  410. DWORD offset = mCandidates->dwOffset[index];
  411. const char* candString = ((const char*)mCandidates + offset);
  412. if (mUseUnicode)
  413. {
  414. return ((const wchar_t*)candString);
  415. }
  416. MultiByteToWideChar(mCodePage, 0, candString, -1, mTempString, (sizeof(mTempString) / sizeof(wchar_t)));
  417. mTempString[(sizeof(mTempString) / sizeof(wchar_t)) - 1] = 0;
  418. return mTempString;
  419. }
  420. return NULL;
  421. }
  422. /******************************************************************************
  423. *
  424. * NAME
  425. * IMECandidate::SelectCandidate
  426. *
  427. * DESCRIPTION
  428. * Select a string in the candidate list.
  429. *
  430. * INPUTS
  431. * Index of candidate string to select.
  432. *
  433. * RESULT
  434. * NONE
  435. *
  436. ******************************************************************************/
  437. void IMECandidate::SelectCandidate(unsigned long selection)
  438. {
  439. HIMC imc = ImmGetContext(mHWND);
  440. if (imc)
  441. {
  442. ImmNotifyIME(imc, NI_SELECTCANDIDATESTR, mIndex, selection);
  443. ImmNotifyIME(imc, NI_CLOSECANDIDATE, mIndex, 0);
  444. ImmReleaseContext(mHWND, imc);
  445. }
  446. }
  447. /******************************************************************************
  448. *
  449. * NAME
  450. * IMECandidate::SetView
  451. *
  452. * DESCRIPTION
  453. *
  454. * INPUTS
  455. * Top - Index of top candidate.
  456. * Bottom - Index of bottom candidate.
  457. *
  458. * RESULT
  459. *
  460. ******************************************************************************/
  461. void IMECandidate::SetView(unsigned long topIndex, unsigned long bottomIndex)
  462. {
  463. HIMC imc = ImmGetContext(mHWND);
  464. if (imc)
  465. {
  466. ImmNotifyIME(imc, NI_SETCANDIDATE_PAGESIZE, mIndex, (bottomIndex - topIndex) + 1);
  467. ImmNotifyIME(imc, NI_SETCANDIDATE_PAGESTART, mIndex, topIndex);
  468. ImmReleaseContext(mHWND, imc);
  469. }
  470. }
  471. } // namespace IME