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.

3040 lines
84 KiB

  1. //
  2. // candui.cpp
  3. //
  4. #include "private.h"
  5. #include "globals.h"
  6. #include "candui.h"
  7. #include "wcand.h"
  8. #include "immxutil.h"
  9. #include "computil.h"
  10. #include "candutil.h"
  11. #include "candobj.h"
  12. #include "msctfp.h"
  13. //
  14. // default key command definition
  15. //
  16. // key command definition in list style
  17. const CANDUIKEYDATA rgKeyDefList[] =
  18. {
  19. /*
  20. { flag, keydata, command, paramater }
  21. */
  22. { CANDUIKEY_VKEY, VK_ESCAPE, CANDUICMD_CANCEL, 0 },
  23. { CANDUIKEY_VKEY, VK_RETURN, CANDUICMD_COMPLETE, 0 },
  24. { CANDUIKEY_VKEY|CANDUIKEY_SHIFT, VK_CONVERT, CANDUICMD_MOVESELPREV, 0 },
  25. { CANDUIKEY_VKEY, VK_CONVERT, CANDUICMD_MOVESELNEXT, 0 },
  26. { CANDUIKEY_VKEY|CANDUIKEY_SHIFT, VK_SPACE, CANDUICMD_MOVESELPREV, 0 },
  27. { CANDUIKEY_VKEY, VK_SPACE, CANDUICMD_MOVESELNEXT, 0 },
  28. { CANDUIKEY_VKEY, VK_UP, CANDUICMD_MOVESELUP, 0 }, // horz only
  29. { CANDUIKEY_VKEY, VK_DOWN, CANDUICMD_MOVESELDOWN, 0 }, // horz only
  30. { CANDUIKEY_VKEY, VK_LEFT, CANDUICMD_MOVESELLEFT, 0 }, // vert only
  31. { CANDUIKEY_VKEY, VK_RIGHT, CANDUICMD_MOVESELRIGHT, 0 }, // vert only
  32. { CANDUIKEY_VKEY, VK_PRIOR, CANDUICMD_MOVESELPREVPG, 0 },
  33. { CANDUIKEY_VKEY, VK_NEXT, CANDUICMD_MOVESELNEXTPG, 0 },
  34. { CANDUIKEY_VKEY, VK_HOME, CANDUICMD_MOVESELFIRST, 0 },
  35. { CANDUIKEY_VKEY, VK_END, CANDUICMD_MOVESELLAST, 0 },
  36. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'1', CANDUICMD_SELECTLINE, 1 },
  37. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'2', CANDUICMD_SELECTLINE, 2 },
  38. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'3', CANDUICMD_SELECTLINE, 3 },
  39. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'4', CANDUICMD_SELECTLINE, 4 },
  40. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'5', CANDUICMD_SELECTLINE, 5 },
  41. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'6', CANDUICMD_SELECTLINE, 6 },
  42. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'7', CANDUICMD_SELECTLINE, 7 },
  43. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'8', CANDUICMD_SELECTLINE, 8 },
  44. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'9', CANDUICMD_SELECTLINE, 9 },
  45. { CANDUIKEY_VKEY|CANDUIKEY_NOSHIFT|CANDUIKEY_NOCTRL, L'0', CANDUICMD_SELECTEXTRACAND, 0 },
  46. { CANDUIKEY_VKEY, VK_OEM_MINUS, CANDUICMD_SELECTRAWDATA, 0 },
  47. { CANDUIKEY_VKEY, VK_NUMPAD1, CANDUICMD_SELECTLINE, 1 },
  48. { CANDUIKEY_VKEY, VK_NUMPAD2, CANDUICMD_SELECTLINE, 2 },
  49. { CANDUIKEY_VKEY, VK_NUMPAD3, CANDUICMD_SELECTLINE, 3 },
  50. { CANDUIKEY_VKEY, VK_NUMPAD4, CANDUICMD_SELECTLINE, 4 },
  51. { CANDUIKEY_VKEY, VK_NUMPAD5, CANDUICMD_SELECTLINE, 5 },
  52. { CANDUIKEY_VKEY, VK_NUMPAD6, CANDUICMD_SELECTLINE, 6 },
  53. { CANDUIKEY_VKEY, VK_NUMPAD7, CANDUICMD_SELECTLINE, 7 },
  54. { CANDUIKEY_VKEY, VK_NUMPAD8, CANDUICMD_SELECTLINE, 8 },
  55. { CANDUIKEY_VKEY, VK_NUMPAD9, CANDUICMD_SELECTLINE, 9 },
  56. { CANDUIKEY_VKEY, VK_NUMPAD0, CANDUICMD_SELECTEXTRACAND, 0 },
  57. { CANDUIKEY_VKEY, VK_SUBTRACT, CANDUICMD_SELECTRAWDATA, 0 },
  58. { CANDUIKEY_VKEY, VK_APPS, CANDUICMD_OPENCANDMENU, 0 },
  59. };
  60. // key command definition in row style
  61. const CANDUIKEYDATA rgKeyDefRow[] =
  62. {
  63. /*
  64. { flag, keydata, command, paramater }
  65. */
  66. { CANDUIKEY_VKEY, VK_ESCAPE, CANDUICMD_CANCEL, 0 },
  67. { CANDUIKEY_VKEY, VK_RETURN, CANDUICMD_CANCEL, 0 },
  68. { CANDUIKEY_VKEY, VK_SPACE, CANDUICMD_COMPLETE, 0 },
  69. { CANDUIKEY_VKEY, VK_UP, CANDUICMD_MOVESELLEFT, 0 }, // horz only
  70. { CANDUIKEY_VKEY, VK_DOWN, CANDUICMD_MOVESELRIGHT, 0 }, // horz only
  71. { CANDUIKEY_VKEY, VK_LEFT, CANDUICMD_MOVESELUP, 0 }, // vert only
  72. { CANDUIKEY_VKEY, VK_RIGHT, CANDUICMD_MOVESELDOWN, 0 }, // vert only
  73. { CANDUIKEY_VKEY, VK_PRIOR, CANDUICMD_MOVESELPREVPG, 0 },
  74. { CANDUIKEY_VKEY, VK_NEXT, CANDUICMD_MOVESELNEXTPG, 0 },
  75. // { CANDUIKEY_CHAR, L'1', CANDUICMD_SELECTLINE, 1 },
  76. // { CANDUIKEY_CHAR, L'2', CANDUICMD_SELECTLINE, 2 },
  77. // { CANDUIKEY_CHAR, L'3', CANDUICMD_SELECTLINE, 3 },
  78. // { CANDUIKEY_CHAR, L'4', CANDUICMD_SELECTLINE, 4 },
  79. // { CANDUIKEY_CHAR, L'5', CANDUICMD_SELECTLINE, 5 },
  80. // { CANDUIKEY_CHAR, L'6', CANDUICMD_SELECTLINE, 6 },
  81. // { CANDUIKEY_CHAR, L'7', CANDUICMD_SELECTLINE, 7 },
  82. // { CANDUIKEY_CHAR, L'8', CANDUICMD_SELECTLINE, 8 },
  83. // { CANDUIKEY_CHAR, L'9', CANDUICMD_SELECTLINE, 9 },
  84. { CANDUIKEY_VKEY, L'1', CANDUICMD_SELECTLINE, 1 },
  85. { CANDUIKEY_VKEY, L'2', CANDUICMD_SELECTLINE, 2 },
  86. { CANDUIKEY_VKEY, L'3', CANDUICMD_SELECTLINE, 3 },
  87. { CANDUIKEY_VKEY, L'4', CANDUICMD_SELECTLINE, 4 },
  88. { CANDUIKEY_VKEY, L'5', CANDUICMD_SELECTLINE, 5 },
  89. { CANDUIKEY_VKEY, L'6', CANDUICMD_SELECTLINE, 6 },
  90. { CANDUIKEY_VKEY, L'7', CANDUICMD_SELECTLINE, 7 },
  91. { CANDUIKEY_VKEY, L'8', CANDUICMD_SELECTLINE, 8 },
  92. { CANDUIKEY_VKEY, L'9', CANDUICMD_SELECTLINE, 9 },
  93. { CANDUIKEY_VKEY, VK_NUMPAD1, CANDUICMD_SELECTLINE, 1 },
  94. { CANDUIKEY_VKEY, VK_NUMPAD2, CANDUICMD_SELECTLINE, 2 },
  95. { CANDUIKEY_VKEY, VK_NUMPAD3, CANDUICMD_SELECTLINE, 3 },
  96. { CANDUIKEY_VKEY, VK_NUMPAD4, CANDUICMD_SELECTLINE, 4 },
  97. { CANDUIKEY_VKEY, VK_NUMPAD5, CANDUICMD_SELECTLINE, 5 },
  98. { CANDUIKEY_VKEY, VK_NUMPAD6, CANDUICMD_SELECTLINE, 6 },
  99. { CANDUIKEY_VKEY, VK_NUMPAD7, CANDUICMD_SELECTLINE, 7 },
  100. { CANDUIKEY_VKEY, VK_NUMPAD8, CANDUICMD_SELECTLINE, 8 },
  101. { CANDUIKEY_VKEY, VK_NUMPAD9, CANDUICMD_SELECTLINE, 9 },
  102. { CANDUIKEY_CHAR, L'-', CANDUICMD_MOVESELPREVPG, 0 },
  103. { CANDUIKEY_CHAR, L'_', CANDUICMD_MOVESELPREVPG, 0 },
  104. { CANDUIKEY_CHAR, L'[', CANDUICMD_MOVESELPREVPG, 0 },
  105. { CANDUIKEY_CHAR, L'+', CANDUICMD_MOVESELNEXTPG, 0 },
  106. { CANDUIKEY_CHAR, L'=', CANDUICMD_MOVESELNEXTPG, 0 },
  107. { CANDUIKEY_CHAR, L']', CANDUICMD_MOVESELNEXTPG, 0 },
  108. { CANDUIKEY_VKEY, VK_APPS, CANDUICMD_OPENCANDMENU, 0 },
  109. };
  110. //
  111. // rule definitions
  112. //
  113. typedef struct _RULEDEF
  114. {
  115. LPCWSTR szRuleName;
  116. CANDUICOMMAND cmd;
  117. UINT uiParam;
  118. } RULEDEF;
  119. // rule definition in normal state
  120. const RULEDEF rgRuleNorm[] =
  121. {
  122. /*
  123. { "rule name", command, paramater }
  124. */
  125. { L"Finalize", CANDUICMD_COMPLETE, 0 },
  126. { L"Cancel", CANDUICMD_CANCEL, 0 },
  127. { L"Next", CANDUICMD_MOVESELNEXT, 0 },
  128. { L"Prev", CANDUICMD_MOVESELPREV, 0 },
  129. { L"First", CANDUICMD_MOVESELFIRST, 0 },
  130. { L"Last", CANDUICMD_MOVESELLAST, 0 },
  131. { L"Menu", CANDUICMD_OPENCANDMENU, 0 },
  132. { L"Select1", CANDUICMD_SELECTLINE, 1 },
  133. { L"Select2", CANDUICMD_SELECTLINE, 2 },
  134. { L"Select3", CANDUICMD_SELECTLINE, 3 },
  135. { L"Select4", CANDUICMD_SELECTLINE, 4 },
  136. { L"Select5", CANDUICMD_SELECTLINE, 5 },
  137. { L"Select6", CANDUICMD_SELECTLINE, 6 },
  138. { L"Select7", CANDUICMD_SELECTLINE, 7 },
  139. { L"Select8", CANDUICMD_SELECTLINE, 8 },
  140. { L"Select9", CANDUICMD_SELECTLINE, 9 },
  141. { L"PageDown", CANDUICMD_MOVESELNEXTPG, 0 },
  142. { L"PageUp", CANDUICMD_MOVESELPREVPG, 0 },
  143. };
  144. //
  145. //
  146. //
  147. class CTfCandidateUIContextOwner : public ITfCandidateUIContextOwner
  148. {
  149. public:
  150. CTfCandidateUIContextOwner( CCandidateUI *pCandUI );
  151. virtual ~CTfCandidateUIContextOwner( void );
  152. //
  153. // IUnknown methods
  154. //
  155. STDMETHODIMP QueryInterface( REFIID riid, void **ppvObj );
  156. STDMETHODIMP_(ULONG) AddRef( void );
  157. STDMETHODIMP_(ULONG) Release( void );
  158. //
  159. // ITfCandidateUIContextOwner methods
  160. //
  161. STDMETHODIMP ProcessCommand(CANDUICOMMAND cmd, INT iParam);
  162. STDMETHODIMP TestText(BSTR bstr, BOOL *pfHandles);
  163. protected:
  164. ULONG m_cRef;
  165. CCandidateUI *m_pCandUI;
  166. };
  167. /*============================================================================*/
  168. /* */
  169. /* C C A N D I D A T E U I */
  170. /* */
  171. /*============================================================================*/
  172. /* C C A N D I D A T E U I */
  173. /*------------------------------------------------------------------------------
  174. ------------------------------------------------------------------------------*/
  175. CCandidateUI::CCandidateUI()
  176. {
  177. Dbg_MemSetThisName(TEXT("CCandidateUI"));
  178. TF_CreateThreadMgr(&_ptim);
  179. m_hWndParent = NULL;
  180. m_pCandWnd = NULL;
  181. m_pic = NULL;
  182. m_pdim = NULL;
  183. m_picParent = NULL;
  184. m_pTargetRange = NULL;
  185. m_codepage = GetACP();
  186. m_fContextEventSinkAdvised = FALSE;
  187. m_dwCookieContextOwnerSink = 0;
  188. m_dwCookieContextKeySink = 0;
  189. m_fTextEventSinkAdvised = FALSE;
  190. m_dwCookieTextEditSink = 0;
  191. m_dwCookieTextLayoutSink = 0;
  192. m_dwCookieTransactionSink = 0;
  193. m_pTextEventSink = NULL;
  194. m_pCandUIKeyTable = NULL;
  195. m_fInTransaction = FALSE;
  196. m_pSelectionStart = NULL;
  197. m_pSelectionCur = NULL;
  198. m_fInCallback = FALSE;
  199. m_pSpTask = NULL;
  200. // create candidate list manager, function manager, functions
  201. CCandListMgr::Initialize( this );
  202. CCandUIObjectMgr::Initialize( this );
  203. CCandUIPropertyMgr::Initialize( this );
  204. CCandUICompartmentMgr::Initialize( this );
  205. CCandUIFunctionMgr::Initialize( this );
  206. CCandUIExtensionMgr::Initialize( this );
  207. }
  208. /* ~ C C A N D I D A T E U I */
  209. /*------------------------------------------------------------------------------
  210. ------------------------------------------------------------------------------*/
  211. CCandidateUI::~CCandidateUI()
  212. {
  213. // this call was for the case that CandidateUI was released wihtout
  214. // CloseCandidateUI() call, but it should not happn (because it will be
  215. // referenced by event sink or interfnal objects by OpenCandidateUI(), so
  216. // ref count nevet be zero unless CloseCandidateUI() call...
  217. // CloseCandidateUIProc();
  218. //
  219. SafeReleaseClear( m_pCandUIKeyTable );
  220. //
  221. CCandUIExtensionMgr::Uninitialize();
  222. CCandUIFunctionMgr::Uninitialize();
  223. CCandUICompartmentMgr::Uninitialize();
  224. CCandUIPropertyMgr::Uninitialize();
  225. CCandUIObjectMgr::Uninitialize();
  226. CCandListMgr::Uninitialize();
  227. // remove ref to this in TLS
  228. SafeRelease( _ptim );
  229. SafeRelease( m_pTargetRange );
  230. DoneTextEventSinks( m_picParent );
  231. ClearSelectionCur();
  232. ClearWndCand();
  233. // release speech
  234. if(m_pSpTask) {
  235. delete m_pSpTask;
  236. }
  237. }
  238. /* E N D C A N D I D A T E L I S T */
  239. /*------------------------------------------------------------------------------
  240. ------------------------------------------------------------------------------*/
  241. void CCandidateUI::EndCandidateList()
  242. {
  243. DoneContextEventSinks( m_pic );
  244. ClearCompartment( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXTOWNER, FALSE );
  245. DoneTextEventSinks( m_picParent );
  246. ClearSelectionCur();
  247. SafeReleaseClear( m_pic );
  248. SafeReleaseClear( m_pTargetRange );
  249. SafeReleaseClear( m_pCandUIKeyTable );
  250. if (m_pdim) {
  251. m_pdim->Pop(0);
  252. m_pdim->Release();
  253. m_pdim = NULL;
  254. SafeRelease( m_picParent );
  255. }
  256. }
  257. /* S E T C L I E N T I D */
  258. /*------------------------------------------------------------------------------
  259. ------------------------------------------------------------------------------*/
  260. STDAPI CCandidateUI::SetClientId( TfClientId tid )
  261. {
  262. m_tidClient = tid;
  263. return S_OK;
  264. }
  265. /* O P E N C A N D I D A T E U I */
  266. /*------------------------------------------------------------------------------
  267. ------------------------------------------------------------------------------*/
  268. STDAPI CCandidateUI::OpenCandidateUI( HWND hWndParent, ITfDocumentMgr *pdim, TfEditCookie ec, ITfRange *pRange )
  269. {
  270. ITfInputProcessorProfiles *pProfile;
  271. ITfRange *pSelection = NULL;
  272. HRESULT hr = E_FAIL;
  273. Assert(!m_pic);
  274. Assert(!m_pdim);
  275. // sanity check
  276. if ((pdim == NULL) || (pRange == NULL)) {
  277. return E_INVALIDARG;
  278. }
  279. // check if candidate list has been set
  280. if (GetCandListMgr()->GetCandList() == NULL) {
  281. return E_FAIL;
  282. }
  283. // fail when it's opening candidate window already
  284. if (m_pCandWnd != NULL) {
  285. return E_FAIL;
  286. }
  287. // ensure that speech is enabled
  288. // BUGBUG - THIS IS TOO LATE TO ENSURE ENGINE IS FORCED TO SYNC VIA A RECOSTATE(INACTIVE) CALL.
  289. EnsureSpeech();
  290. //
  291. //
  292. //
  293. m_pdim = pdim;
  294. m_pdim->AddRef();
  295. // store current top IC
  296. GetTopIC( pdim, &m_picParent );
  297. //
  298. // create candidate window
  299. //
  300. ClearWndCand();
  301. if (CreateCandWindowObject( m_picParent, &m_pCandWnd ) == S_OK) {
  302. BOOL fClipped;
  303. RECT rc;
  304. SetCompartmentDWORD( m_tidClient, m_picParent, GUID_COMPARTMENT_MSCANDIDATEUI_WINDOW, 0x00000001, FALSE );
  305. m_pCandWnd->Initialize();
  306. // set target clause poisition
  307. GetTextExtInActiveView( ec, pRange, &rc, &fClipped );
  308. m_pCandWnd->SetTargetRect( &rc, fClipped );
  309. // initialize candidate list
  310. m_pCandWnd->InitCandidateList();
  311. // create window
  312. m_pCandWnd->CreateWnd( m_hWndParent );
  313. hr = S_OK;
  314. }
  315. //
  316. // create context for CandidteUI
  317. //
  318. SafeReleaseClear( m_pic );
  319. if (SUCCEEDED(hr)) {
  320. TfEditCookie ecTmp;
  321. // create context
  322. hr = pdim->CreateContext( m_tidClient, 0, NULL, &m_pic, &ecTmp );
  323. // disable keyboard while candidate UI open
  324. if (SUCCEEDED(hr)) {
  325. SetCompartmentDWORD( m_tidClient, m_pic, GUID_COMPARTMENT_KEYBOARD_DISABLED, 0x00000001, FALSE );
  326. SetCompartmentDWORD( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXT, 0x00000001, FALSE );
  327. }
  328. // create context owner instance
  329. if (SUCCEEDED(hr)) {
  330. CTfCandidateUIContextOwner *pCxtOwner;
  331. pCxtOwner = new CTfCandidateUIContextOwner( this );
  332. if (pCxtOwner == NULL) {
  333. hr = E_OUTOFMEMORY;
  334. }
  335. else {
  336. SetCompartmentUnknown( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXTOWNER, (IUnknown*)pCxtOwner );
  337. }
  338. }
  339. // init context event sinks
  340. if (SUCCEEDED(hr)) {
  341. hr = InitContextEventSinks( m_pic );
  342. }
  343. // push context
  344. if (SUCCEEDED(hr)) {
  345. hr = pdim->Push( m_pic );
  346. }
  347. }
  348. //
  349. // cleanup all when failed
  350. //
  351. if (FAILED(hr)) {
  352. // cleanup context
  353. if (m_pic != NULL) {
  354. DoneContextEventSinks( m_pic );
  355. ClearCompartment( m_tidClient, m_pic, GUID_COMPARTMENT_MSCANDIDATEUI_CONTEXTOWNER, FALSE );
  356. SafeReleaseClear( m_pic );
  357. }
  358. // cleanup candidate window
  359. if (m_pCandWnd != NULL) {
  360. m_pCandWnd->DestroyWnd();
  361. ClearWndCand();
  362. }
  363. // release objects
  364. SafeReleaseClear( m_picParent );
  365. SafeReleaseClear( m_pdim );
  366. return hr;
  367. }
  368. //
  369. // initialize miscs
  370. //
  371. // get current codepage from current assembly
  372. m_codepage = GetACP();
  373. if (SUCCEEDED(CoCreateInstance( CLSID_TF_InputProcessorProfiles, NULL, CLSCTX_INPROC_SERVER, IID_ITfInputProcessorProfiles, (void **)&pProfile ))) {
  374. LANGID langid;
  375. char szCpg[ 16 ];
  376. if (pProfile->GetCurrentLanguage( &langid ) == S_OK) {
  377. if (GetLocaleInfo( MAKELCID(langid, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, szCpg, ARRAYSIZE(szCpg) ) != 0) {
  378. m_codepage = atoi( szCpg );
  379. }
  380. }
  381. pProfile->Release();
  382. }
  383. // get key table
  384. SafeRelease( m_pCandUIKeyTable );
  385. m_pCandUIKeyTable = GetKeyTableProc( m_picParent );
  386. // make copy target range
  387. pRange->Clone( &m_pTargetRange );
  388. // store selection first
  389. ClearSelectionCur();
  390. if (GetSelectionSimple( ec, m_picParent, &pSelection ) == S_OK) {
  391. SetSelectionCur( pSelection );
  392. SafeRelease( pSelection );
  393. }
  394. // init text event sinks
  395. DoneTextEventSinks( m_picParent );
  396. InitTextEventSinks( m_picParent );
  397. //
  398. // show candidate window at last
  399. //
  400. m_pCandWnd->Show( GetPropertyMgr()->GetCandWindowProp()->IsVisible() );
  401. m_pCandWnd->UpdateAllWindow();
  402. // notify initial seletion
  403. NotifySelectCand( GetCandListMgr()->GetCandList()->GetSelection() );
  404. return hr;
  405. }
  406. /* C L O S E C A N D I D A T E U I */
  407. /*------------------------------------------------------------------------------
  408. ------------------------------------------------------------------------------*/
  409. STDAPI CCandidateUI::CloseCandidateUI( void )
  410. {
  411. HRESULT hr;
  412. // Windows#502340
  413. // CandidateUI will be released during DestroyWindow(). As result,
  414. // ref count will be zero and instance will be disposed during closeing UI.
  415. // prevent from it, keep one refcount until closing process will finished.
  416. AddRef();
  417. hr = CloseCandidateUIProc();
  418. Release();
  419. return hr;
  420. }
  421. /* S E T C A N D I D A T E L I S T */
  422. /*------------------------------------------------------------------------------
  423. ------------------------------------------------------------------------------*/
  424. STDAPI CCandidateUI::SetCandidateList( ITfCandidateList *pCandList )
  425. {
  426. // release before change candidate list
  427. GetCandListMgr()->ClearCandiateList();
  428. // set new candidate list
  429. return GetCandListMgr()->SetCandidateList( pCandList );
  430. }
  431. /* S E T S E L E C T I O N */
  432. /*------------------------------------------------------------------------------
  433. ------------------------------------------------------------------------------*/
  434. STDAPI CCandidateUI::SetSelection( ULONG nIndex )
  435. {
  436. HRESULT hr;
  437. int iCandItem;
  438. // check if candidate list has been set
  439. if (GetCandListMgr()->GetCandList() == NULL) {
  440. return E_FAIL;
  441. }
  442. // map index to icanditem
  443. hr = GetCandListMgr()->GetCandList()->MapIndexToIItem( nIndex, &iCandItem );
  444. if (FAILED(hr)) {
  445. Assert( FALSE );
  446. return hr;
  447. }
  448. return GetCandListMgr()->SetSelection( iCandItem, NULL /* no cand function */ );
  449. }
  450. /* G E T S E L E C T I O N */
  451. /*------------------------------------------------------------------------------
  452. ------------------------------------------------------------------------------*/
  453. STDAPI CCandidateUI::GetSelection( ULONG *pnIndex )
  454. {
  455. HRESULT hr;
  456. int iCandItem;
  457. ULONG nIndex;
  458. if (pnIndex == NULL) {
  459. return E_INVALIDARG;
  460. }
  461. // check if candidate list has been set
  462. if (GetCandListMgr()->GetCandList() == NULL) {
  463. return E_FAIL;
  464. }
  465. iCandItem = GetCandListMgr()->GetCandList()->GetSelection();
  466. hr = GetCandListMgr()->GetCandList()->MapIItemToIndex( iCandItem, &nIndex );
  467. if (FAILED(hr)) {
  468. Assert( FALSE );
  469. return hr;
  470. }
  471. *pnIndex = nIndex;
  472. return S_OK;
  473. }
  474. /* S E T T A R G E T R A N G E */
  475. /*------------------------------------------------------------------------------
  476. Set target range
  477. Memo: This method works while candidate UI is opened.
  478. ------------------------------------------------------------------------------*/
  479. STDAPI CCandidateUI::SetTargetRange( ITfRange *pRange )
  480. {
  481. CEditSession *pes;
  482. if (pRange == NULL) {
  483. return E_FAIL;
  484. }
  485. if (m_pCandWnd == NULL) {
  486. return E_FAIL;
  487. }
  488. SafeReleaseClear( m_pTargetRange );
  489. pRange->Clone( &m_pTargetRange );
  490. // move candidate window
  491. if (pes = new CEditSession( EditSessionCallback )) {
  492. HRESULT hr;
  493. pes->_state.u = ESCB_RESETTARGETPOS;
  494. pes->_state.pv = this;
  495. pes->_state.wParam = 0;
  496. pes->_state.pRange = m_pTargetRange;
  497. pes->_state.pic = m_picParent;
  498. m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_SYNC, &hr );
  499. pes->Release();
  500. }
  501. return S_OK;
  502. }
  503. /* G E T T A R G E T R A N G E */
  504. /*------------------------------------------------------------------------------
  505. ------------------------------------------------------------------------------*/
  506. STDAPI CCandidateUI::GetTargetRange( ITfRange **ppRange )
  507. {
  508. if (m_pTargetRange == NULL) {
  509. return E_FAIL;
  510. }
  511. Assert( ppRange != NULL );
  512. return m_pTargetRange->Clone( ppRange );
  513. }
  514. /* G E T U I O B J E C T */
  515. /*------------------------------------------------------------------------------
  516. ------------------------------------------------------------------------------*/
  517. STDAPI CCandidateUI::GetUIObject( REFIID riid, IUnknown **ppunk )
  518. {
  519. return GetPropertyMgr()->GetObject( riid, (void **)ppunk );
  520. }
  521. /* G E T F U N C T I O N */
  522. /*------------------------------------------------------------------------------
  523. ------------------------------------------------------------------------------*/
  524. STDAPI CCandidateUI::GetFunction( REFIID riid, IUnknown **ppunk )
  525. {
  526. if (ppunk == NULL) {
  527. return E_INVALIDARG;
  528. }
  529. // extension manager
  530. if (IsEqualGUID( riid, IID_ITfCandUIFnExtension )) {
  531. CCandUIFnExtension *pObject;
  532. HRESULT hr;
  533. pObject = new CCandUIFnExtension( this, GetExtensionMgr() );
  534. if (pObject == NULL) {
  535. return E_OUTOFMEMORY;
  536. }
  537. hr = pObject->QueryInterface( riid, (void **)ppunk );
  538. pObject->Release();
  539. return hr;
  540. }
  541. // key config
  542. if (IsEqualGUID( riid, IID_ITfCandUIFnKeyConfig )) {
  543. CCandUIFnKeyConfig *pObject;
  544. HRESULT hr;
  545. pObject = new CCandUIFnKeyConfig( this );
  546. if (pObject == NULL) {
  547. return E_OUTOFMEMORY;
  548. }
  549. hr = pObject->QueryInterface( riid, (void **)ppunk );
  550. pObject->Release();
  551. return hr;
  552. }
  553. // UI config
  554. if (IsEqualGUID( riid, IID_ITfCandUIFnUIConfig )) {
  555. CCandUIFnUIConfig *pObject;
  556. HRESULT hr;
  557. pObject = new CCandUIFnUIConfig( this );
  558. if (pObject == NULL) {
  559. return E_OUTOFMEMORY;
  560. }
  561. hr = pObject->QueryInterface( riid, (void **)ppunk );
  562. pObject->Release();
  563. return hr;
  564. }
  565. // regular functions
  566. return GetFunctionMgr()->GetObject( riid, (void **)ppunk );
  567. }
  568. /* P R O C E S S C O M M A N D */
  569. /*------------------------------------------------------------------------------
  570. ------------------------------------------------------------------------------*/
  571. STDAPI CCandidateUI::ProcessCommand( CANDUICOMMAND cmd, INT iParam )
  572. {
  573. //
  574. if (cmd == CANDUICMD_NONE) {
  575. return E_INVALIDARG;
  576. }
  577. if (m_pCandWnd == NULL) {
  578. return E_FAIL;
  579. }
  580. return m_pCandWnd->ProcessCommand( cmd, iParam );
  581. }
  582. /* C L O S E C A N D I D A T E U I P R O C */
  583. /*------------------------------------------------------------------------------
  584. close candidate u i proc
  585. ------------------------------------------------------------------------------*/
  586. HRESULT CCandidateUI::CloseCandidateUIProc( void )
  587. {
  588. if (m_picParent && m_pCandWnd) {
  589. SetCompartmentDWORD( m_tidClient, m_picParent, GUID_COMPARTMENT_MSCANDIDATEUI_WINDOW, 0x00000000, FALSE );
  590. }
  591. if (m_pCandWnd) {
  592. m_pCandWnd->DestroyWnd();
  593. ClearWndCand();
  594. EndCandidateList();
  595. }
  596. GetCandListMgr()->ClearCandiateList();
  597. if (m_pSpTask)
  598. m_pSpTask->_Activate(FALSE);
  599. return S_OK;
  600. }
  601. //
  602. // key config function methods
  603. //
  604. /* S E T K E Y T A B L E */
  605. /*------------------------------------------------------------------------------
  606. ------------------------------------------------------------------------------*/
  607. HRESULT CCandidateUI::SetKeyTable( ITfContext *pic, ITfCandUIKeyTable *pCandUIKeyTable )
  608. {
  609. HRESULT hr;
  610. CCandUIKeyTable *pCandUIKeyTableCopy;
  611. if ((pic == NULL) || (pCandUIKeyTable == NULL)) {
  612. return E_INVALIDARG;
  613. }
  614. if (GetCompartmentMgr() == NULL) {
  615. return E_FAIL;
  616. }
  617. // store copy of key table to input context
  618. pCandUIKeyTableCopy = new CCandUIKeyTable();
  619. if (pCandUIKeyTableCopy == NULL) {
  620. return E_OUTOFMEMORY;
  621. }
  622. hr = pCandUIKeyTableCopy->SetKeyTable( pCandUIKeyTable );
  623. if (FAILED( hr )) {
  624. pCandUIKeyTableCopy->Release();
  625. return hr;
  626. }
  627. hr = GetCompartmentMgr()->SetKeyTable( pic, pCandUIKeyTableCopy );
  628. if (FAILED( hr )) {
  629. pCandUIKeyTableCopy->Release();
  630. return hr;
  631. }
  632. pCandUIKeyTableCopy->Release();
  633. // reload key table if exist
  634. // REVIEW: KOJIW: If we support changing keytable of candidate UI in other IC,
  635. // need to do this in compartment event sink.
  636. if (m_pCandUIKeyTable != NULL) {
  637. m_pCandUIKeyTable->Release();
  638. Assert( m_picParent != NULL );
  639. m_pCandUIKeyTable = GetKeyTableProc( m_picParent );
  640. }
  641. return S_OK;
  642. }
  643. /* G E T K E Y T A B L E */
  644. /*------------------------------------------------------------------------------
  645. ------------------------------------------------------------------------------*/
  646. HRESULT CCandidateUI::GetKeyTable( ITfContext *pic, ITfCandUIKeyTable **ppCandUIKeyTable)
  647. {
  648. if ((pic == NULL) || (ppCandUIKeyTable == NULL)) {
  649. return E_INVALIDARG;
  650. }
  651. // load key table from input context
  652. *ppCandUIKeyTable = GetKeyTableProc( pic );
  653. return (*ppCandUIKeyTable != NULL) ? S_OK : E_FAIL;
  654. }
  655. /* R E S E T K E Y T A B L E */
  656. /*------------------------------------------------------------------------------
  657. ------------------------------------------------------------------------------*/
  658. HRESULT CCandidateUI::ResetKeyTable( ITfContext *pic )
  659. {
  660. HRESULT hr;
  661. if (pic == NULL) {
  662. return E_INVALIDARG;
  663. }
  664. if (GetCompartmentMgr() == NULL) {
  665. return E_FAIL;
  666. }
  667. hr = GetCompartmentMgr()->ClearKeyTable( pic );
  668. if (FAILED( hr )) {
  669. return hr;
  670. }
  671. // reload key table if exist
  672. if (m_pCandUIKeyTable != NULL) {
  673. m_pCandUIKeyTable->Release();
  674. Assert( m_picParent != NULL );
  675. m_pCandUIKeyTable = GetKeyTableProc( m_picParent );
  676. }
  677. return S_OK;
  678. }
  679. //
  680. // UI config function methods
  681. //
  682. /* S E T U I S T Y L E */
  683. /*------------------------------------------------------------------------------
  684. ------------------------------------------------------------------------------*/
  685. HRESULT CCandidateUI::SetUIStyle( ITfContext *pic, CANDUISTYLE style )
  686. {
  687. HRESULT hr = S_OK;
  688. if (pic == NULL) {
  689. return E_INVALIDARG;
  690. }
  691. if (GetCompartmentMgr() == NULL) {
  692. return E_FAIL;
  693. }
  694. // store ui style to input context
  695. GetCompartmentMgr()->SetUIStyle( pic, style );
  696. // rebuild candidate window
  697. // REVIEW: KOJIW: If we support changing ui style of candidate UI in other IC,
  698. // need to do this in compartment event sink.
  699. if ((m_picParent == pic) && (m_pCandWnd != NULL)) {
  700. // destory candidate window object
  701. m_pCandWnd->DestroyWnd();
  702. ClearWndCand();
  703. // create and initialize window object
  704. hr = CreateCandWindowObject( m_picParent, &m_pCandWnd );
  705. if (SUCCEEDED(hr)) {
  706. hr = InitCandWindow();
  707. }
  708. }
  709. return hr;
  710. }
  711. /* G E T U I S T Y L E */
  712. /*------------------------------------------------------------------------------
  713. ------------------------------------------------------------------------------*/
  714. HRESULT CCandidateUI::GetUIStyle( ITfContext *pic, CANDUISTYLE *pstyle )
  715. {
  716. if ((pic == NULL) || (pstyle == NULL)) {
  717. return E_INVALIDARG;
  718. }
  719. if (GetCompartmentMgr() == NULL) {
  720. return E_FAIL;
  721. }
  722. if (FAILED( GetCompartmentMgr()->GetUIStyle( pic, pstyle ))) {
  723. *pstyle = CANDUISTY_LIST;
  724. }
  725. return S_OK;
  726. }
  727. /* S E T U I O P T I O N */
  728. /*------------------------------------------------------------------------------
  729. ------------------------------------------------------------------------------*/
  730. HRESULT CCandidateUI::SetUIOption( ITfContext *pic, DWORD dwOption )
  731. {
  732. HRESULT hr = S_OK;
  733. if (pic == NULL) {
  734. return E_INVALIDARG;
  735. }
  736. if (GetCompartmentMgr() == NULL) {
  737. return E_FAIL;
  738. }
  739. // store ui style to input context
  740. GetCompartmentMgr()->SetUIOption( pic, dwOption );
  741. // rebuild candidate window
  742. // REVIEW: KOJIW: If we support changing ui style of candidate UI in other IC,
  743. // need to do this in compartment event sink.
  744. if ((m_picParent == pic) && (m_pCandWnd != NULL)) {
  745. // destory candidate window object
  746. m_pCandWnd->DestroyWnd();
  747. ClearWndCand();
  748. // create and initialize window object
  749. hr = CreateCandWindowObject( m_picParent, &m_pCandWnd );
  750. if (SUCCEEDED(hr)) {
  751. hr = InitCandWindow();
  752. }
  753. }
  754. return hr;
  755. }
  756. /* G E T U I O P T I O N */
  757. /*------------------------------------------------------------------------------
  758. ------------------------------------------------------------------------------*/
  759. HRESULT CCandidateUI::GetUIOption( ITfContext *pic, DWORD *pdwOption )
  760. {
  761. if ((pic == NULL) || (pdwOption == NULL)) {
  762. return E_INVALIDARG;
  763. }
  764. if (GetCompartmentMgr() == NULL) {
  765. return E_FAIL;
  766. }
  767. if (FAILED( GetCompartmentMgr()->GetUIOption( pic, pdwOption ))) {
  768. *pdwOption = 0;
  769. }
  770. return S_OK;
  771. }
  772. //
  773. // callback functions
  774. //
  775. /* I N I T C O N T E X T E V E N T S I N K S */
  776. /*------------------------------------------------------------------------------
  777. initialize sinks for input context events
  778. ------------------------------------------------------------------------------*/
  779. HRESULT CCandidateUI::InitContextEventSinks( ITfContext *pic )
  780. {
  781. HRESULT hr = E_FAIL;
  782. ITfSource *pSource = NULL;
  783. Assert( pic == m_picParent );
  784. Assert( !m_fContextEventSinkAdvised );
  785. m_fContextEventSinkAdvised = FALSE;
  786. if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
  787. if (FAILED(pSource->AdviseSink( IID_ITfContextOwner, (ITfContextOwner *)this, &m_dwCookieContextOwnerSink ))) {
  788. pSource->Release();
  789. return hr;
  790. }
  791. if (FAILED(pSource->AdviseSink( IID_ITfContextKeyEventSink, (ITfContextKeyEventSink *)this, &m_dwCookieContextKeySink ))) {
  792. pSource->UnadviseSink( m_dwCookieContextOwnerSink );
  793. pSource->Release();
  794. return hr;
  795. }
  796. pSource->Release();
  797. m_fContextEventSinkAdvised = TRUE;
  798. hr = S_OK;
  799. }
  800. // advise text event sink for own IC
  801. // NOTE: This is a temporary fix for Satori#3644 (Cicero#3407) to handle
  802. // a text event from HW Tip. So the detect logic is very tiny (it just
  803. // handles half-width alphanumeric numbers). In the next version of Cicero,
  804. // we will use commanding feature to do same thing...
  805. // (related functions: TextEventCallback, HandleTextDeltas)
  806. m_pTextEventSink = new CTextEventSink( TextEventCallback, this );
  807. if (m_pTextEventSink != NULL) {
  808. m_pTextEventSink->_Advise( pic, ICF_TEXTDELTA );
  809. }
  810. return hr;
  811. }
  812. /* D O N E C O N T E X T E V E N T S I N K S */
  813. /*------------------------------------------------------------------------------
  814. uninitialize sinks for input context events
  815. ------------------------------------------------------------------------------*/
  816. HRESULT CCandidateUI::DoneContextEventSinks( ITfContext *pic )
  817. {
  818. HRESULT hr = E_FAIL;
  819. ITfSource *pSource;
  820. Assert( pic == m_picParent );
  821. // unadvise text event sink for own IC
  822. if (m_pTextEventSink != NULL) {
  823. m_pTextEventSink->_Unadvise();
  824. SafeReleaseClear( m_pTextEventSink );
  825. }
  826. if (!m_fContextEventSinkAdvised) {
  827. return S_OK;
  828. }
  829. if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
  830. pSource->UnadviseSink( m_dwCookieContextOwnerSink );
  831. pSource->UnadviseSink( m_dwCookieContextKeySink );
  832. pSource->Release();
  833. m_fContextEventSinkAdvised = FALSE;
  834. hr = S_OK;
  835. }
  836. return hr;
  837. }
  838. /* G E T A C P F R O M P O I N T */
  839. /*------------------------------------------------------------------------------
  840. Get acp from point
  841. (ITfContextOwner method)
  842. ------------------------------------------------------------------------------*/
  843. HRESULT CCandidateUI::GetACPFromPoint( const POINT *pt, DWORD dwFlags, LONG *pacp )
  844. {
  845. return E_FAIL;
  846. }
  847. /* G E T S C R E E N E X T */
  848. /*------------------------------------------------------------------------------
  849. Get screen extent of context
  850. (ITfContextOwner method)
  851. ------------------------------------------------------------------------------*/
  852. HRESULT CCandidateUI::GetScreenExt( RECT *prc )
  853. {
  854. return E_FAIL;
  855. }
  856. /* G E T T E X T E X T */
  857. /*------------------------------------------------------------------------------
  858. Get text externt of context
  859. (ITfContextOwner method)
  860. ------------------------------------------------------------------------------*/
  861. HRESULT CCandidateUI::GetTextExt( LONG acpStart, LONG acpEnd, RECT *prc, BOOL *pfClipped )
  862. {
  863. return E_FAIL;
  864. }
  865. /* G E T S T A T U S */
  866. /*------------------------------------------------------------------------------
  867. Get status of context
  868. (ITfContextOwner method)
  869. ------------------------------------------------------------------------------*/
  870. HRESULT CCandidateUI::GetStatus( TF_STATUS *pdcs )
  871. {
  872. if (pdcs == NULL) {
  873. return E_POINTER;
  874. }
  875. memset(pdcs, 0, sizeof(*pdcs));
  876. pdcs->dwDynamicFlags = 0;
  877. pdcs->dwStaticFlags = 0;
  878. return S_OK;
  879. }
  880. /* G E T W N D */
  881. /*------------------------------------------------------------------------------
  882. Get window of context
  883. (ITfContextOwner method)
  884. ------------------------------------------------------------------------------*/
  885. HRESULT CCandidateUI::GetWnd( HWND *phwnd )
  886. {
  887. if (phwnd == NULL) {
  888. return E_POINTER;
  889. }
  890. *phwnd = NULL;
  891. if (m_pCandWnd != NULL) {
  892. *phwnd = m_pCandWnd->GetWnd();
  893. }
  894. return S_OK;
  895. }
  896. /* G E T A T T R I B U T E */
  897. /*------------------------------------------------------------------------------
  898. Get attribute of context
  899. (ITfContextOwner method)
  900. ------------------------------------------------------------------------------*/
  901. HRESULT CCandidateUI::GetAttribute( REFGUID rguidAttribute, VARIANT *pvarValue )
  902. {
  903. return E_NOTIMPL;
  904. }
  905. /* O N K E Y D O W N */
  906. /*------------------------------------------------------------------------------
  907. event sink for key down event
  908. (ITfContextKeyEventSink method)
  909. ------------------------------------------------------------------------------*/
  910. HRESULT CCandidateUI::OnKeyDown( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
  911. {
  912. return OnKeyEvent( ICO_KEYDOWN, wParam, lParam, pfEaten );
  913. }
  914. /* O N K E Y U P */
  915. /*------------------------------------------------------------------------------
  916. event sink for key up event
  917. (ITfContextKeyEventSink method)
  918. ------------------------------------------------------------------------------*/
  919. HRESULT CCandidateUI::OnKeyUp( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
  920. {
  921. return OnKeyEvent( ICO_KEYUP, wParam, lParam, pfEaten );
  922. }
  923. /* O N T E S T K E Y D O W N */
  924. /*------------------------------------------------------------------------------
  925. event sink for key down testing event
  926. (ITfContextKeyEventSink method)
  927. ------------------------------------------------------------------------------*/
  928. HRESULT CCandidateUI::OnTestKeyDown( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
  929. {
  930. return OnKeyEvent( ICO_TESTKEYDOWN, wParam, lParam, pfEaten );
  931. }
  932. /* O N T E S T K E Y U P */
  933. /*------------------------------------------------------------------------------
  934. event sink for key up testing event
  935. (ITfContextKeyEventSink method)
  936. ------------------------------------------------------------------------------*/
  937. HRESULT CCandidateUI::OnTestKeyUp( WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
  938. {
  939. return OnKeyEvent( ICO_TESTKEYUP, wParam, lParam, pfEaten );
  940. }
  941. /* T E X T E V E N T C A L L B A C K */
  942. /*------------------------------------------------------------------------------
  943. text event (for own IC) callback function
  944. (static function)
  945. ------------------------------------------------------------------------------*/
  946. HRESULT CCandidateUI::TextEventCallback( UINT uCode, VOID *pv, VOID *pvData )
  947. {
  948. HRESULT hr;
  949. CCandidateUI *pCandUI;
  950. //
  951. pCandUI = (CCandidateUI *)pv;
  952. Assert( pCandUI != NULL );
  953. // ignore event of myself
  954. if (uCode == ICF_TEXTDELTA) {
  955. TESENDEDIT *pTESEndEdit = (TESENDEDIT*)pvData;
  956. IEnumTfRanges *pEnumRanges;
  957. if (SUCCEEDED(pTESEndEdit->pEditRecord->GetTextAndPropertyUpdates( TF_GTP_INCL_TEXT, NULL, 0, &pEnumRanges ))) {
  958. CEditSession *pes;
  959. if (pes = new CEditSession(EditSessionCallback)) {
  960. pes->_state.u = ESCB_TEXTEVENT;
  961. pes->_state.pv = (void *)pCandUI;
  962. pes->_state.pic = pCandUI->m_pic;
  963. pes->_state.pv1 = pEnumRanges; // DONT FORGET TO RELESE IT IN EDIT SESSION!!!
  964. pCandUI->m_pic->RequestEditSession( 0, pes, TF_ES_READ | TF_ES_SYNC, &hr );
  965. pes->Release();
  966. }
  967. else {
  968. pEnumRanges->Release();
  969. }
  970. }
  971. }
  972. return S_OK;
  973. }
  974. //
  975. // text event sink functions
  976. //
  977. /* I N I T T E X T E V E N T S I N K S */
  978. /*------------------------------------------------------------------------------
  979. initialize sinks for text events
  980. ------------------------------------------------------------------------------*/
  981. HRESULT CCandidateUI::InitTextEventSinks( ITfContext *pic )
  982. {
  983. HRESULT hr = E_FAIL;
  984. ITfSource *pSource = NULL;
  985. Assert( pic == m_picParent );
  986. Assert( !m_fTextEventSinkAdvised );
  987. Assert( !IsInEditTransaction() );
  988. m_fTextEventSinkAdvised = FALSE;
  989. LeaveEditTransaction();
  990. if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
  991. if (FAILED(pSource->AdviseSink( IID_ITfTextEditSink, (ITfTextEditSink *)this, &m_dwCookieTextEditSink ))) {
  992. pSource->Release();
  993. return hr;
  994. }
  995. if (FAILED(pSource->AdviseSink( IID_ITfTextLayoutSink, (ITfTextLayoutSink *)this, &m_dwCookieTextLayoutSink ))) {
  996. pSource->UnadviseSink( m_dwCookieTextEditSink );
  997. pSource->Release();
  998. return hr;
  999. }
  1000. if (FAILED(pSource->AdviseSink( IID_ITfEditTransactionSink, (ITfEditTransactionSink *)this, &m_dwCookieTransactionSink ))) {
  1001. pSource->UnadviseSink( m_dwCookieTextEditSink );
  1002. pSource->UnadviseSink( m_dwCookieTextLayoutSink );
  1003. pSource->Release();
  1004. return hr;
  1005. }
  1006. pSource->Release();
  1007. m_fTextEventSinkAdvised = TRUE;
  1008. hr = S_OK;
  1009. }
  1010. return hr;
  1011. }
  1012. /* D O N E T E X T E V E N T S I N K S */
  1013. /*------------------------------------------------------------------------------
  1014. uninitialize sinks for text events
  1015. ------------------------------------------------------------------------------*/
  1016. HRESULT CCandidateUI::DoneTextEventSinks( ITfContext *pic )
  1017. {
  1018. HRESULT hr = E_FAIL;
  1019. ITfSource *pSource;
  1020. Assert( pic == m_picParent );
  1021. LeaveEditTransaction();
  1022. if (!m_fTextEventSinkAdvised) {
  1023. return S_OK;
  1024. }
  1025. if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK) {
  1026. pSource->UnadviseSink( m_dwCookieTextEditSink );
  1027. pSource->UnadviseSink( m_dwCookieTextLayoutSink );
  1028. pSource->UnadviseSink( m_dwCookieTransactionSink );
  1029. pSource->Release();
  1030. m_fTextEventSinkAdvised = FALSE;
  1031. hr = S_OK;
  1032. }
  1033. return hr;
  1034. }
  1035. /* O N E N D E D I T */
  1036. /*------------------------------------------------------------------------------
  1037. event sink for text edit event
  1038. (ITfTextEditSink method)
  1039. ------------------------------------------------------------------------------*/
  1040. HRESULT CCandidateUI::OnEndEdit( ITfContext *pic, TfEditCookie ecReadOnly, ITfEditRecord *pEditRecord )
  1041. {
  1042. BOOL fInWriteSession = FALSE;
  1043. BOOL fSelChanged = FALSE;
  1044. // get selection status
  1045. if (FAILED(pEditRecord->GetSelectionStatus(&fSelChanged))) {
  1046. return S_OK;
  1047. }
  1048. // keep current selection always
  1049. if (fSelChanged) {
  1050. ITfRange *pSelection = NULL;
  1051. if (GetSelectionSimple( ecReadOnly, pic, &pSelection ) == S_OK) {
  1052. SetSelectionCur( pSelection );
  1053. }
  1054. SafeRelease( pSelection );
  1055. }
  1056. // ignore events during edit transaction
  1057. if (IsInEditTransaction()) {
  1058. return S_OK;
  1059. }
  1060. // ignore events made by client tip
  1061. pic->InWriteSession( m_tidClient, &fInWriteSession );
  1062. if (fInWriteSession) {
  1063. return S_OK;
  1064. }
  1065. // cancel candidate session when selection has been moved
  1066. if (fSelChanged) {
  1067. NotifyCancelCand();
  1068. }
  1069. return S_OK;
  1070. }
  1071. /* O N L A Y O U T C H A N G E */
  1072. /*------------------------------------------------------------------------------
  1073. event sink for text layout event
  1074. (ITfTextLayoutSink method)
  1075. ------------------------------------------------------------------------------*/
  1076. HRESULT CCandidateUI::OnLayoutChange( ITfContext *pic, TfLayoutCode lcode, ITfContextView *pView )
  1077. {
  1078. BOOL fInWriteSession = FALSE;
  1079. CEditSession *pes;
  1080. // ignore events made by client tip
  1081. pic->InWriteSession( m_tidClient, &fInWriteSession );
  1082. if (fInWriteSession) {
  1083. return S_OK;
  1084. }
  1085. // we only care about the active view
  1086. if (!IsActiveView( m_picParent, (ITfContextView *)pView )) {
  1087. return S_OK;
  1088. }
  1089. // move candidate window
  1090. Assert( m_pCandWnd != NULL );
  1091. if (pes = new CEditSession( EditSessionCallback )) {
  1092. HRESULT hr;
  1093. pes->_state.u = ESCB_RESETTARGETPOS;
  1094. pes->_state.pv = this;
  1095. pes->_state.wParam = 0;
  1096. pes->_state.pRange = m_pTargetRange;
  1097. pes->_state.pic = m_picParent;
  1098. m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_SYNC, &hr );
  1099. pes->Release();
  1100. }
  1101. return S_OK;
  1102. }
  1103. /* O N S T A R T E D I T T R A N S A C T I O N */
  1104. /*------------------------------------------------------------------------------
  1105. event sink for start of application transaction
  1106. (ITfEditTransactionSink method)
  1107. ------------------------------------------------------------------------------*/
  1108. HRESULT CCandidateUI::OnStartEditTransaction( ITfContext *pic )
  1109. {
  1110. // enter transaction session
  1111. Assert( !IsInEditTransaction() );
  1112. EnterEditTransaction( GetSelectionCur() );
  1113. return S_OK;
  1114. }
  1115. /* O N E N D E D I T T R A N S A C T I O N */
  1116. /*------------------------------------------------------------------------------
  1117. event sink for end of application transaction
  1118. (ITfEditTransactionSink method)
  1119. ------------------------------------------------------------------------------*/
  1120. HRESULT CCandidateUI::OnEndEditTransaction( ITfContext *pic )
  1121. {
  1122. CEditSession *pes;
  1123. // sanity check
  1124. if (!IsInEditTransaction()) {
  1125. return S_OK;
  1126. }
  1127. // check selection movement
  1128. if (pes = new CEditSession( EditSessionCallback )) {
  1129. HRESULT hr;
  1130. pes->_state.u = ESCB_COMPARERANGEANDCLOSECANDIDATE;
  1131. pes->_state.pv = this;
  1132. pes->_state.pv1 = GetSelectionStart();
  1133. pes->_state.pv2 = GetSelectionCur();
  1134. pes->_state.pic = m_picParent;
  1135. m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_ASYNC, &hr );
  1136. pes->Release();
  1137. }
  1138. // leave transaction session
  1139. LeaveEditTransaction();
  1140. return S_OK;
  1141. }
  1142. //
  1143. // edit session
  1144. //
  1145. /* E D I T S E S S I O N C A L L B A C K */
  1146. /*------------------------------------------------------------------------------
  1147. ------------------------------------------------------------------------------*/
  1148. HRESULT CCandidateUI::EditSessionCallback( TfEditCookie ec, CEditSession *pes )
  1149. {
  1150. CCandidateUI *pCandUI;
  1151. switch (pes->_state.u)
  1152. {
  1153. case ESCB_RESETTARGETPOS:
  1154. {
  1155. pCandUI = (CCandidateUI *)pes->_state.pv;
  1156. RECT rc;
  1157. BOOL fClipped;
  1158. if (pes->_state.pRange == NULL || pCandUI->m_pCandWnd == NULL) {
  1159. break;
  1160. }
  1161. if (!pCandUI->GetPropertyMgr()->GetCandWindowProp()->IsAutoMoveEnabled()) {
  1162. break;
  1163. }
  1164. // reset target clause poisition
  1165. GetTextExtInActiveView( ec, pes->_state.pRange, &rc, &fClipped );
  1166. pCandUI->m_pCandWnd->SetTargetRect( &rc, fClipped );
  1167. break;
  1168. }
  1169. case ESCB_COMPARERANGEANDCLOSECANDIDATE:
  1170. {
  1171. ITfContext *pic = pes->_state.pic;
  1172. BOOL fRangeIdentical = FALSE;
  1173. ITfRange *pRange1 = (ITfRange*)pes->_state.pv1;
  1174. ITfRange *pRange2 = (ITfRange*)pes->_state.pv2;
  1175. LONG lStart;
  1176. LONG lEnd;
  1177. CCandidateUI *_this = (CCandidateUI *)pes->_state.pv;
  1178. pRange1->CompareStart( ec, pRange2, TF_ANCHOR_START, &lStart );
  1179. pRange1->CompareEnd( ec, pRange2, TF_ANCHOR_END, &lEnd );
  1180. fRangeIdentical = (lStart == 0) && (lEnd == 0);
  1181. // Since we made this call asynchronous, we need
  1182. if (!fRangeIdentical)
  1183. {
  1184. _this->NotifyCancelCand();
  1185. }
  1186. break;
  1187. }
  1188. case ESCB_TEXTEVENT:
  1189. {
  1190. pCandUI = (CCandidateUI *)pes->_state.pv;
  1191. ITfContext *pic = pes->_state.pic;
  1192. IEnumTfRanges *pEnumRanges = (IEnumTfRanges *)pes->_state.pv1;
  1193. // handle textevent
  1194. pCandUI->HandleTextDeltas( ec, pic, pEnumRanges );
  1195. pEnumRanges->Release();
  1196. break;
  1197. }
  1198. }
  1199. return S_OK;
  1200. }
  1201. //
  1202. // selection
  1203. //
  1204. /* S E T S E L E C T I O N C U R */
  1205. /*------------------------------------------------------------------------------
  1206. ------------------------------------------------------------------------------*/
  1207. void CCandidateUI::SetSelectionCur( ITfRange *pSelection )
  1208. {
  1209. SafeReleaseClear( m_pSelectionCur );
  1210. m_pSelectionCur = pSelection;
  1211. if (m_pSelectionCur != NULL) {
  1212. m_pSelectionCur->AddRef();
  1213. }
  1214. }
  1215. /* C L E A R S E L E C T I O N C U R */
  1216. /*------------------------------------------------------------------------------
  1217. ------------------------------------------------------------------------------*/
  1218. void CCandidateUI::ClearSelectionCur( void )
  1219. {
  1220. SafeReleaseClear( m_pSelectionCur );
  1221. }
  1222. /* G E T S E L E C T I O N C U R */
  1223. /*------------------------------------------------------------------------------
  1224. ------------------------------------------------------------------------------*/
  1225. ITfRange *CCandidateUI::GetSelectionCur( void )
  1226. {
  1227. return m_pSelectionCur;
  1228. }
  1229. //
  1230. // transaction session functions
  1231. //
  1232. /* S E T S E L E C T I O N S T A R T */
  1233. /*------------------------------------------------------------------------------
  1234. ------------------------------------------------------------------------------*/
  1235. void CCandidateUI::SetSelectionStart( ITfRange *pSelection )
  1236. {
  1237. SafeReleaseClear( m_pSelectionStart );
  1238. m_pSelectionStart = pSelection;
  1239. if (m_pSelectionStart != NULL) {
  1240. m_pSelectionStart->AddRef();
  1241. }
  1242. }
  1243. /* C L E A R S E L E C T I O N S T A R T */
  1244. /*------------------------------------------------------------------------------
  1245. ------------------------------------------------------------------------------*/
  1246. void CCandidateUI::ClearSelectionStart( void )
  1247. {
  1248. SafeReleaseClear( m_pSelectionStart );
  1249. }
  1250. /* G E T S E L E C T I O N S T A R T */
  1251. /*------------------------------------------------------------------------------
  1252. ------------------------------------------------------------------------------*/
  1253. ITfRange *CCandidateUI::GetSelectionStart( void )
  1254. {
  1255. return m_pSelectionStart;
  1256. }
  1257. /* E N T E R E D I T T R A N S A C T I O N */
  1258. /*------------------------------------------------------------------------------
  1259. ------------------------------------------------------------------------------*/
  1260. void CCandidateUI::EnterEditTransaction( ITfRange *pSelection )
  1261. {
  1262. Assert( !m_fInTransaction );
  1263. if (pSelection == NULL) {
  1264. return;
  1265. }
  1266. m_fInTransaction = TRUE;
  1267. SetSelectionStart( pSelection );
  1268. }
  1269. /* L E A V E E D I T T R A N S A C T I O N */
  1270. /*------------------------------------------------------------------------------
  1271. ------------------------------------------------------------------------------*/
  1272. void CCandidateUI::LeaveEditTransaction( void )
  1273. {
  1274. m_fInTransaction = FALSE;
  1275. ClearSelectionStart();
  1276. }
  1277. //
  1278. // notification function (notification to client)
  1279. //
  1280. /* N O T I F Y C A N C E L C A N D */
  1281. /*------------------------------------------------------------------------------
  1282. Send notification (callback) to TIP that to cancel candidate
  1283. ------------------------------------------------------------------------------*/
  1284. HRESULT CCandidateUI::NotifyCancelCand( void )
  1285. {
  1286. if (m_pCandWnd) {
  1287. m_pCandWnd->UpdateAllWindow();
  1288. }
  1289. return CallSetResult( 0, CAND_CANCELED );
  1290. }
  1291. /* N O T I F Y S E L E C T C A N D */
  1292. /*------------------------------------------------------------------------------
  1293. Send notification (callback) to TIP that selection has been changed
  1294. ------------------------------------------------------------------------------*/
  1295. HRESULT CCandidateUI::NotifySelectCand( int iCandItem )
  1296. {
  1297. HRESULT hr;
  1298. ULONG nIndex;
  1299. // NOTE: Do not send a notification to TIP to prevent from updating inline
  1300. // text during filtering.
  1301. // This will be called by filtering candidates, and aslo sorting candidates
  1302. // because selection in UI will be changed by sorting. But the actual selected
  1303. // item never changed by sorting. When the selection has been changed by
  1304. // user action such as hitting arrow key, the filtering string has already
  1305. // been reset. So, we can send notify correctly in that case.
  1306. if (GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
  1307. if (GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString() != NULL) {
  1308. return S_OK;
  1309. }
  1310. }
  1311. Assert( GetCandListMgr()->GetCandList() != NULL );
  1312. hr = GetCandListMgr()->GetCandList()->MapIItemToIndex( iCandItem, &nIndex );
  1313. if (FAILED(hr)) {
  1314. Assert( FALSE );
  1315. return hr;
  1316. }
  1317. if (m_pCandWnd) {
  1318. m_pCandWnd->UpdateAllWindow();
  1319. }
  1320. return CallSetResult( nIndex, CAND_SELECTED );
  1321. }
  1322. /* N O T I F Y C O M P L E T E O P T I O N */
  1323. /*------------------------------------------------------------------------------
  1324. Send notification (callback) to TIP that to complete option
  1325. ------------------------------------------------------------------------------*/
  1326. HRESULT CCandidateUI::NotifyCompleteOption( int iCandItem )
  1327. {
  1328. HRESULT hr;
  1329. ULONG nIndex;
  1330. Assert( GetCandListMgr()->GetOptionsList() != NULL );
  1331. hr = GetCandListMgr()->GetOptionsList()->MapIItemToIndex( iCandItem, &nIndex );
  1332. if (FAILED(hr)) {
  1333. Assert( FALSE );
  1334. return hr;
  1335. }
  1336. if (m_pCandWnd) {
  1337. m_pCandWnd->UpdateAllWindow();
  1338. }
  1339. return CallSetOptionResult( nIndex, CAND_FINALIZED );
  1340. }
  1341. /* N O T I F Y C O M P L E T E C A N D */
  1342. /*------------------------------------------------------------------------------
  1343. Send notification (callback) to TIP that to complete candidate
  1344. ------------------------------------------------------------------------------*/
  1345. HRESULT CCandidateUI::NotifyCompleteCand( int iCandItem )
  1346. {
  1347. HRESULT hr;
  1348. ULONG nIndex;
  1349. Assert( GetCandListMgr()->GetCandList() != NULL );
  1350. hr = GetCandListMgr()->GetCandList()->MapIItemToIndex( iCandItem, &nIndex );
  1351. if (FAILED(hr)) {
  1352. Assert( FALSE );
  1353. return hr;
  1354. }
  1355. if (m_pCandWnd) {
  1356. m_pCandWnd->UpdateAllWindow();
  1357. }
  1358. return CallSetResult( nIndex, CAND_FINALIZED );
  1359. }
  1360. /* N O T I F Y E X T E N S I O N E V E N T */
  1361. /*------------------------------------------------------------------------------
  1362. ------------------------------------------------------------------------------*/
  1363. HRESULT CCandidateUI::NotifyExtensionEvent( int iExtension, DWORD dwCommand, LPARAM lParam )
  1364. {
  1365. CCandUIExtension *pExtension;
  1366. HRESULT hr = E_FAIL;
  1367. pExtension = GetExtensionMgr()->GetExtension( iExtension );
  1368. if (pExtension != NULL) {
  1369. hr = pExtension->NotifyExtensionEvent( dwCommand, lParam );
  1370. }
  1371. if (m_pCandWnd) {
  1372. m_pCandWnd->UpdateAllWindow();
  1373. }
  1374. return hr;
  1375. }
  1376. /* N O T I F Y F I L T E R I N G E V E N T */
  1377. /*------------------------------------------------------------------------------
  1378. ------------------------------------------------------------------------------*/
  1379. HRESULT CCandidateUI::NotifyFilteringEvent( CANDUIFILTEREVENT ev )
  1380. {
  1381. Assert( GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled() );
  1382. if (m_pCandWnd) {
  1383. m_pCandWnd->UpdateAllWindow();
  1384. }
  1385. if (GetFunctionMgr()->GetCandFnAutoFilter()->GetEventSink() != NULL) {
  1386. return GetFunctionMgr()->GetCandFnAutoFilter()->GetEventSink()->OnFilterEvent( ev );
  1387. }
  1388. else {
  1389. return S_OK;
  1390. }
  1391. }
  1392. /* N O T I F Y S O R T E V E N T */
  1393. /*------------------------------------------------------------------------------
  1394. ------------------------------------------------------------------------------*/
  1395. HRESULT CCandidateUI::NotifySortEvent( CANDUISORTEVENT ev )
  1396. {
  1397. if (m_pCandWnd) {
  1398. m_pCandWnd->UpdateAllWindow();
  1399. }
  1400. if (GetFunctionMgr()->GetCandFnSort()->GetEventSink() != NULL) {
  1401. return GetFunctionMgr()->GetCandFnSort()->GetEventSink()->OnSortEvent( ev );
  1402. }
  1403. else {
  1404. return S_OK;
  1405. }
  1406. }
  1407. /* N O T I F Y C O M P L E T E R A W D A T A */
  1408. /*------------------------------------------------------------------------------
  1409. ------------------------------------------------------------------------------*/
  1410. HRESULT CCandidateUI::NotifyCompleteRawData( void )
  1411. {
  1412. HRESULT hr;
  1413. Assert( GetCandListMgr()->GetCandList() != NULL );
  1414. if (m_pCandWnd) {
  1415. m_pCandWnd->UpdateAllWindow();
  1416. }
  1417. hr = CallSetResult( GetCandListMgr()->GetCandList()->GetRawDataIndex(), CAND_FINALIZED );
  1418. return hr;
  1419. }
  1420. /* N O T I F Y C O M P L E T E E X T R A C A N D */
  1421. /*------------------------------------------------------------------------------
  1422. ------------------------------------------------------------------------------*/
  1423. HRESULT CCandidateUI::NotifyCompleteExtraCand( void )
  1424. {
  1425. HRESULT hr;
  1426. Assert( GetCandListMgr()->GetCandList() != NULL );
  1427. if (m_pCandWnd) {
  1428. m_pCandWnd->UpdateAllWindow();
  1429. }
  1430. hr = CallSetResult( GetCandListMgr()->GetCandList()->GetExtraCandIndex(), CAND_FINALIZED );
  1431. return hr;
  1432. }
  1433. /* C A L L S E T R E S U L T */
  1434. /*------------------------------------------------------------------------------
  1435. Send notification to TIP
  1436. ------------------------------------------------------------------------------*/
  1437. HRESULT CCandidateUI::CallSetOptionResult( int nIndex, TfCandidateResult imcr )
  1438. {
  1439. HRESULT hr = E_FAIL;
  1440. AddRef();
  1441. if (!m_fInCallback) {
  1442. ITfOptionsCandidateList *pCandList;
  1443. m_fInCallback = TRUE;
  1444. if (SUCCEEDED(GetCandListMgr()->GetOptionsCandidateList( &pCandList ))) {
  1445. hr = pCandList->SetOptionsResult( nIndex, imcr );
  1446. pCandList->Release();
  1447. }
  1448. m_fInCallback = FALSE;
  1449. }
  1450. Release();
  1451. return hr;
  1452. }
  1453. /* C A L L S E T R E S U L T */
  1454. /*------------------------------------------------------------------------------
  1455. Send notification to TIP
  1456. ------------------------------------------------------------------------------*/
  1457. HRESULT CCandidateUI::CallSetResult( int nIndex, TfCandidateResult imcr )
  1458. {
  1459. HRESULT hr = E_FAIL;
  1460. AddRef();
  1461. if (!m_fInCallback) {
  1462. ITfCandidateList *pCandList;
  1463. m_fInCallback = TRUE;
  1464. if (SUCCEEDED(GetCandListMgr()->GetCandidateList( &pCandList ))) {
  1465. hr = pCandList->SetResult( nIndex, imcr );
  1466. pCandList->Release();
  1467. }
  1468. m_fInCallback = FALSE;
  1469. }
  1470. Release();
  1471. return hr;
  1472. }
  1473. //
  1474. // internal functions
  1475. //
  1476. /* C R E A T E C A N D W I N D O W O B J E C T */
  1477. /*------------------------------------------------------------------------------
  1478. ------------------------------------------------------------------------------*/
  1479. HRESULT CCandidateUI::CreateCandWindowObject( ITfContext *pic, CCandWindowBase** ppCandWnd )
  1480. {
  1481. CANDUISTYLE style;
  1482. DWORD dwOption;
  1483. DWORD dwStyle;
  1484. Assert( ppCandWnd );
  1485. *ppCandWnd = NULL;
  1486. if (FAILED( GetCompartmentMgr()->GetUIStyle( pic, &style ))) {
  1487. style = CANDUISTY_LIST;
  1488. }
  1489. if (FAILED( GetCompartmentMgr()->GetUIOption( pic, &dwOption ))) {
  1490. dwOption = 0;
  1491. }
  1492. dwStyle = 0;
  1493. if ((dwOption & CANDUIOPT_ENABLETHEME) != 0) {
  1494. dwStyle |= UIWINDOW_WHISTLERLOOK;
  1495. }
  1496. switch (style) {
  1497. default:
  1498. case CANDUISTY_LIST: {
  1499. *ppCandWnd = new CCandWindow( this, dwStyle );
  1500. break;
  1501. }
  1502. case CANDUISTY_ROW: {
  1503. *ppCandWnd = new CChsCandWindow( this, dwStyle );
  1504. break;
  1505. }
  1506. }
  1507. return (*ppCandWnd != NULL) ? S_OK : E_OUTOFMEMORY;
  1508. }
  1509. /* I N I T C A N D W I N D O W */
  1510. /*------------------------------------------------------------------------------
  1511. ------------------------------------------------------------------------------*/
  1512. HRESULT CCandidateUI::InitCandWindow( void )
  1513. {
  1514. CEditSession *pes;
  1515. if (m_pCandWnd == NULL) {
  1516. return E_FAIL;
  1517. }
  1518. m_pCandWnd->Initialize();
  1519. // move candidate window
  1520. Assert( m_pCandWnd != NULL );
  1521. if (pes = new CEditSession( EditSessionCallback )) {
  1522. HRESULT hr;
  1523. pes->_state.u = ESCB_RESETTARGETPOS;
  1524. pes->_state.pv = this;
  1525. pes->_state.wParam = 0;
  1526. pes->_state.pRange = m_pTargetRange;
  1527. pes->_state.pic = m_picParent;
  1528. m_picParent->RequestEditSession( m_tidClient, pes, TF_ES_READ | TF_ES_SYNC, &hr );
  1529. pes->Release();
  1530. }
  1531. // initialize candidate list
  1532. m_pCandWnd->InitCandidateList();
  1533. // create window
  1534. m_pCandWnd->CreateWnd( m_hWndParent );
  1535. m_pCandWnd->Show( GetPropertyMgr()->GetCandWindowProp()->IsVisible() );
  1536. m_pCandWnd->UpdateAllWindow();
  1537. return S_OK;
  1538. }
  1539. //
  1540. //
  1541. //
  1542. /* O N K E Y E V E N T */
  1543. /*------------------------------------------------------------------------------
  1544. ------------------------------------------------------------------------------*/
  1545. HRESULT CCandidateUI::OnKeyEvent( UINT uCode, WPARAM wParam, LPARAM lParam, BOOL *pfEaten )
  1546. {
  1547. HRESULT hr = E_FAIL;
  1548. BOOL fHandled = FALSE;
  1549. BYTE rgbKeyState[ 256 ];
  1550. Assert( pfEaten != NULL );
  1551. Assert( uCode == ICO_KEYDOWN || uCode == ICO_KEYUP || uCode == ICO_TESTKEYDOWN || uCode == ICO_TESTKEYUP );
  1552. if (pfEaten == NULL) {
  1553. return E_POINTER;
  1554. }
  1555. *pfEaten = FALSE;
  1556. if (m_pCandWnd == NULL) {
  1557. return hr;
  1558. }
  1559. if (GetKeyboardState( rgbKeyState )) {
  1560. if (GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
  1561. fHandled = FHandleFilteringKey( uCode, (int)wParam, rgbKeyState, pfEaten );
  1562. }
  1563. if (!fHandled) {
  1564. fHandled = FHandleKeyEvent( uCode, (int)wParam, rgbKeyState, pfEaten );
  1565. }
  1566. // cancel candidate when unknown key has come
  1567. if (!fHandled) {
  1568. NotifyCancelCand();
  1569. }
  1570. hr = S_OK;
  1571. }
  1572. return hr;
  1573. }
  1574. /* H A N D L E K E Y E V E N T */
  1575. /*------------------------------------------------------------------------------
  1576. Handling key event
  1577. return S_OK when processed the key event.
  1578. ------------------------------------------------------------------------------*/
  1579. BOOL CCandidateUI::FHandleKeyEvent( UINT uCode, UINT uVKey, BYTE *pbKeyState, BOOL *pfEatKey )
  1580. {
  1581. CANDUICOMMAND cmd;
  1582. UINT uiParam;
  1583. // NOTE: KOJIW: We need to ignore keyup events to not close candidate UI
  1584. // immediately after TIP opens CandidateUI with KEYDOWN of unknown key.
  1585. if (uCode == ICO_KEYUP || uCode == ICO_TESTKEYUP) {
  1586. return TRUE;
  1587. }
  1588. // process command on keydown
  1589. CommandFromKey( uVKey, pbKeyState, &cmd, &uiParam );
  1590. if (cmd == CANDUICMD_NONE) {
  1591. switch (uVKey) {
  1592. case VK_SHIFT:
  1593. case VK_CONTROL: {
  1594. return TRUE;
  1595. }
  1596. default: {
  1597. return FALSE;
  1598. }
  1599. }
  1600. }
  1601. if (uCode == ICO_KEYDOWN) {
  1602. *pfEatKey = SUCCEEDED(m_pCandWnd->ProcessCommand( cmd, uiParam ));
  1603. }
  1604. else {
  1605. *pfEatKey = TRUE;
  1606. }
  1607. return *pfEatKey;
  1608. }
  1609. /* H A N D L E T E X T D E L T A S */
  1610. /*------------------------------------------------------------------------------
  1611. ------------------------------------------------------------------------------*/
  1612. BOOL CCandidateUI::HandleTextDeltas( TfEditCookie ec, ITfContext *pic, IEnumTfRanges *pEnumRanges )
  1613. {
  1614. ULONG ulFetched;
  1615. ITfRange *pRange;
  1616. pEnumRanges->Reset();
  1617. while (pEnumRanges->Next( 1, &pRange, &ulFetched ) == S_OK) {
  1618. WCHAR szText[ 256 ];
  1619. ULONG cch;
  1620. // check text in the range
  1621. szText[0] = L'\0';
  1622. cch = 0;
  1623. if (pRange != NULL) {
  1624. pRange->GetText( ec, 0, szText, ARRAYSIZE(szText), &cch );
  1625. pRange->Release();
  1626. }
  1627. //
  1628. if (0 < cch) {
  1629. int i = 0;
  1630. ULONG ich;
  1631. for (ich = 0; ich < cch; ich++) {
  1632. if ((L'0' <= szText[ich]) && (szText[ich] <= L'9')) {
  1633. i = i * 10 + (szText[ich] - L'0');
  1634. }
  1635. else if (szText[ich] == L' ') {
  1636. break;
  1637. }
  1638. else {
  1639. i = -1;
  1640. break;
  1641. }
  1642. }
  1643. if (0 <= i) {
  1644. if (i == 0) {
  1645. PostCommand( CANDUICMD_SELECTEXTRACAND, 0 );
  1646. }
  1647. else {
  1648. PostCommand( CANDUICMD_SELECTLINE, i );
  1649. }
  1650. }
  1651. }
  1652. }
  1653. return TRUE;
  1654. }
  1655. /* P O S T C O M M A N D */
  1656. /*------------------------------------------------------------------------------
  1657. ------------------------------------------------------------------------------*/
  1658. void CCandidateUI::PostCommand( CANDUICOMMAND cmd, INT iParam )
  1659. {
  1660. if ((cmd != CANDUICMD_NONE) && (m_pCandWnd != NULL)) {
  1661. PostMessage( m_pCandWnd->GetWnd(), WM_USER, (WPARAM)cmd, (LPARAM)iParam );
  1662. }
  1663. }
  1664. //
  1665. // Auto filtering functions
  1666. //
  1667. /* H A N D L E F I L T E R I N G K E Y */
  1668. /*------------------------------------------------------------------------------
  1669. Handle key event for filtering
  1670. Returns TRUE to eat the event (when key has been handled)
  1671. ------------------------------------------------------------------------------*/
  1672. BOOL CCandidateUI::FHandleFilteringKey( UINT uCode, UINT uVKey, BYTE *pbKeyState, BOOL *pfEatKey )
  1673. {
  1674. BOOL fHandled = FALSE;
  1675. BOOL fUpdateList = FALSE;
  1676. switch (uVKey) {
  1677. case VK_RETURN: {
  1678. break;
  1679. }
  1680. case VK_TAB: {
  1681. if (GetCandListMgr()->GetCandList() != NULL) {
  1682. if (uCode == ICO_KEYDOWN) {
  1683. int iCandItem;
  1684. iCandItem = GetCandListMgr()->GetCandList()->GetSelection();
  1685. NotifyCompleteCand( iCandItem );
  1686. *pfEatKey = TRUE;
  1687. }
  1688. else {
  1689. *pfEatKey = TRUE;
  1690. }
  1691. fHandled = TRUE;
  1692. }
  1693. break;
  1694. }
  1695. case VK_BACK: {
  1696. if (uCode == ICO_KEYDOWN) {
  1697. *pfEatKey = (DelFilteringChar( &fUpdateList ) == S_OK);
  1698. }
  1699. else {
  1700. *pfEatKey = TRUE;
  1701. }
  1702. fHandled = TRUE;
  1703. break;
  1704. }
  1705. default: {
  1706. WCHAR wch;
  1707. // Check this is not a control + key combination as we do not want to pass this on to the filtering system.
  1708. if (pbKeyState[VK_CONTROL] & 0x80) {
  1709. break;
  1710. }
  1711. // convert key to char
  1712. wch = CharFromKey( uVKey, pbKeyState );
  1713. if (wch == L'\0') {
  1714. break;
  1715. }
  1716. // add filtering character
  1717. if (uCode == ICO_KEYDOWN) {
  1718. *pfEatKey = (AddFilteringChar( wch, &fUpdateList ) == S_OK);
  1719. }
  1720. else {
  1721. *pfEatKey = TRUE;
  1722. }
  1723. fHandled = *pfEatKey;
  1724. break;
  1725. }
  1726. }
  1727. // update candidate list
  1728. if (fUpdateList) {
  1729. *pfEatKey &= (FilterCandidateList() == S_OK);
  1730. }
  1731. return fHandled;
  1732. }
  1733. /* A D D F I L T E R I N G C H A R */
  1734. /*------------------------------------------------------------------------------
  1735. ------------------------------------------------------------------------------*/
  1736. HRESULT CCandidateUI::AddFilteringChar( WCHAR wch, BOOL *pfUpdateList )
  1737. {
  1738. HRESULT hr = S_FALSE;
  1739. LPCWSTR szFilterCur;
  1740. WCHAR *szFilterNew;
  1741. int cch;
  1742. *pfUpdateList = FALSE;
  1743. if (!GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
  1744. return S_FALSE;
  1745. }
  1746. // append a character and set filtering string
  1747. szFilterCur = GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString();
  1748. if (szFilterCur == NULL) {
  1749. cch = 0;
  1750. szFilterNew = new WCHAR[ 2 ];
  1751. }
  1752. else {
  1753. cch = wcslen(szFilterCur);
  1754. szFilterNew = new WCHAR[ cch + 2 ];
  1755. }
  1756. if (szFilterNew == NULL) {
  1757. return E_OUTOFMEMORY;
  1758. }
  1759. if (szFilterCur != NULL) {
  1760. StringCchCopyW( szFilterNew, cch+2, szFilterCur );
  1761. }
  1762. *(szFilterNew + cch) = wch;
  1763. *(szFilterNew + cch + 1) = L'\0';
  1764. // Satori#3632: check if there is item matches with new filter string
  1765. // (return S_FALSE when no item matches to pass key event to keyboard command handler)
  1766. if (GetFunctionMgr()->GetCandFnAutoFilter()->FExistItemMatches( szFilterNew )) {
  1767. GetFunctionMgr()->GetCandFnAutoFilter()->SetFilterString( szFilterNew );
  1768. *pfUpdateList = TRUE;
  1769. hr = S_OK;
  1770. }
  1771. else {
  1772. // Only when alpha, punctation, space key is pressed,
  1773. // and there is no alternate match because of this input,
  1774. // we want to notify client of NONMATCH event, so that
  1775. // client can inject the previous filter string to document,
  1776. //
  1777. // for all other key input, we don't notify that event.
  1778. if ( iswalpha(wch) || iswpunct(wch) )
  1779. {
  1780. // Notify client of non-matching.
  1781. NotifyFilteringEvent( CANDUIFEV_NONMATCH );
  1782. NotifyCancelCand();
  1783. }
  1784. hr = S_FALSE;
  1785. }
  1786. delete szFilterNew;
  1787. //
  1788. return hr;
  1789. }
  1790. /* D E L F I L T E R I N G C H A R */
  1791. /*------------------------------------------------------------------------------
  1792. ------------------------------------------------------------------------------*/
  1793. HRESULT CCandidateUI::DelFilteringChar( BOOL *pfUpdateList )
  1794. {
  1795. LPCWSTR szFilterCur;
  1796. WCHAR *szFilterNew;
  1797. int cch;
  1798. *pfUpdateList = FALSE;
  1799. if (!GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
  1800. return S_OK;
  1801. }
  1802. // get current filtering string
  1803. szFilterCur = GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString();
  1804. if (szFilterCur == NULL) {
  1805. NotifyCancelCand();
  1806. return S_FALSE;
  1807. }
  1808. // delete last character and set filtering string
  1809. cch = wcslen(szFilterCur);
  1810. Assert( 0 < cch );
  1811. szFilterNew = new WCHAR[ cch + 1 ];
  1812. if (szFilterNew == NULL)
  1813. {
  1814. return E_OUTOFMEMORY;
  1815. }
  1816. StringCchCopyW( szFilterNew, cch+1, szFilterCur );
  1817. *(szFilterNew + cch - 1) = L'\0';
  1818. GetFunctionMgr()->GetCandFnAutoFilter()->SetFilterString( szFilterNew );
  1819. delete szFilterNew;
  1820. //
  1821. *pfUpdateList = TRUE;
  1822. return S_OK;
  1823. }
  1824. /* F I L T E R C A N D I D A T E L I S T */
  1825. /*------------------------------------------------------------------------------
  1826. ------------------------------------------------------------------------------*/
  1827. HRESULT CCandidateUI::FilterCandidateList( void )
  1828. {
  1829. int nItemVisible;
  1830. if (!GetFunctionMgr()->GetCandFnAutoFilter()->IsEnabled()) {
  1831. return S_OK;
  1832. }
  1833. Assert( GetCandListMgr()->GetCandList() != NULL );
  1834. // build candidate list with filtering
  1835. nItemVisible = GetFunctionMgr()->GetCandFnAutoFilter()->FilterCandidateList();
  1836. // close candidate when no item has been mathced
  1837. if (nItemVisible == 0) {
  1838. NotifyCancelCand();
  1839. return E_FAIL;
  1840. }
  1841. // complete candidate when only one item matched and user typed fully
  1842. if (nItemVisible == 1) {
  1843. CCandidateItem *pCandItem;
  1844. int iCandItem;
  1845. BOOL fComplete = FALSE;
  1846. iCandItem = GetCandListMgr()->GetCandList()->GetSelection();
  1847. pCandItem = GetCandListMgr()->GetCandList()->GetCandidateItem( iCandItem );
  1848. Assert( pCandItem != NULL );
  1849. if ((pCandItem != NULL) && (GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString() != NULL)) {
  1850. fComplete = (wcslen(pCandItem->GetString()) == wcslen(GetFunctionMgr()->GetCandFnAutoFilter()->GetFilterString()));
  1851. }
  1852. if (fComplete) {
  1853. NotifyCompleteCand( iCandItem );
  1854. return S_OK;
  1855. }
  1856. }
  1857. // notify TIP that filtering has been updated
  1858. NotifyFilteringEvent( CANDUIFEV_UPDATED );
  1859. return S_OK;
  1860. }
  1861. /* FHandleSpellingChar */
  1862. /*------------------------------------------------------------------------------
  1863. ------------------------------------------------------------------------------*/
  1864. HRESULT CCandidateUI::FHandleSpellingChar(WCHAR ch)
  1865. {
  1866. BOOL fUpdateList = FALSE;
  1867. if (S_OK == AddFilteringChar( ch, &fUpdateList ) && fUpdateList) {
  1868. return FilterCandidateList();
  1869. }
  1870. return E_FAIL;
  1871. }
  1872. /*
  1873. **
  1874. ** Speech handling functions
  1875. **
  1876. **
  1877. */
  1878. /* E N S U R E S P E E C H */
  1879. /*------------------------------------------------------------------------------
  1880. ------------------------------------------------------------------------------*/
  1881. void CCandidateUI::EnsureSpeech(void)
  1882. {
  1883. if (m_pSpTask)
  1884. {
  1885. // make sure grammars are up/running
  1886. m_pSpTask->_LoadGrammars();
  1887. m_pSpTask->_Activate(TRUE);
  1888. return;
  1889. }
  1890. m_pSpTask = new CSpTask(this);
  1891. if (m_pSpTask)
  1892. {
  1893. if (!m_pSpTask->IsSpeechInitialized())
  1894. {
  1895. m_pSpTask->InitializeSpeech();
  1896. }
  1897. }
  1898. }
  1899. /* N O T I F Y S P E E C H C M D */
  1900. /*------------------------------------------------------------------------------
  1901. Speech command handler
  1902. ------------------------------------------------------------------------------*/
  1903. HRESULT CCandidateUI::NotifySpeechCmd(SPPHRASE *pPhrase, const WCHAR *pszRuleName, ULONG ulRuleId)
  1904. {
  1905. HRESULT hr = S_OK;
  1906. CANDUICOMMAND cmd;
  1907. UINT uiParam;
  1908. if (m_pCandWnd == NULL) {
  1909. return E_FAIL;
  1910. }
  1911. CommandFromRule( pszRuleName, &cmd, &uiParam );
  1912. if (cmd != CANDUICMD_NONE) {
  1913. m_pCandWnd->ProcessCommand( cmd, uiParam );
  1914. }
  1915. return hr;
  1916. }
  1917. /* C H A R F R O M K E Y */
  1918. /*------------------------------------------------------------------------------
  1919. ------------------------------------------------------------------------------*/
  1920. WCHAR CCandidateUI::CharFromKey( UINT uVKey, BYTE *pbKeyState )
  1921. {
  1922. WORD wBuf;
  1923. char rgch[2];
  1924. WCHAR wch;
  1925. int cch;
  1926. int cwch;
  1927. cch = ToAscii( uVKey, 0, pbKeyState, &wBuf, 0 );
  1928. rgch[0] = LOBYTE(wBuf);
  1929. rgch[1] = HIBYTE(wBuf);
  1930. cwch = MultiByteToWideChar( m_codepage, 0, rgch, cch, &wch, 1 );
  1931. if (cwch != 1) {
  1932. wch = L'\0';
  1933. }
  1934. return wch;
  1935. }
  1936. /* G E T K E Y C O N F I G P R O C */
  1937. /*------------------------------------------------------------------------------
  1938. ------------------------------------------------------------------------------*/
  1939. CCandUIKeyTable *CCandidateUI::GetKeyTableProc( ITfContext *pic )
  1940. {
  1941. CCandUIKeyTable *pCandUIKeyTable;
  1942. CANDUISTYLE style;
  1943. // check key table in input context
  1944. if (GetCompartmentMgr() != NULL) {
  1945. if (SUCCEEDED(GetCompartmentMgr()->GetKeyTable( pic, &pCandUIKeyTable ))) {
  1946. return pCandUIKeyTable;
  1947. }
  1948. }
  1949. // use default key table
  1950. if (FAILED(GetCompartmentMgr()->GetUIStyle( pic, &style ))) {
  1951. style = CANDUISTY_LIST;
  1952. }
  1953. pCandUIKeyTable = new CCandUIKeyTable();
  1954. if (pCandUIKeyTable)
  1955. {
  1956. switch (style) {
  1957. default:
  1958. case CANDUISTY_LIST: {
  1959. pCandUIKeyTable->SetKeyTable( rgKeyDefList, ARRAYSIZE(rgKeyDefList) );
  1960. break;
  1961. }
  1962. case CANDUISTY_ROW: {
  1963. pCandUIKeyTable->SetKeyTable( rgKeyDefRow, ARRAYSIZE(rgKeyDefRow) );
  1964. break;
  1965. }
  1966. }
  1967. }
  1968. return pCandUIKeyTable;
  1969. }
  1970. /* C O M M A N D F R O M K E Y */
  1971. /*------------------------------------------------------------------------------
  1972. Get command from key
  1973. ------------------------------------------------------------------------------*/
  1974. void CCandidateUI::CommandFromKey( UINT uVKey, BYTE *pbKeyState, CANDUICOMMAND *pcmd, UINT *pParam )
  1975. {
  1976. Assert( pcmd != NULL );
  1977. Assert( pParam != NULL );
  1978. Assert( pbKeyState != NULL );
  1979. *pcmd = CANDUICMD_NONE;
  1980. *pParam = 0;
  1981. // check special keys
  1982. switch( uVKey) {
  1983. case VK_TAB: {
  1984. *pcmd = CANDUICMD_NOP;
  1985. break;
  1986. }
  1987. }
  1988. if (*pcmd != CANDUICMD_NONE) {
  1989. return;
  1990. }
  1991. // find from key table
  1992. if (m_pCandUIKeyTable != NULL) {
  1993. WCHAR wch = CharFromKey( uVKey, pbKeyState );
  1994. m_pCandUIKeyTable->CommandFromKey( uVKey, wch, pbKeyState, GetPropertyMgr()->GetCandWindowProp()->GetUIDirection(), pcmd, pParam );
  1995. }
  1996. }
  1997. /* C O M M A N D F R O M R U L E */
  1998. /*------------------------------------------------------------------------------
  1999. Get command from speech rule
  2000. ------------------------------------------------------------------------------*/
  2001. void CCandidateUI::CommandFromRule( LPCWSTR szRule, CANDUICOMMAND *pcmd, UINT *pParam )
  2002. {
  2003. const RULEDEF *pRuleDef = NULL;
  2004. int nRuleDef = 0;
  2005. Assert( pcmd != NULL );
  2006. Assert( pParam != NULL );
  2007. *pcmd = CANDUICMD_NONE;
  2008. *pParam = 0;
  2009. //
  2010. // find ruledef table from current state
  2011. //
  2012. // NOTE: Currently CandidateUI doesn't have candidate Menu... only Normal state is available
  2013. if (!m_pCandWnd->FCandMenuOpen()) {
  2014. pRuleDef = rgRuleNorm;
  2015. nRuleDef = ARRAYSIZE(rgRuleNorm);
  2016. }
  2017. //
  2018. // get command from ruledef table
  2019. //
  2020. if (pRuleDef != NULL) {
  2021. while (0 < nRuleDef) {
  2022. if (wcscmp( szRule, pRuleDef->szRuleName ) == 0) {
  2023. *pcmd = pRuleDef->cmd;
  2024. *pParam = pRuleDef->uiParam;
  2025. break;
  2026. }
  2027. nRuleDef--;
  2028. pRuleDef++;
  2029. }
  2030. }
  2031. }
  2032. //
  2033. //
  2034. //
  2035. /* C T F C A N D I D A T E U I C O N T E X T O W N E R */
  2036. /*------------------------------------------------------------------------------
  2037. constructor of CTfCandidateUIContextOwner
  2038. ------------------------------------------------------------------------------*/
  2039. CTfCandidateUIContextOwner::CTfCandidateUIContextOwner( CCandidateUI *pCandUI )
  2040. {
  2041. m_pCandUI = pCandUI;
  2042. if (m_pCandUI != NULL) {
  2043. m_pCandUI->AddRef();
  2044. }
  2045. }
  2046. /* ~ C T F C A N D I D A T E U I C O N T E X T O W N E R */
  2047. /*------------------------------------------------------------------------------
  2048. destructor of CTfCandidateUIContextOwner
  2049. ------------------------------------------------------------------------------*/
  2050. CTfCandidateUIContextOwner::~CTfCandidateUIContextOwner( void )
  2051. {
  2052. if (m_pCandUI != NULL) {
  2053. m_pCandUI->Release();
  2054. }
  2055. }
  2056. /* Q U E R Y I N T E R F A C E */
  2057. /*------------------------------------------------------------------------------
  2058. Query interface
  2059. (IUnknown method)
  2060. ------------------------------------------------------------------------------*/
  2061. STDAPI CTfCandidateUIContextOwner::QueryInterface( REFIID riid, void **ppvObj )
  2062. {
  2063. if (ppvObj == NULL) {
  2064. return E_POINTER;
  2065. }
  2066. *ppvObj = NULL;
  2067. if (IsEqualIID( riid, IID_IUnknown ) || IsEqualIID( riid, IID_ITfCandidateUIContextOwner )) {
  2068. *ppvObj = SAFECAST( this, ITfCandidateUIContextOwner* );
  2069. }
  2070. if (*ppvObj == NULL) {
  2071. return E_NOINTERFACE;
  2072. }
  2073. AddRef();
  2074. return S_OK;
  2075. }
  2076. /* A D D R E F */
  2077. /*------------------------------------------------------------------------------
  2078. Increment reference count
  2079. (IUnknown method)
  2080. ------------------------------------------------------------------------------*/
  2081. STDAPI_(ULONG) CTfCandidateUIContextOwner::AddRef( void )
  2082. {
  2083. m_cRef++;
  2084. return m_cRef;
  2085. }
  2086. /* R E L E A S E */
  2087. /*------------------------------------------------------------------------------
  2088. Decrement reference count and release object
  2089. (IUnknown method)
  2090. ------------------------------------------------------------------------------*/
  2091. STDAPI_(ULONG) CTfCandidateUIContextOwner::Release( void )
  2092. {
  2093. m_cRef--;
  2094. if (0 < m_cRef) {
  2095. return m_cRef;
  2096. }
  2097. delete this;
  2098. return 0;
  2099. }
  2100. /* P R O C E S S C O M M A N D */
  2101. /*------------------------------------------------------------------------------
  2102. process command
  2103. ------------------------------------------------------------------------------*/
  2104. STDAPI CTfCandidateUIContextOwner::ProcessCommand(CANDUICOMMAND cmd, INT iParam)
  2105. {
  2106. HRESULT hr;
  2107. if (m_pCandUI != NULL) {
  2108. m_pCandUI->PostCommand( cmd, iParam );
  2109. hr = S_OK;
  2110. }
  2111. else {
  2112. hr = E_FAIL;
  2113. }
  2114. return hr;
  2115. }
  2116. /* T E S T T E X T */
  2117. /*------------------------------------------------------------------------------
  2118. test text
  2119. ------------------------------------------------------------------------------*/
  2120. STDAPI CTfCandidateUIContextOwner::TestText(BSTR bstr, BOOL *pfHandles)
  2121. {
  2122. HRESULT hr;
  2123. int i;
  2124. ULONG ich;
  2125. ULONG cch;
  2126. if (bstr == NULL || pfHandles == NULL) {
  2127. hr = E_INVALIDARG;
  2128. goto Exit;
  2129. }
  2130. if (m_pCandUI == NULL) {
  2131. hr = E_FAIL;
  2132. goto Exit;
  2133. }
  2134. *pfHandles = FALSE;
  2135. i = 0;
  2136. cch = SysStringLen( bstr );
  2137. for (ich = 0; ich < cch; ich++) {
  2138. if ((L'0' <= bstr[ich]) && (bstr[ich] <= L'9')) {
  2139. i = i * 10 + (bstr[ich] - L'0');
  2140. }
  2141. else if (bstr[ich] == L' ') {
  2142. break;
  2143. }
  2144. else {
  2145. i = -1;
  2146. break;
  2147. }
  2148. }
  2149. if (0 <= i) {
  2150. if (i == 0) {
  2151. if (m_pCandUI->GetCandListMgr()->GetCandList() != NULL) {
  2152. *pfHandles = (m_pCandUI->GetCandListMgr()->GetCandList()->GetExtraCandItem() != NULL);
  2153. }
  2154. }
  2155. else {
  2156. if (m_pCandUI->GetCandWindow() != NULL) {
  2157. m_pCandUI->GetCandWindow()->IsIndexValid( i, pfHandles );
  2158. }
  2159. }
  2160. }
  2161. hr = S_OK;
  2162. Exit:
  2163. return hr;
  2164. }