1 /*
2 * PROJECT: ReactOS msctfime.ime
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: The bridge of msctfime.ime
5 * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include "msctfime.h"
9
10 WINE_DEFAULT_DEBUG_CHANNEL(msctfime);
11
12 /// @implemented
CicBridge()13 CicBridge::CicBridge()
14 {
15 m_bImmxInited = FALSE;
16 m_bUnknown1 = FALSE;
17 m_bDeactivating = FALSE;
18 m_bUnknown2 = FALSE;
19 m_pKeystrokeMgr = NULL;
20 m_pDocMgr = NULL;
21 m_pThreadMgrEventSink = NULL;
22 m_cliendId = 0;
23 m_cRefs = 1;
24 }
25
26 /// @implemented
QueryInterface(REFIID riid,LPVOID * ppvObj)27 STDMETHODIMP CicBridge::QueryInterface(REFIID riid, LPVOID* ppvObj)
28 {
29 static const QITAB c_tab[] =
30 {
31 QITABENT(CicBridge, ITfSysHookSink),
32 { NULL }
33 };
34 return ::QISearch(this, c_tab, riid, ppvObj);
35 }
36
37 /// @implemented
STDMETHODIMP_(ULONG)38 STDMETHODIMP_(ULONG) CicBridge::AddRef()
39 {
40 return ::InterlockedIncrement(&m_cRefs);
41 }
42
43 /// @implemented
STDMETHODIMP_(ULONG)44 STDMETHODIMP_(ULONG) CicBridge::Release()
45 {
46 if (::InterlockedDecrement(&m_cRefs) == 0)
47 {
48 delete this;
49 return 0;
50 }
51 return m_cRefs;
52 }
53
54 /// @implemented
~CicBridge()55 CicBridge::~CicBridge()
56 {
57 TLS *pTLS = TLS::PeekTLS();
58 if (!pTLS || !pTLS->m_pThreadMgr)
59 return;
60
61 if (SUCCEEDED(DeactivateIMMX(pTLS, pTLS->m_pThreadMgr)))
62 UnInitIMMX(pTLS);
63 }
64
65 /// @implemented
66 ITfDocumentMgr*
GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT> & imeContext)67 CicBridge::GetDocumentManager(_Inout_ CicIMCCLock<CTFIMECONTEXT>& imeContext)
68 {
69 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
70 if (!pCicIC)
71 return NULL;
72
73 pCicIC->m_pDocumentMgr->AddRef();
74 return pCicIC->m_pDocumentMgr;
75 }
76
77 /// @implemented
78 HRESULT
CreateInputContext(_Inout_ TLS * pTLS,_In_ HIMC hIMC)79 CicBridge::CreateInputContext(
80 _Inout_ TLS *pTLS,
81 _In_ HIMC hIMC)
82 {
83 CicIMCLock imcLock(hIMC);
84 if (FAILED(imcLock.m_hr))
85 return imcLock.m_hr;
86
87 if (!imcLock.get().hCtfImeContext)
88 {
89 HIMCC hCtfImeContext = ImmCreateIMCC(sizeof(CTFIMECONTEXT));
90 if (!hCtfImeContext)
91 return E_OUTOFMEMORY;
92 imcLock.get().hCtfImeContext = hCtfImeContext;
93 }
94
95 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
96 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
97 if (pCicIC)
98 return S_OK;
99
100 pCicIC = new(cicNoThrow) CicInputContext(m_cliendId, &m_LibThread, hIMC);
101 if (!pCicIC)
102 {
103 imeContext.unlock();
104 imcLock.unlock();
105 DestroyInputContext(pTLS, hIMC);
106 return E_OUTOFMEMORY;
107 }
108
109 if (!pTLS->m_pThreadMgr)
110 {
111 pCicIC->Release();
112 imeContext.unlock();
113 imcLock.unlock();
114 DestroyInputContext(pTLS, hIMC);
115 return E_NOINTERFACE;
116 }
117
118 imeContext.get().m_pCicIC = pCicIC;
119
120 HRESULT hr = pCicIC->CreateInputContext(pTLS->m_pThreadMgr, imcLock);
121 if (FAILED(hr))
122 {
123 pCicIC->Release();
124 imeContext.get().m_pCicIC = NULL;
125 return hr;
126 }
127
128 HWND hWnd = imcLock.get().hWnd;
129 if (hWnd && hWnd == ::GetFocus())
130 {
131 ITfDocumentMgr *pDocMgr = GetDocumentManager(imeContext);
132 if (pDocMgr)
133 {
134 SetAssociate(pTLS, hWnd, hIMC, pTLS->m_pThreadMgr, pDocMgr);
135 pDocMgr->Release();
136 }
137 }
138
139 return hr;
140 }
141
142 /// @implemented
DestroyInputContext(TLS * pTLS,HIMC hIMC)143 HRESULT CicBridge::DestroyInputContext(TLS *pTLS, HIMC hIMC)
144 {
145 CicIMCLock imcLock(hIMC);
146 HRESULT hr = imcLock.m_hr;
147 if (FAILED(hr))
148 return hr;
149
150 hr = E_FAIL;
151 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
152 if (imeContext)
153 hr = imeContext.m_hr;
154
155 if (SUCCEEDED(hr) && !(imeContext.get().m_dwCicFlags & 1))
156 {
157 imeContext.get().m_dwCicFlags |= 1;
158
159 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
160 if (pCicIC)
161 {
162 imeContext.get().m_pCicIC = NULL;
163 hr = pCicIC->DestroyInputContext();
164 pCicIC->Release();
165 imeContext.get().m_pCicIC = NULL;
166 }
167 }
168
169 if (imcLock.get().hCtfImeContext)
170 {
171 ImmDestroyIMCC(imcLock.get().hCtfImeContext);
172 imcLock.get().hCtfImeContext = NULL;
173 hr = S_OK;
174 }
175
176 return hr;
177 }
178
179 /// @implemented
180 ITfContext *
GetInputContext(CicIMCCLock<CTFIMECONTEXT> & imeContext)181 CicBridge::GetInputContext(CicIMCCLock<CTFIMECONTEXT>& imeContext)
182 {
183 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
184 if (!pCicIC)
185 return NULL;
186 return pCicIC->m_pContext;
187 }
188
189 /// @implemented
OnSetOpenStatus(TLS * pTLS,ITfThreadMgr_P * pThreadMgr,CicIMCLock & imcLock,CicInputContext * pCicIC)190 HRESULT CicBridge::OnSetOpenStatus(
191 TLS *pTLS,
192 ITfThreadMgr_P *pThreadMgr,
193 CicIMCLock& imcLock,
194 CicInputContext *pCicIC)
195 {
196 if (!imcLock.get().fOpen && imcLock.ValidCompositionString())
197 pCicIC->EscbCompComplete(imcLock);
198
199 pTLS->m_bNowOpening = TRUE;
200 HRESULT hr = SetCompartmentDWORD(m_cliendId, pThreadMgr,
201 GUID_COMPARTMENT_KEYBOARD_OPENCLOSE,
202 imcLock.get().fOpen, FALSE);
203 pTLS->m_bNowOpening = FALSE;
204 return hr;
205 }
206
207 /// Selects the IME context.
208 /// @implemented
209 HRESULT
SelectEx(_Inout_ TLS * pTLS,_Inout_ ITfThreadMgr_P * pThreadMgr,_In_ HIMC hIMC,_In_ BOOL fSelect,_In_ HKL hKL)210 CicBridge::SelectEx(
211 _Inout_ TLS *pTLS,
212 _Inout_ ITfThreadMgr_P *pThreadMgr,
213 _In_ HIMC hIMC,
214 _In_ BOOL fSelect,
215 _In_ HKL hKL)
216 {
217 CicIMCLock imcLock(hIMC);
218 if (FAILED(imcLock.m_hr))
219 return imcLock.m_hr;
220
221 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
222 if (FAILED(imeContext.m_hr))
223 return imeContext.m_hr;
224
225 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
226 if (pCicIC)
227 pCicIC->m_bSelecting = TRUE;
228
229 if (fSelect)
230 {
231 if (pCicIC)
232 pCicIC->m_bCandidateOpen = FALSE;
233 if (imcLock.get().fOpen)
234 OnSetOpenStatus(pTLS, pThreadMgr, imcLock, pCicIC);
235 }
236 else
237 {
238 ITfContext *pContext = GetInputContext(imeContext);
239 pThreadMgr->RequestPostponedLock(pContext);
240 if (pCicIC)
241 pCicIC->m_bSelecting = FALSE;
242 if (pContext)
243 pContext->Release();
244 }
245
246 return imeContext.m_hr;
247 }
248
249 /// Used in CicBridge::EnumCreateInputContextCallback and
250 /// CicBridge::EnumDestroyInputContextCallback.
251 typedef struct ENUM_CREATE_DESTROY_IC
252 {
253 TLS *m_pTLS;
254 CicBridge *m_pBridge;
255 } ENUM_CREATE_DESTROY_IC, *PENUM_CREATE_DESTROY_IC;
256
257 /// Creates input context for the current thread.
258 /// @implemented
EnumCreateInputContextCallback(HIMC hIMC,LPARAM lParam)259 BOOL CALLBACK CicBridge::EnumCreateInputContextCallback(HIMC hIMC, LPARAM lParam)
260 {
261 PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam;
262 pData->m_pBridge->CreateInputContext(pData->m_pTLS, hIMC);
263 return TRUE;
264 }
265
266 /// Destroys input context for the current thread.
267 /// @implemented
EnumDestroyInputContextCallback(HIMC hIMC,LPARAM lParam)268 BOOL CALLBACK CicBridge::EnumDestroyInputContextCallback(HIMC hIMC, LPARAM lParam)
269 {
270 PENUM_CREATE_DESTROY_IC pData = (PENUM_CREATE_DESTROY_IC)lParam;
271 pData->m_pBridge->DestroyInputContext(pData->m_pTLS, hIMC);
272 return TRUE;
273 }
274
275 /// @implemented
276 HRESULT
ActivateIMMX(_Inout_ TLS * pTLS,_Inout_ ITfThreadMgr_P * pThreadMgr)277 CicBridge::ActivateIMMX(
278 _Inout_ TLS *pTLS,
279 _Inout_ ITfThreadMgr_P *pThreadMgr)
280 {
281 HRESULT hr = pThreadMgr->ActivateEx(&m_cliendId, 1);
282 if (hr != S_OK)
283 {
284 m_cliendId = 0;
285 return E_FAIL;
286 }
287
288 if (m_cActivateLocks++ != 0)
289 return S_OK;
290
291 ITfSourceSingle *pSource = NULL;
292 hr = pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void**)&pSource);
293 if (FAILED(hr))
294 {
295 DeactivateIMMX(pTLS, pThreadMgr);
296 return hr;
297 }
298
299 CFunctionProvider *pProvider = new(cicNoThrow) CFunctionProvider(m_cliendId);
300 if (!pProvider)
301 {
302 hr = E_FAIL;
303 goto Finish;
304 }
305
306 pSource->AdviseSingleSink(m_cliendId, IID_ITfFunctionProvider, pProvider);
307 pProvider->Release();
308
309 if (!m_pDocMgr)
310 {
311 hr = pThreadMgr->CreateDocumentMgr(&m_pDocMgr);
312 if (FAILED(hr))
313 {
314 hr = E_FAIL;
315 goto Finish;
316 }
317
318 SetCompartmentDWORD(m_cliendId, m_pDocMgr, GUID_COMPARTMENT_CTFIME_DIMFLAGS, TRUE, FALSE);
319 }
320
321 pThreadMgr->SetSysHookSink(this);
322
323 hr = S_OK;
324 if (pTLS->m_bDestroyed)
325 {
326 ENUM_CREATE_DESTROY_IC Data = { pTLS, this };
327 ImmEnumInputContext(0, CicBridge::EnumCreateInputContextCallback, (LPARAM)&Data);
328 }
329
330 Finish:
331 if (FAILED(hr))
332 DeactivateIMMX(pTLS, pThreadMgr);
333 if (pSource)
334 pSource->Release();
335 return hr;
336 }
337
338 /// @implemented
339 HRESULT
DeactivateIMMX(_Inout_ TLS * pTLS,_Inout_ ITfThreadMgr_P * pThreadMgr)340 CicBridge::DeactivateIMMX(
341 _Inout_ TLS *pTLS,
342 _Inout_ ITfThreadMgr_P *pThreadMgr)
343 {
344 if (m_bDeactivating)
345 return TRUE;
346
347 m_bDeactivating = TRUE;
348
349 if (m_cliendId)
350 {
351 ENUM_CREATE_DESTROY_IC Data = { pTLS, this };
352 ImmEnumInputContext(0, CicBridge::EnumDestroyInputContextCallback, (LPARAM)&Data);
353 pTLS->m_bDestroyed = TRUE;
354
355 ITfSourceSingle *pSource = NULL;
356 if (pThreadMgr->QueryInterface(IID_ITfSourceSingle, (void **)&pSource) == S_OK)
357 pSource->UnadviseSingleSink(m_cliendId, IID_ITfFunctionProvider);
358
359 m_cliendId = 0;
360
361 while (m_cActivateLocks > 0)
362 {
363 --m_cActivateLocks;
364 pThreadMgr->Deactivate();
365 }
366
367 if (pSource)
368 pSource->Release();
369 }
370
371 if (m_pDocMgr)
372 {
373 m_pDocMgr->Release();
374 m_pDocMgr = NULL;
375 }
376
377 pThreadMgr->SetSysHookSink(NULL);
378
379 m_bDeactivating = FALSE;
380
381 return S_OK;
382 }
383
384 /// @implemented
385 HRESULT
InitIMMX(_Inout_ TLS * pTLS)386 CicBridge::InitIMMX(_Inout_ TLS *pTLS)
387 {
388 if (m_bImmxInited)
389 return S_OK;
390
391 HRESULT hr = S_OK;
392 if (!pTLS->m_pThreadMgr)
393 {
394 ITfThreadMgr *pThreadMgr = NULL;
395 hr = TF_CreateThreadMgr(&pThreadMgr);
396 if (FAILED(hr))
397 return E_FAIL;
398
399 hr = pThreadMgr->QueryInterface(IID_ITfThreadMgr_P, (void **)&pTLS->m_pThreadMgr);
400 if (pThreadMgr)
401 pThreadMgr->Release();
402 if (FAILED(hr))
403 return E_FAIL;
404 }
405
406 if (!m_pThreadMgrEventSink)
407 {
408 m_pThreadMgrEventSink =
409 new(cicNoThrow) CThreadMgrEventSink(CThreadMgrEventSink::DIMCallback, NULL, NULL);
410 if (!m_pThreadMgrEventSink)
411 {
412 UnInitIMMX(pTLS);
413 return E_FAIL;
414 }
415 }
416
417 m_pThreadMgrEventSink->SetCallbackPV(m_pThreadMgrEventSink);
418 m_pThreadMgrEventSink->_Advise(pTLS->m_pThreadMgr);
419
420 if (!pTLS->m_pProfile)
421 {
422 pTLS->m_pProfile = new(cicNoThrow) CicProfile();
423 if (!pTLS->m_pProfile)
424 return E_OUTOFMEMORY;
425
426 hr = pTLS->m_pProfile->InitProfileInstance(pTLS);
427 if (FAILED(hr))
428 {
429 UnInitIMMX(pTLS);
430 return E_FAIL;
431 }
432 }
433
434 hr = pTLS->m_pThreadMgr->QueryInterface(IID_ITfKeystrokeMgr_P, (void **)&m_pKeystrokeMgr);
435 if (FAILED(hr))
436 {
437 UnInitIMMX(pTLS);
438 return E_FAIL;
439 }
440
441 hr = InitDisplayAttrbuteLib(&m_LibThread);
442 if (FAILED(hr))
443 {
444 UnInitIMMX(pTLS);
445 return E_FAIL;
446 }
447
448 m_bImmxInited = TRUE;
449 return S_OK;
450 }
451
452 /// @implemented
UnInitIMMX(_Inout_ TLS * pTLS)453 BOOL CicBridge::UnInitIMMX(_Inout_ TLS *pTLS)
454 {
455 UninitDisplayAttrbuteLib(&m_LibThread);
456 TFUninitLib_Thread(&m_LibThread);
457
458 if (m_pKeystrokeMgr)
459 {
460 m_pKeystrokeMgr->Release();
461 m_pKeystrokeMgr = NULL;
462 }
463
464 if (pTLS->m_pProfile)
465 {
466 pTLS->m_pProfile->Release();
467 pTLS->m_pProfile = NULL;
468 }
469
470 if (m_pThreadMgrEventSink)
471 {
472 m_pThreadMgrEventSink->_Unadvise();
473 m_pThreadMgrEventSink->Release();
474 m_pThreadMgrEventSink = NULL;
475 }
476
477 if (pTLS->m_pThreadMgr)
478 {
479 pTLS->m_pThreadMgr->Release();
480 pTLS->m_pThreadMgr = NULL;
481 }
482
483 m_bImmxInited = FALSE;
484 return TRUE;
485 }
486
487 /// @implemented
OnPreFocusDIM(HWND hwnd)488 STDMETHODIMP CicBridge::OnPreFocusDIM(HWND hwnd)
489 {
490 return S_OK;
491 }
492
493 /// @unimplemented
OnSysKeyboardProc(UINT,LONG)494 STDMETHODIMP CicBridge::OnSysKeyboardProc(UINT, LONG)
495 {
496 return E_NOTIMPL;
497 }
498
499 /// @implemented
OnSysShellProc(INT,UINT,LONG)500 STDMETHODIMP CicBridge::OnSysShellProc(INT, UINT, LONG)
501 {
502 return S_OK;
503 }
504
505 /// @implemented
506 void
PostTransMsg(_In_ HWND hWnd,_In_ INT cTransMsgs,_In_ const TRANSMSG * pTransMsgs)507 CicBridge::PostTransMsg(
508 _In_ HWND hWnd,
509 _In_ INT cTransMsgs,
510 _In_ const TRANSMSG *pTransMsgs)
511 {
512 for (INT i = 0; i < cTransMsgs; ++i, ++pTransMsgs)
513 {
514 ::PostMessageW(hWnd, pTransMsgs->message, pTransMsgs->wParam, pTransMsgs->lParam);
515 }
516 }
517
518 /// @implemented
519 HRESULT
ConfigureGeneral(_Inout_ TLS * pTLS,_In_ ITfThreadMgr * pThreadMgr,_In_ HKL hKL,_In_ HWND hWnd)520 CicBridge::ConfigureGeneral(
521 _Inout_ TLS* pTLS,
522 _In_ ITfThreadMgr *pThreadMgr,
523 _In_ HKL hKL,
524 _In_ HWND hWnd)
525 {
526 CicProfile *pProfile = pTLS->m_pProfile;
527 if (!pProfile)
528 return E_OUTOFMEMORY;
529
530 TF_LANGUAGEPROFILE profile;
531 HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD, &profile);
532 if (FAILED(hr))
533 return hr;
534
535 ITfFunctionProvider *pProvider = NULL;
536 hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider);
537 if (FAILED(hr))
538 return hr;
539
540 ITfFnConfigure *pFnConfigure = NULL;
541 hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigure, (IUnknown**)&pFnConfigure);
542 if (FAILED(hr))
543 {
544 pProvider->Release();
545 return hr;
546 }
547
548 hr = pFnConfigure->Show(hWnd, profile.langid, profile.guidProfile);
549
550 pFnConfigure->Release();
551 pProvider->Release();
552 return hr;
553 }
554
555 /// @implemented
556 HRESULT
ConfigureRegisterWord(_Inout_ TLS * pTLS,_In_ ITfThreadMgr * pThreadMgr,_In_ HKL hKL,_In_ HWND hWnd,_Inout_opt_ LPVOID lpData)557 CicBridge::ConfigureRegisterWord(
558 _Inout_ TLS* pTLS,
559 _In_ ITfThreadMgr *pThreadMgr,
560 _In_ HKL hKL,
561 _In_ HWND hWnd,
562 _Inout_opt_ LPVOID lpData)
563 {
564 CicProfile *pProfile = pTLS->m_pProfile;
565 if (!pProfile)
566 return E_OUTOFMEMORY;
567
568 TF_LANGUAGEPROFILE profile;
569 HRESULT hr = pProfile->GetActiveLanguageProfile(hKL, GUID_TFCAT_TIP_KEYBOARD, &profile);
570 if (FAILED(hr))
571 return hr;
572
573 ITfFunctionProvider *pProvider = NULL;
574 hr = pThreadMgr->GetFunctionProvider(profile.clsid, &pProvider);
575 if (FAILED(hr))
576 return hr;
577
578 ITfFnConfigureRegisterWord *pFunction = NULL;
579 hr = pProvider->GetFunction(GUID_NULL, IID_ITfFnConfigureRegisterWord, (IUnknown**)&pFunction);
580 if (FAILED(hr))
581 {
582 pProvider->Release();
583 return hr;
584 }
585
586 REGISTERWORDW* pRegWord = (REGISTERWORDW*)lpData;
587 if (pRegWord)
588 {
589 if (pRegWord->lpWord)
590 {
591 hr = E_OUTOFMEMORY;
592 BSTR bstrWord = SysAllocString(pRegWord->lpWord);
593 if (bstrWord)
594 {
595 hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile, bstrWord);
596 SysFreeString(bstrWord);
597 }
598 }
599 else
600 {
601 hr = pFunction->Show(hWnd, profile.langid, profile.guidProfile, NULL);
602 }
603 }
604
605 pProvider->Release();
606 pFunction->Release();
607 return hr;
608 }
609
610 /// @unimplemented
SetAssociate(TLS * pTLS,HWND hWnd,HIMC hIMC,ITfThreadMgr_P * pThreadMgr,ITfDocumentMgr * pDocMgr)611 void CicBridge::SetAssociate(
612 TLS *pTLS,
613 HWND hWnd,
614 HIMC hIMC,
615 ITfThreadMgr_P *pThreadMgr,
616 ITfDocumentMgr *pDocMgr)
617 {
618 //FIXME
619 }
620
621 HRESULT
SetActiveContextAlways(TLS * pTLS,HIMC hIMC,BOOL fActive,HWND hWnd,HKL hKL)622 CicBridge::SetActiveContextAlways(TLS *pTLS, HIMC hIMC, BOOL fActive, HWND hWnd, HKL hKL)
623 {
624 auto pThreadMgr = pTLS->m_pThreadMgr;
625 if (!pThreadMgr)
626 return E_OUTOFMEMORY;
627
628 if (fActive)
629 {
630 if (!hIMC)
631 {
632 SetAssociate(pTLS, hWnd, hIMC, pThreadMgr, m_pDocMgr);
633 return S_OK;
634 }
635
636 CicIMCLock imcLock(hIMC);
637 if (FAILED(imcLock.m_hr))
638 return imcLock.m_hr;
639
640 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
641 if (FAILED(imeContext.m_hr))
642 return imeContext.m_hr;
643
644 if (hIMC == ::ImmGetContext(hWnd))
645 {
646 ITfDocumentMgr *pDocMgr = GetDocumentManager(imeContext);
647 if (pDocMgr)
648 {
649 SetAssociate(pTLS, imcLock.get().hWnd, hIMC, pThreadMgr, pDocMgr);
650 pDocMgr->Release();
651 }
652 }
653
654 return S_OK;
655 }
656
657 if (hIMC && !IsEALang(LOWORD(hKL)))
658 {
659 CicIMCLock imcLock(hIMC);
660 if (FAILED(imcLock.m_hr))
661 return imcLock.m_hr;
662
663 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
664 if (FAILED(imeContext.m_hr))
665 return imeContext.m_hr;
666
667 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
668 if (!pCicIC->m_dwUnknown6_5[2] && !pCicIC->m_dwUnknown6_5[3])
669 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
670 }
671
672 if (!hIMC || (::GetFocus() != hWnd) || (hIMC != ::ImmGetContext(hWnd)))
673 SetAssociate(pTLS, hWnd, hIMC, pThreadMgr, m_pDocMgr);
674
675 return S_OK;
676 }
677
678 /// @unimplemented
679 BOOL
DoOpenCandidateHanja(ITfThreadMgr_P * pThreadMgr,CicIMCLock & imcLock,CicInputContext * pCicIC)680 CicBridge::DoOpenCandidateHanja(
681 ITfThreadMgr_P *pThreadMgr,
682 CicIMCLock& imcLock,
683 CicInputContext *pCicIC)
684 {
685 return FALSE;
686 }
687
688 /// @unimplemented
689 HRESULT
OnSetConversionSentenceMode(ITfThreadMgr_P * pThreadMgr,CicIMCLock & imcLock,CicInputContext * pCicIC,DWORD dwValue,LANGID LangID)690 CicBridge::OnSetConversionSentenceMode(
691 ITfThreadMgr_P *pThreadMgr,
692 CicIMCLock& imcLock,
693 CicInputContext *pCicIC,
694 DWORD dwValue,
695 LANGID LangID)
696 {
697 return E_NOTIMPL;
698 }
699
700 /// @implemented
Notify(TLS * pTLS,ITfThreadMgr_P * pThreadMgr,HIMC hIMC,DWORD dwAction,DWORD dwIndex,DWORD_PTR dwValue)701 HRESULT CicBridge::Notify(
702 TLS *pTLS,
703 ITfThreadMgr_P *pThreadMgr,
704 HIMC hIMC,
705 DWORD dwAction,
706 DWORD dwIndex,
707 DWORD_PTR dwValue)
708 {
709 CicIMCLock imcLock(hIMC);
710 if (FAILED(imcLock.m_hr))
711 return imcLock.m_hr;
712
713 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
714 if (FAILED(imeContext.m_hr))
715 return imeContext.m_hr;
716
717 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
718 if (!pCicIC)
719 return E_OUTOFMEMORY;
720
721 CicProfile *pProfile = pTLS->m_pProfile;
722 if (!pProfile)
723 return E_OUTOFMEMORY;
724
725 LANGID LangID;
726 pProfile->GetLangId(&LangID);
727
728 switch (dwAction)
729 {
730 case NI_OPENCANDIDATE:
731 if (PRIMARYLANGID(LangID) == LANG_KOREAN)
732 {
733 if (DoOpenCandidateHanja(pThreadMgr, imcLock, pCicIC))
734 return S_OK;
735 return E_FAIL;
736 }
737 return E_NOTIMPL;
738
739 case NI_COMPOSITIONSTR:
740 switch (dwIndex)
741 {
742 case CPS_COMPLETE:
743 pCicIC->EscbCompComplete(imcLock);
744 break;
745
746 case CPS_CONVERT:
747 case CPS_REVERT:
748 return E_NOTIMPL;
749
750 case CPS_CANCEL:
751 pCicIC->EscbCompCancel(imcLock);
752 break;
753
754 default:
755 return E_FAIL;
756 }
757 return S_OK;
758
759 case NI_CONTEXTUPDATED:
760 switch (dwValue)
761 {
762 case IMC_SETCONVERSIONMODE:
763 case IMC_SETSENTENCEMODE:
764 return OnSetConversionSentenceMode(pThreadMgr, imcLock, pCicIC, dwValue, LangID);
765
766 case IMC_SETOPENSTATUS:
767 return OnSetOpenStatus(pTLS, pThreadMgr, imcLock, pCicIC);
768
769 case IMC_SETCANDIDATEPOS:
770 return pCicIC->OnSetCandidatePos(pTLS, imcLock);
771
772 case IMC_SETCOMPOSITIONFONT:
773 case IMC_SETCOMPOSITIONWINDOW:
774 return E_NOTIMPL;
775
776 default:
777 return E_FAIL;
778 }
779 break;
780
781 default:
782 return E_NOTIMPL;
783 }
784 }
785
786 /// @unimplemented
ProcessKey(TLS * pTLS,ITfThreadMgr_P * pThreadMgr,HIMC hIMC,WPARAM wParam,LPARAM lParam,CONST LPBYTE lpbKeyState,INT * pnUnknown60)787 BOOL CicBridge::ProcessKey(
788 TLS *pTLS,
789 ITfThreadMgr_P *pThreadMgr,
790 HIMC hIMC,
791 WPARAM wParam,
792 LPARAM lParam,
793 CONST LPBYTE lpbKeyState,
794 INT *pnUnknown60)
795 {
796 return FALSE; // FIXME
797 }
798
799 /// @unimplemented
800 HRESULT
ToAsciiEx(TLS * pTLS,ITfThreadMgr_P * pThreadMgr,UINT uVirtKey,UINT uScanCode,CONST LPBYTE lpbKeyState,LPTRANSMSGLIST lpTransBuf,UINT fuState,HIMC hIMC,UINT * pResult)801 CicBridge::ToAsciiEx(
802 TLS *pTLS,
803 ITfThreadMgr_P *pThreadMgr,
804 UINT uVirtKey,
805 UINT uScanCode,
806 CONST LPBYTE lpbKeyState,
807 LPTRANSMSGLIST lpTransBuf,
808 UINT fuState,
809 HIMC hIMC,
810 UINT *pResult)
811 {
812 return E_NOTIMPL; // FIXME
813 }
814
815 /// @implemented
816 BOOL
SetCompositionString(TLS * pTLS,ITfThreadMgr_P * pThreadMgr,HIMC hIMC,DWORD dwIndex,LPCVOID lpComp,DWORD dwCompLen,LPCVOID lpRead,DWORD dwReadLen)817 CicBridge::SetCompositionString(
818 TLS *pTLS,
819 ITfThreadMgr_P *pThreadMgr,
820 HIMC hIMC,
821 DWORD dwIndex,
822 LPCVOID lpComp,
823 DWORD dwCompLen,
824 LPCVOID lpRead,
825 DWORD dwReadLen)
826 {
827 CicIMCLock imcLock(hIMC);
828 if (FAILED(imcLock.m_hr))
829 return FALSE;
830
831 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
832 if (FAILED(imeContext.m_hr))
833 return FALSE;
834
835 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
836 auto pProfile = pTLS->m_pProfile;
837 if (!pCicIC || !pProfile)
838 return FALSE;
839
840 UINT uCodePage;
841 pProfile->GetCodePageA(&uCodePage);
842
843 LANGID LangID;
844 if (dwIndex != SCS_SETSTR ||
845 !lpComp || *(WORD*)lpComp ||
846 !dwCompLen ||
847 FAILED(pProfile->GetLangId(&LangID)) ||
848 PRIMARYLANGID(LangID) != LANG_KOREAN)
849 {
850 return pCicIC->SetCompositionString(imcLock, pThreadMgr, dwIndex,
851 lpComp, dwCompLen, lpRead, dwReadLen,
852 uCodePage);
853 }
854
855 if (imcLock.get().fdwConversion & IME_CMODE_NATIVE)
856 {
857 ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
858 return TRUE;
859 }
860
861 return FALSE;
862 }
863
864 /// @unimplemented
865 LRESULT
EscHanjaMode(TLS * pTLS,HIMC hIMC,LPVOID lpData)866 CicBridge::EscHanjaMode(TLS *pTLS, HIMC hIMC, LPVOID lpData)
867 {
868 CicIMCLock imcLock(hIMC);
869 if (FAILED(imcLock.m_hr))
870 return imcLock.m_hr;
871
872 CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
873 if (FAILED(imeContext.m_hr))
874 return imeContext.m_hr;
875
876 CicInputContext *pCicIC = imeContext.get().m_pCicIC;
877 if (!pCicIC)
878 return TRUE;
879
880 if (pCicIC->m_bCandidateOpen)
881 return TRUE;
882
883 pCicIC->m_dwUnknown6_5[4] |= 0x1;
884
885 //FIXME
886
887 pCicIC->m_dwUnknown6_5[4] &= ~0x1;
888
889 return TRUE;
890 }
891
892 /// @implemented
893 LRESULT
EscapeKorean(TLS * pTLS,HIMC hIMC,UINT uSubFunc,LPVOID lpData)894 CicBridge::EscapeKorean(TLS *pTLS, HIMC hIMC, UINT uSubFunc, LPVOID lpData)
895 {
896 if (uSubFunc == IME_ESC_QUERY_SUPPORT)
897 return *(DWORD*)lpData == IME_ESC_HANJA_MODE;
898 if (uSubFunc == IME_ESC_HANJA_MODE)
899 return EscHanjaMode(pTLS, hIMC, lpData);
900 return 0;
901 }
902
903 /// @implemented
IsOwnDim(ITfDocumentMgr * pDocMgr)904 BOOL CicBridge::IsOwnDim(ITfDocumentMgr *pDocMgr)
905 {
906 DWORD dwDimFlags = 0;
907 HRESULT hr = ::GetCompartmentDWORD(pDocMgr, GUID_COMPARTMENT_CTFIME_DIMFLAGS,
908 &dwDimFlags, FALSE);
909 if (FAILED(hr))
910 return FALSE;
911 return !!(dwDimFlags & 0x1);
912 }
913