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.

570 lines
16 KiB

  1. //
  2. // ic.cpp
  3. //
  4. #include "private.h"
  5. #include "common.h"
  6. #include "korimx.h"
  7. #include "icpriv.h"
  8. #include "ipointcic.h"
  9. #include "cleanup.h"
  10. #include "helpers.h"
  11. //+---------------------------------------------------------------------------
  12. //
  13. // OnStartCleanupContext
  14. //
  15. //----------------------------------------------------------------------------
  16. HRESULT CKorIMX::OnStartCleanupContext()
  17. {
  18. // nb: a real tip, for performace, should skip input contexts it knows
  19. // it doesn't need a lock and callback on. For instance, kimx only
  20. // cares about ic's with ongoing compositions. We could remember which ic's
  21. // have compositions, then return FALSE for all but the ic's with compositions.
  22. // It is really bad perf to have the library make a lock request for every
  23. // ic!
  24. m_fPendingCleanup = fTrue;
  25. return S_OK;
  26. }
  27. //+---------------------------------------------------------------------------
  28. //
  29. // OnEndCleanupContext
  30. //
  31. // Called after all ic's with cleanup sinks have been called.
  32. //----------------------------------------------------------------------------
  33. HRESULT CKorIMX::OnEndCleanupContext()
  34. {
  35. // our profile just changed or we are about to be deactivated
  36. // in either case we don't have to worry about anything interrupting ic cleanup
  37. // callbacks anymore
  38. m_fPendingCleanup = fFalse;
  39. return S_OK;
  40. }
  41. //+---------------------------------------------------------------------------
  42. //
  43. // OnCleanupContext
  44. //
  45. // This method is a callback for the library helper CleanupAllContexts.
  46. // We have to be very careful here because we may be called _after_ this tip
  47. // has been deactivated, if the app couldn't grant a lock right away.
  48. //----------------------------------------------------------------------------
  49. HRESULT CKorIMX::OnCleanupContext(TfEditCookie ecWrite, ITfContext *pic)
  50. {
  51. // all kimx cares about is finalizing compositions
  52. CleanupAllCompositions(ecWrite, pic, CLSID_KorIMX, _CleanupCompositionsCallback, this);
  53. return S_OK;
  54. }
  55. //+---------------------------------------------------------------------------
  56. //
  57. // ITfActiveLanguageProfileNotifySink::OnActivated
  58. //
  59. //----------------------------------------------------------------------------
  60. STDAPI CKorIMX::OnActivated(REFCLSID clsid, REFGUID guidProfile, BOOL bActivated)
  61. {
  62. // our profile just changed or we are about to be deactivated
  63. // in either case we don't have to worry about anything interrupting ic cleanup
  64. // callbacks anymore
  65. m_fPendingCleanup = fFalse;
  66. //if (IsSoftKbdEnabled())
  67. // OnActivatedSoftKbd(bActivated);
  68. return S_OK;
  69. }
  70. //+---------------------------------------------------------------------------
  71. //
  72. // _CleanupCompositionsCallback
  73. //
  74. //----------------------------------------------------------------------------
  75. /* static */
  76. void CKorIMX::_CleanupCompositionsCallback(TfEditCookie ecWrite, ITfRange *rangeComposition, void *pvPrivate)
  77. {
  78. CKorIMX* pKorTip = (CKorIMX*)pvPrivate;
  79. ITfContext *pic;
  80. if (rangeComposition->GetContext(&pic) != S_OK)
  81. return;
  82. if (pKorTip)
  83. pKorTip->MakeResultString(ecWrite, pic, rangeComposition);
  84. // _FinalizeRange(ecWrite, pic, rangeComposition);
  85. pic->Release();
  86. }
  87. /*---------------------------------------------------------------------------
  88. CKorIMX::_InitICPriv
  89. Init IC private data
  90. ---------------------------------------------------------------------------*/
  91. HRESULT CKorIMX::_InitICPriv(ITfContext *pic)
  92. {
  93. CICPriv *picp;
  94. CCompartmentEventSink* pCompartmentSink;
  95. ITfSourceSingle *pSourceSingle;
  96. TF_STATUS dcs;
  97. // Check pic
  98. if (pic == NULL)
  99. return E_FAIL;
  100. //
  101. // check enable/disable (Candidate stack)
  102. //
  103. if (IsDisabledIC(pic) || IsEmptyIC(pic))
  104. return S_OK;
  105. // Initialize Private data members
  106. if ((picp = GetInputContextPriv(pic)) == NULL)
  107. {
  108. IUnknown *punk;
  109. if ((picp = new CICPriv) == NULL)
  110. return E_OUTOFMEMORY;
  111. // IC
  112. picp->RegisterIC(pic);
  113. // IMX
  114. picp->RegisterIMX(this);
  115. if (picp->IsInitializedIPoint() == FALSE)
  116. {
  117. //struct _GUID RefID={0}; // dummy id
  118. IImeIPoint1 *pIP;
  119. LPCIPointCic pCIPointCic = NULL;
  120. //////////////////////////////////////////////////////////////////////
  121. // Create IImeIPoint1 instance
  122. //////////////////////////////////////////////////////////////////////
  123. if ((pCIPointCic = new CIPointCic(this)) == NULL)
  124. {
  125. return E_OUTOFMEMORY;
  126. }
  127. // This increments the reference count
  128. if (FAILED(pCIPointCic->QueryInterface(IID_IImeIPoint1, (VOID **)&pIP)))
  129. {
  130. delete pCIPointCic;
  131. return E_OUTOFMEMORY;
  132. }
  133. // initialize kernel
  134. pCIPointCic->Initialize(pic);
  135. // register ic depended objects.
  136. picp->RegisterIPoint(pIP);
  137. picp->InitializedIPoint(fTrue);
  138. }
  139. //
  140. // text edit sink/edit transaction sink
  141. //
  142. ITfSource *pSource;
  143. DWORD dwCookieForTextEditSink = 0;
  144. //DWORD dwCookieForTransactionSink = 0;
  145. if (pic->QueryInterface(IID_ITfSource, (void **)&pSource ) == S_OK)
  146. {
  147. pSource->AdviseSink(IID_ITfTextEditSink, (ITfTextEditSink *)this, &dwCookieForTextEditSink);
  148. //pSource->AdviseSink(IID_ITfEditTransactionSink, (ITfEditTransactionSink *)this, &dwCookieForTransactionSink);
  149. pSource->Release();
  150. picp->RegisterCookieForTextEditSink(dwCookieForTextEditSink);
  151. //picp->RegisterCookieForTransactionSink(dwCookieForTransactionSink);
  152. }
  153. // compartment event sink
  154. if ((pCompartmentSink = new CCompartmentEventSink(_CompEventSinkCallback, picp)) != NULL )
  155. {
  156. picp->RegisterCompartmentEventSink(pCompartmentSink);
  157. // On/Off - compartment
  158. pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_KEYBOARD_OPENCLOSE, FALSE);
  159. // Conversion mode - compartment
  160. pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, FALSE);
  161. // SoftKeyboard Open/Close
  162. pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_KOR_SOFTKBD_OPENCLOSE, FALSE);
  163. // Soft Keyboard layout change
  164. pCompartmentSink->_Advise(GetTIM(), GUID_COMPARTMENT_SOFTKBD_KBDLAYOUT, FALSE);
  165. }
  166. Assert(pCompartmentSink != NULL);
  167. if (pic->QueryInterface(IID_ITfSourceSingle, (void **)&pSourceSingle) == S_OK)
  168. {
  169. // setup a cleanup callback
  170. // nb: a real tip doesn't need to be this aggressive, for instance
  171. // kimx probably only needs this sink on the focus ic.
  172. pSourceSingle->AdviseSingleSink(GetTID(), IID_ITfCleanupContextSink, (ITfCleanupContextSink *)this);
  173. pSourceSingle->Release();
  174. }
  175. // Initialized kernel
  176. picp->Initialized(fTrue);
  177. // Set to compartment GUID
  178. GetCompartmentUnknown(pic, GUID_IC_PRIVATE, &punk);
  179. if (!punk)
  180. {
  181. SetCompartmentUnknown(GetTID(), pic, GUID_IC_PRIVATE, picp);
  182. picp->Release();
  183. }
  184. else
  185. {
  186. // Praive data already exist.
  187. punk->Release();
  188. return E_FAIL;
  189. }
  190. }
  191. // Set AIMM1.2
  192. picp->SetAIMM(fFalse);
  193. pic->GetStatus(&dcs);
  194. if (dcs.dwStaticFlags & TF_SS_TRANSITORY)
  195. picp->SetAIMM(fTrue);
  196. return S_OK;
  197. }
  198. /*---------------------------------------------------------------------------
  199. CKorIMX::_DeleteICPriv
  200. Delete IC private data
  201. ---------------------------------------------------------------------------*/
  202. HRESULT CKorIMX::_DeleteICPriv(ITfContext *pic)
  203. {
  204. CICPriv *picp;
  205. IUnknown *punk;
  206. CCompartmentEventSink* pCompartmentSink;
  207. ITfSource *pSource;
  208. ITfSourceSingle *pSourceSingle;
  209. if (pic == NULL)
  210. return E_FAIL;
  211. picp = GetInputContextPriv(pic);
  212. #ifdef DBG
  213. Assert(IsDisabledIC(pic) || picp != NULL );
  214. #endif
  215. if (picp == NULL)
  216. return S_FALSE;
  217. //
  218. // Compartment event sink
  219. //
  220. pCompartmentSink = picp->GetCompartmentEventSink();
  221. if (pCompartmentSink)
  222. {
  223. pCompartmentSink->_Unadvise();
  224. pCompartmentSink->Release();
  225. }
  226. //
  227. // text edit sink
  228. //
  229. if (pic->QueryInterface( IID_ITfSource, (void **)&pSource) == S_OK)
  230. {
  231. pSource->UnadviseSink(picp->GetCookieForTextEditSink());
  232. //pSource->UnadviseSink(picp->GetCookieForTransactionSink());
  233. pSource->Release();
  234. }
  235. picp->RegisterCookieForTextEditSink(0);
  236. // Clear ITfCleanupContextSink
  237. if (pic->QueryInterface(IID_ITfSourceSingle, (void **)&pSourceSingle) == S_OK)
  238. {
  239. pSourceSingle->UnadviseSingleSink(GetTID(), IID_ITfCleanupContextSink);
  240. pSourceSingle->Release();
  241. }
  242. // UnInitialize IPoint
  243. IImeIPoint1 *pIP = GetIPoint(pic);
  244. // IImeIPoint
  245. if (pIP)
  246. {
  247. pIP->Release();
  248. }
  249. picp->RegisterIPoint(NULL);
  250. picp->InitializedIPoint(fFalse); // reset
  251. // Reset init flag
  252. picp->Initialized(fFalse);
  253. // We MUST clear out the private data before cicero is free
  254. // to release the ic
  255. GetCompartmentUnknown(pic, GUID_IC_PRIVATE, &punk);
  256. if (punk)
  257. punk->Release();
  258. ClearCompartment(GetTID(), pic, GUID_IC_PRIVATE, fFalse);
  259. return S_OK;
  260. }
  261. /*---------------------------------------------------------------------------
  262. CKorIMX::GetInputContextPriv
  263. Get IC private data
  264. ---------------------------------------------------------------------------*/
  265. CICPriv *CKorIMX::GetInputContextPriv(ITfContext *pic)
  266. {
  267. IUnknown *punk;
  268. if (pic == NULL)
  269. return NULL;
  270. GetCompartmentUnknown(pic, GUID_IC_PRIVATE, &punk);
  271. if (punk)
  272. punk->Release();
  273. return (CICPriv *)punk;
  274. }
  275. /*---------------------------------------------------------------------------
  276. CKorIMX::OnICChange
  277. ---------------------------------------------------------------------------*/
  278. void CKorIMX::OnFocusChange(ITfContext *pic, BOOL fActivate)
  279. {
  280. BOOL fReleaseIC = fFalse;
  281. BOOL fDisabledIC = IsDisabledIC(pic);
  282. BOOL fEmptyIC = IsEmptyIC(pic);
  283. BOOL fCandidateIC = IsCandidateIC(pic);
  284. BOOL fInEditSession;
  285. HRESULT hr;
  286. if (fEmptyIC)
  287. {
  288. if (m_pToolBar)
  289. m_pToolBar->SetCurrentIC(NULL);
  290. if (IsSoftKbdEnabled())
  291. SoftKbdOnThreadFocusChange(fFalse);
  292. return; // do nothing
  293. }
  294. if (fDisabledIC == fTrue && fCandidateIC == fFalse )
  295. {
  296. if (m_pToolBar)
  297. m_pToolBar->SetCurrentIC(NULL);
  298. if (IsSoftKbdEnabled())
  299. SoftKbdOnThreadFocusChange(fFalse);
  300. return; // do nothing
  301. }
  302. // O10 #278261: Restore Soft Keyboard winfow after switched from Empty Context to normal IC.
  303. if (IsSoftKbdEnabled())
  304. SoftKbdOnThreadFocusChange(fActivate);
  305. // Notify focus change to IME Pad svr
  306. if (m_pPadCore)
  307. {
  308. m_pPadCore->SetFocus(fActivate);
  309. }
  310. // Terminate
  311. if (fActivate == fFalse)
  312. {
  313. if (!fDisabledIC && pic && GetIPComposition(pic))
  314. {
  315. if (SUCCEEDED(pic->InWriteSession(GetTID(), &fInEditSession)) && !fInEditSession)
  316. {
  317. CEditSession2 *pes;
  318. ESSTRUCT ess;
  319. ESStructInit(&ess, ESCB_COMPLETE);
  320. if ((pes = new CEditSession2(pic, this, &ess, _EditSessionCallback2)))
  321. {
  322. pes->Invoke(ES2_READWRITE | ES2_SYNC, &hr);
  323. pes->Release();
  324. }
  325. }
  326. }
  327. // Close cand UI if opened.
  328. if (m_fCandUIOpen)
  329. CloseCandidateUIProc();
  330. return;
  331. }
  332. // fActivate == TRUE
  333. if (fDisabledIC)
  334. {
  335. pic = GetRootIC();
  336. fReleaseIC = fTrue;
  337. }
  338. if (m_pToolBar)
  339. m_pToolBar->SetCurrentIC(pic);
  340. if (m_pPadCore)
  341. {
  342. IImeIPoint1* pIP = GetIPoint(pic);
  343. m_pPadCore->SetIPoint(pIP);
  344. }
  345. if (pic && !fDisabledIC)
  346. {
  347. CICPriv *picp;
  348. // Sync GUID_COMPARTMENT_KEYBOARD_OPENCLOSE with GUID_COMPARTMENT_KORIMX_CONVMODE
  349. // This for Word now but looks not good since we don't sync On/Off status with conv mode.
  350. // In future Apps should set GUID_MODEBIAS_HANGUL on boot and should be Korean specific code.
  351. if (GetConvMode(pic) == TIP_NULL_CONV_MODE) // if this is first boot.
  352. {
  353. if (IsOn(pic))
  354. SetCompartmentDWORD(GetTID(), GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, TIP_HANGUL_MODE, fFalse);
  355. else
  356. SetCompartmentDWORD(GetTID(), GetTIM(), GUID_COMPARTMENT_KORIMX_CONVMODE, TIP_ALPHANUMERIC_MODE, fFalse);
  357. }
  358. else
  359. {
  360. // Reset ModeBias
  361. picp = GetInputContextPriv(pic);
  362. if (picp)
  363. picp->SetModeBias(NULL);
  364. }
  365. // Modebias check here
  366. CheckModeBias(pic);
  367. }
  368. if (fReleaseIC)
  369. SafeRelease(pic);
  370. }
  371. // REVIEW::
  372. // tmp solution
  373. ITfContext* CKorIMX::GetRootIC(ITfDocumentMgr* pDim)
  374. {
  375. if (pDim == NULL)
  376. {
  377. pDim = m_pCurrentDim;
  378. if( pDim == NULL )
  379. return NULL;
  380. }
  381. IEnumTfContexts *pEnumIc = NULL;
  382. if (SUCCEEDED(pDim->EnumContexts(&pEnumIc)))
  383. {
  384. ITfContext *pic = NULL;
  385. while (pEnumIc->Next(1, &pic, NULL) == S_OK)
  386. break;
  387. pEnumIc->Release();
  388. return pic;
  389. }
  390. return NULL; // error case
  391. }
  392. IImeIPoint1* CKorIMX::GetIPoint(ITfContext *pic)
  393. {
  394. CICPriv *picp;
  395. if (pic == NULL)
  396. {
  397. return NULL;
  398. }
  399. picp = GetInputContextPriv(pic);
  400. if (picp)
  401. {
  402. return picp->GetIPoint();
  403. }
  404. return NULL;
  405. }
  406. BOOL CKorIMX::IsDisabledIC(ITfContext *pic)
  407. {
  408. DWORD dwFlag;
  409. if (pic == NULL)
  410. return fFalse;
  411. GetCompartmentDWORD(pic, GUID_COMPARTMENT_KEYBOARD_DISABLED, &dwFlag, fFalse);
  412. if (dwFlag)
  413. return fTrue; // do not create any kernel related info into ic.
  414. else
  415. return fFalse;
  416. }
  417. /* I S E M P T Y I C */
  418. BOOL CKorIMX::IsEmptyIC(ITfContext *pic)
  419. {
  420. DWORD dwFlag;
  421. if (pic == NULL)
  422. return fFalse;
  423. GetCompartmentDWORD(pic, GUID_COMPARTMENT_EMPTYCONTEXT, &dwFlag, fFalse);
  424. if (dwFlag)
  425. return fTrue; // do not create any kernel related info into ic.
  426. return fFalse;
  427. }
  428. /* I S C A N D I D A T E I C */
  429. /*------------------------------------------------------------------------------
  430. Check if the input context is one of candidate UI
  431. ------------------------------------------------------------------------------*/
  432. BOOL CKorIMX::IsCandidateIC(ITfContext *pic)
  433. {
  434. DWORD dwFlag;
  435. if (pic == NULL)
  436. return fFalse;
  437. GetCompartmentDWORD( pic, GUID_COMPARTMENT_KEYBOARD_DISABLED, &dwFlag, fFalse);
  438. if (dwFlag)
  439. return fTrue; // do not create any kernel related info into ic.
  440. return fFalse;
  441. }
  442. HWND CKorIMX::GetAppWnd(ITfContext *pic)
  443. {
  444. ITfContextView* pView;
  445. HWND hwndApp = 0;
  446. if (pic == NULL)
  447. return 0;
  448. pic->GetActiveView(&pView);
  449. if (pView == NULL)
  450. return 0;
  451. pView->GetWnd(&hwndApp);
  452. pView->Release();
  453. return hwndApp;
  454. }