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.

541 lines
17 KiB

  1. /*++
  2. Copyright (c) 2001, Microsoft Corporation
  3. Module Name:
  4. candpos.cpp
  5. Abstract:
  6. This file implements the CCandidatePosition Class.
  7. Author:
  8. Revision History:
  9. Notes:
  10. --*/
  11. #include "private.h"
  12. #include "candpos.h"
  13. #include "ctxtcomp.h"
  14. #include "uicomp.h"
  15. HRESULT
  16. CCandidatePosition::GetCandidatePosition(
  17. IN IMCLock& imc,
  18. IN CicInputContext& CicContext,
  19. IN IME_UIWND_STATE uists,
  20. IN LANGID langid,
  21. OUT RECT* out_rcArea
  22. )
  23. {
  24. HRESULT hr;
  25. ::SetRect(out_rcArea, 0, 0, 0, 0);
  26. #if 0
  27. //
  28. // Simplified Chinese TIP's Candidate window create ic and Push it.
  29. // AIMM can know candidate window status.
  30. // If it opened, we returns position of imc->cfCandForm.
  31. // Not use QueryCharPos() because it returns position of Reading window.
  32. //
  33. if (langid == MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED)) {
  34. CAImeContext* _pAImeContext = imc->m_pAImeContext;
  35. if (_pAImeContext == NULL)
  36. return E_FAIL;
  37. if (_pAImeContext->m_fOpenCandidateWindow) {
  38. if (imc->cfCandForm[0].dwStyle != CFS_DEFAULT && imc->cfCandForm[0].dwStyle != CFS_EXCLUDE) {
  39. #if 0
  40. //
  41. // Chinese TIP needs rectangle
  42. //
  43. IMECHARPOSITION ip = {0};
  44. ip.dwSize = sizeof(IMECHARPOSITION);
  45. if (QueryCharPos(ptls, imc, &ip)) {
  46. //
  47. // Sure. Support "query positioning".
  48. //
  49. RECT rect;
  50. hr = GetRectFromApp(imc,
  51. &rect); // rect = screen coordinate.
  52. if (SUCCEEDED(hr)) {
  53. MapWindowPoints(HWND_DESKTOP, imc->hWnd, (LPPOINT)&rect, sizeof(RECT)/sizeof(POINT));
  54. hr = GetRectFromHIMC(imc,
  55. CFS_EXCLUDE,
  56. &imc->cfCandForm[0].ptCurrentPos,
  57. &rect,
  58. out_rcArea);
  59. if (SUCCEEDED(hr))
  60. return hr;
  61. }
  62. }
  63. #endif
  64. //
  65. // Chinese TIP needs rectangle
  66. //
  67. hr = GetRectFromCompFont(imc,
  68. &imc->cfCandForm[0].ptCurrentPos,
  69. out_rcArea);
  70. if (SUCCEEDED(hr))
  71. return hr;
  72. }
  73. hr = GetRectFromHIMC(imc,
  74. imc->cfCandForm[0].dwStyle,
  75. &imc->cfCandForm[0].ptCurrentPos,
  76. &imc->cfCandForm[0].rcArea,
  77. out_rcArea);
  78. return hr;
  79. }
  80. }
  81. #endif
  82. //
  83. // Is apps support "query positioning" ?
  84. //
  85. CicInputContext::IME_QUERY_POS qpos = CicInputContext::IME_QUERY_POS_UNKNOWN;
  86. if (SUCCEEDED(CicContext.InquireIMECharPosition(langid, imc, &qpos)) &&
  87. qpos == CicInputContext::IME_QUERY_POS_YES) {
  88. //
  89. // Sure. Support "query positioning".
  90. //
  91. hr = GetRectFromApp(imc,
  92. CicContext,
  93. langid,
  94. out_rcArea);
  95. if (SUCCEEDED(hr))
  96. return hr;
  97. else
  98. CicContext.ResetIMECharPosition();
  99. }
  100. #if 0
  101. //
  102. // Is apps composition window Level 1 or 2 ?
  103. //
  104. // For Level 1 and 2, there are handled in CInputContextOwnerCallBack::IcoTextExt()
  105. //
  106. IME_UIWND_STATE uists;
  107. uists = UIComposition::InquireImeUIWndState(imc);
  108. if (uists == IME_UIWND_LEVEL1 ||
  109. uists == IME_UIWND_LEVEL2)
  110. {
  111. //
  112. // Get candidate window rectangle from composition
  113. //
  114. DWORD dwCharPos = GetCharPos(imc, langid);
  115. hr = UIComposition::GetCandRectFromComposition(imc, langid, dwCharPos, out_rcArea);
  116. return hr;
  117. }
  118. #endif
  119. //
  120. // This apps is Level 3 or unknown, and do not support "query position".
  121. //
  122. if ( (PRIMARYLANGID(langid) == LANG_CHINESE) &&
  123. (imc->cfCandForm[0].dwIndex == -1 ||
  124. (uists != IME_UIWND_LEVEL3 && CicContext.m_fOpenCandidateWindow.IsResetFlag())
  125. )
  126. )
  127. {
  128. //
  129. // Assume CHT/CHS's Reading Window Position.
  130. //
  131. hr = GetRectFromHIMC(imc, FALSE,
  132. imc->cfCompForm.dwStyle,
  133. &imc->cfCompForm.ptCurrentPos,
  134. &imc->cfCompForm.rcArea,
  135. out_rcArea);
  136. return hr;
  137. }
  138. //
  139. // This apps is Level 3 or unknown, and do not support "query position".
  140. //
  141. if (PRIMARYLANGID(langid) == LANG_KOREAN)
  142. {
  143. hr = GetRectFromHIMC(imc, TRUE,
  144. imc->cfCandForm[0].dwStyle,
  145. &imc->cfCandForm[0].ptCurrentPos,
  146. &imc->cfCandForm[0].rcArea,
  147. out_rcArea);
  148. return hr;
  149. }
  150. //
  151. // This is workaround for IME_UIWND_UNKNOWN case.
  152. // If WM_IME_STARTCOMPOSITION is not comes in, uists set IME_UIWND_UNKNOWN.
  153. //
  154. if ( (uists == IME_UIWND_UNKNOWN) &&
  155. // #513458
  156. // If apps specified any cfCandForm, then ctfime should use it.
  157. (imc->cfCandForm[0].dwIndex == -1))
  158. {
  159. hr = GetRectFromHIMC(imc, FALSE,
  160. imc->cfCompForm.dwStyle,
  161. &imc->cfCompForm.ptCurrentPos,
  162. &imc->cfCompForm.rcArea,
  163. out_rcArea);
  164. }
  165. else
  166. {
  167. hr = GetRectFromHIMC(imc, TRUE,
  168. imc->cfCandForm[0].dwStyle,
  169. &imc->cfCandForm[0].ptCurrentPos,
  170. &imc->cfCandForm[0].rcArea,
  171. out_rcArea);
  172. }
  173. return hr;
  174. }
  175. HRESULT
  176. CCandidatePosition::GetRectFromApp(
  177. IN IMCLock& imc,
  178. IN CicInputContext& CicContext,
  179. IN LANGID langid,
  180. OUT RECT* out_rcArea
  181. )
  182. {
  183. IMECHARPOSITION ip = {0};
  184. ip.dwSize = sizeof(IMECHARPOSITION);
  185. ip.dwCharPos = GetCharPos(imc, langid);
  186. HRESULT hr;
  187. if (SUCCEEDED(hr = CicContext.RetrieveIMECharPosition(imc, &ip))) {
  188. switch (imc.GetDirection()) {
  189. case DIR_TOP_BOTTOM:
  190. ::SetRect(out_rcArea,
  191. ip.pt.x - ip.cLineHeight, // left
  192. ip.pt.y, // top
  193. ip.pt.x, // right
  194. max(ip.pt.y, ip.rcDocument.bottom)); // bottom
  195. break;
  196. case DIR_BOTTOM_TOP:
  197. ::SetRect(out_rcArea,
  198. ip.pt.x - ip.cLineHeight, // left
  199. min(ip.pt.y, ip.rcDocument.top), // top
  200. ip.pt.x, // right
  201. ip.pt.y); // bottom
  202. break;
  203. case DIR_RIGHT_LEFT:
  204. ::SetRect(out_rcArea,
  205. min(ip.pt.x, ip.rcDocument.left), // left
  206. ip.pt.y, // top
  207. ip.pt.x, // right
  208. ip.pt.y + ip.cLineHeight); // bottom
  209. break;
  210. case DIR_LEFT_RIGHT:
  211. ::SetRect(out_rcArea,
  212. ip.pt.x, // left
  213. ip.pt.y, // top
  214. max(ip.pt.x, ip.rcDocument.right), // right
  215. ip.pt.y + ip.cLineHeight); // bottom
  216. break;
  217. }
  218. }
  219. return hr;
  220. }
  221. HRESULT
  222. CCandidatePosition::GetRectFromHIMC(
  223. IN IMCLock& imc,
  224. IN BOOL fCandForm,
  225. IN DWORD dwStyle,
  226. IN POINT* ptCurrentPos,
  227. IN RECT* rcArea,
  228. OUT RECT* out_rcArea
  229. )
  230. {
  231. HWND hWnd = imc->hWnd;
  232. POINT pt;
  233. if (dwStyle == CFS_DEFAULT)
  234. {
  235. ::SystemParametersInfo(SPI_GETWORKAREA,
  236. 0,
  237. out_rcArea,
  238. 0);
  239. out_rcArea->left = out_rcArea->right;
  240. out_rcArea->top = out_rcArea->bottom;
  241. return S_OK;
  242. }
  243. else if (dwStyle & (CFS_RECT | CFS_POINT | CFS_FORCE_POSITION))
  244. {
  245. if (! fCandForm)
  246. {
  247. return GetRectFromCompFont(imc,
  248. ptCurrentPos,
  249. out_rcArea);
  250. }
  251. else
  252. {
  253. out_rcArea->left = ptCurrentPos->x;
  254. out_rcArea->right = ptCurrentPos->x;
  255. out_rcArea->top = ptCurrentPos->y;
  256. out_rcArea->bottom = ptCurrentPos->y;
  257. }
  258. }
  259. else if (dwStyle == CFS_CANDIDATEPOS)
  260. {
  261. //
  262. // We needs rectangle
  263. //
  264. return GetRectFromCompFont(imc,
  265. ptCurrentPos,
  266. out_rcArea);
  267. }
  268. else if (dwStyle == CFS_EXCLUDE)
  269. {
  270. GetCandidateArea(imc, dwStyle, ptCurrentPos, rcArea, out_rcArea);
  271. }
  272. pt.x = pt.y = 0;
  273. ClientToScreen(hWnd, &pt);
  274. out_rcArea->left += pt.x;
  275. out_rcArea->right += pt.x;
  276. out_rcArea->top += pt.y;
  277. out_rcArea->bottom += pt.y;
  278. return S_OK;
  279. }
  280. HRESULT
  281. CCandidatePosition::GetRectFromCompFont(
  282. IN IMCLock& imc,
  283. IN POINT* ptCurrentPos,
  284. OUT RECT* out_rcArea
  285. )
  286. {
  287. HRESULT hr = E_FAIL;
  288. HDC dc = ::GetDC(imc->hWnd);
  289. if (dc != NULL) {
  290. LOGFONT logfont;
  291. if (ImmGetCompositionFont((HIMC)imc, &logfont)) {
  292. HFONT font = ::CreateFontIndirect( &logfont );
  293. if (font != NULL) {
  294. HFONT prev_font;
  295. prev_font = (HFONT)::SelectObject(dc, font);
  296. TEXTMETRIC metric;
  297. if (::GetTextMetrics(dc, &metric)) {
  298. int font_cx = metric.tmMaxCharWidth;
  299. int font_cy = metric.tmHeight;
  300. switch (imc.GetDirection()) {
  301. case DIR_TOP_BOTTOM:
  302. ::SetRect(out_rcArea,
  303. ptCurrentPos->x - font_cx, // left
  304. ptCurrentPos->y, // top
  305. ptCurrentPos->x, // right
  306. ptCurrentPos->y + font_cy); // bottom
  307. break;
  308. case DIR_BOTTOM_TOP:
  309. ::SetRect(out_rcArea,
  310. ptCurrentPos->x, // left
  311. ptCurrentPos->y - font_cy, // top
  312. ptCurrentPos->x + font_cx, // right
  313. ptCurrentPos->y); // bottom
  314. break;
  315. case DIR_RIGHT_LEFT:
  316. ::SetRect(out_rcArea,
  317. ptCurrentPos->x - font_cx, // left
  318. ptCurrentPos->y - font_cy, // top
  319. ptCurrentPos->x, // right
  320. ptCurrentPos->y); // bottom
  321. break;
  322. case DIR_LEFT_RIGHT:
  323. ::SetRect(out_rcArea,
  324. ptCurrentPos->x, // left
  325. ptCurrentPos->y, // top
  326. ptCurrentPos->x + font_cx, // right
  327. ptCurrentPos->y + font_cy); // bottom
  328. break;
  329. }
  330. POINT pt;
  331. pt.x = pt.y = 0;
  332. ClientToScreen(imc->hWnd, &pt);
  333. out_rcArea->left += pt.x;
  334. out_rcArea->right += pt.x;
  335. out_rcArea->top += pt.y;
  336. out_rcArea->bottom += pt.y;
  337. hr = S_OK;
  338. }
  339. ::SelectObject(dc, prev_font);
  340. ::DeleteObject(font);
  341. }
  342. }
  343. ::ReleaseDC(imc->hWnd, dc);
  344. }
  345. return hr;
  346. }
  347. /*
  348. *
  349. * dwStyle == CFS_EXCLUDE
  350. *
  351. */
  352. HRESULT
  353. CCandidatePosition::GetCandidateArea(
  354. IN IMCLock& imc,
  355. IN DWORD dwStyle,
  356. IN POINT* ptCurrentPos,
  357. IN RECT* rcArea,
  358. OUT RECT* out_rcArea
  359. )
  360. {
  361. POINT pt = *ptCurrentPos;
  362. RECT rc = *rcArea;
  363. switch (imc.GetDirection()) {
  364. case DIR_TOP_BOTTOM:
  365. ::SetRect(out_rcArea,
  366. min(pt.x, rcArea->left), // left
  367. max(pt.y, rcArea->top), // top
  368. max(pt.x, rcArea->right), // right
  369. rcArea->bottom); // bottom
  370. break;
  371. case DIR_BOTTOM_TOP:
  372. ::SetRect(out_rcArea,
  373. min(pt.x, rcArea->left), // left
  374. rcArea->top, // top
  375. max(pt.x, rcArea->right), // right
  376. min(pt.y, rcArea->bottom)); // bottom
  377. break;
  378. case DIR_RIGHT_LEFT:
  379. ::SetRect(out_rcArea,
  380. rcArea->left, // left
  381. min(pt.y, rcArea->top), // top
  382. min(pt.x, rcArea->right), // right
  383. max(pt.y, rcArea->bottom)); // bottom
  384. break;
  385. case DIR_LEFT_RIGHT:
  386. ::SetRect(out_rcArea,
  387. max(pt.x, rcArea->left), // left
  388. min(pt.y, rcArea->top), // top
  389. rcArea->right, // right
  390. max(pt.y, rcArea->bottom)); // bottom
  391. break;
  392. }
  393. return S_OK;
  394. }
  395. HRESULT
  396. CCandidatePosition::FindAttributeInCompositionString(
  397. IN IMCLock& imc,
  398. IN BYTE target_attribute,
  399. OUT CWCompCursorPos& wCursorPosition
  400. )
  401. {
  402. HRESULT hr = E_FAIL;
  403. CWCompString wCompString;
  404. CWCompAttribute wCompAttribute;
  405. if (SUCCEEDED(hr = EscbGetTextAndAttribute(imc, &wCompString, &wCompAttribute))) {
  406. LONG num_of_written = (LONG)wCompAttribute.ReadCompData();
  407. if (num_of_written == 0)
  408. return E_FAIL;
  409. BYTE* attribute = new BYTE[ num_of_written ];
  410. if (attribute != NULL) {
  411. //
  412. // Get attribute data.
  413. //
  414. wCompAttribute.ReadCompData(attribute, num_of_written);
  415. LONG start_position = 0;
  416. LONG ich = 0;
  417. LONG attr_size = num_of_written;
  418. while (ich < attr_size && attribute[ich] != target_attribute)
  419. ich++;
  420. if (ich < attr_size) {
  421. start_position = ich;
  422. }
  423. else {
  424. //
  425. // If not hit with target_attribute, then returns S_FALSE.
  426. //
  427. hr = S_FALSE;
  428. }
  429. wCursorPosition.Set(start_position);
  430. delete [] attribute;
  431. }
  432. }
  433. return hr;
  434. }
  435. DWORD
  436. CCandidatePosition::GetCharPos(
  437. IMCLock& imc,
  438. LANGID langid)
  439. {
  440. CWCompCursorPos wCursorPosition;
  441. HRESULT hr;
  442. DWORD dwCharPos = 0;
  443. if (PRIMARYLANGID(langid) == LANG_JAPANESE &&
  444. (hr = FindAttributeInCompositionString(imc,
  445. ATTR_TARGET_CONVERTED,
  446. wCursorPosition)) == S_OK) {
  447. dwCharPos = wCursorPosition.GetAt(0);
  448. }
  449. else if (PRIMARYLANGID(langid) == LANG_JAPANESE &&
  450. (hr = FindAttributeInCompositionString(imc,
  451. ATTR_INPUT,
  452. wCursorPosition)) == S_OK) {
  453. dwCharPos = wCursorPosition.GetAt(0);
  454. }
  455. else {
  456. if (SUCCEEDED(hr = EscbGetCursorPosition(imc, &wCursorPosition))) {
  457. CWCompCursorPos wStartSelection;
  458. CWCompCursorPos wEndSelection;
  459. if (SUCCEEDED(hr = EscbGetStartEndSelection(imc, wStartSelection, wEndSelection))) {
  460. dwCharPos = min(wCursorPosition.GetAt(0),
  461. wStartSelection.GetAt(0));
  462. }
  463. else {
  464. dwCharPos = wCursorPosition.GetAt(0);
  465. }
  466. }
  467. else {
  468. dwCharPos = 0;
  469. }
  470. }
  471. return dwCharPos;
  472. }