xref: /reactos/dll/ime/msctfime/ui.cpp (revision 299e4305)
1 /*
2  * PROJECT:     ReactOS msctfime.ime
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     User Interface 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 /***********************************************************************/
13 
14 UINT WM_MSIME_SERVICE = 0;
15 UINT WM_MSIME_UIREADY = 0;
16 UINT WM_MSIME_RECONVERTREQUEST = 0;
17 UINT WM_MSIME_RECONVERT = 0;
18 UINT WM_MSIME_DOCUMENTFEED = 0;
19 UINT WM_MSIME_QUERYPOSITION = 0;
20 UINT WM_MSIME_MODEBIAS = 0;
21 UINT WM_MSIME_SHOWIMEPAD = 0;
22 UINT WM_MSIME_MOUSE = 0;
23 UINT WM_MSIME_KEYMAP = 0;
24 
25 /// @implemented
26 BOOL IsMsImeMessage(_In_ UINT uMsg)
27 {
28     return (uMsg == WM_MSIME_SERVICE ||
29             uMsg == WM_MSIME_UIREADY ||
30             uMsg == WM_MSIME_RECONVERTREQUEST ||
31             uMsg == WM_MSIME_RECONVERT ||
32             uMsg == WM_MSIME_DOCUMENTFEED ||
33             uMsg == WM_MSIME_QUERYPOSITION ||
34             uMsg == WM_MSIME_MODEBIAS ||
35             uMsg == WM_MSIME_SHOWIMEPAD ||
36             uMsg == WM_MSIME_MOUSE ||
37             uMsg == WM_MSIME_KEYMAP);
38 }
39 
40 /// @implemented
41 BOOL RegisterMSIMEMessage(VOID)
42 {
43     // Using ANSI (A) version here can reduce binary size.
44     WM_MSIME_SERVICE = RegisterWindowMessageA("MSIMEService");
45     WM_MSIME_UIREADY = RegisterWindowMessageA("MSIMEUIReady");
46     WM_MSIME_RECONVERTREQUEST = RegisterWindowMessageA("MSIMEReconvertRequest");
47     WM_MSIME_RECONVERT = RegisterWindowMessageA("MSIMEReconvert");
48     WM_MSIME_DOCUMENTFEED = RegisterWindowMessageA("MSIMEDocumentFeed");
49     WM_MSIME_QUERYPOSITION = RegisterWindowMessageA("MSIMEQueryPosition");
50     WM_MSIME_MODEBIAS = RegisterWindowMessageA("MSIMEModeBias");
51     WM_MSIME_SHOWIMEPAD = RegisterWindowMessageA("MSIMEShowImePad");
52     WM_MSIME_MOUSE = RegisterWindowMessageA("MSIMEMouseOperation");
53     WM_MSIME_KEYMAP = RegisterWindowMessageA("MSIMEKeyMap");
54     return (WM_MSIME_SERVICE &&
55             WM_MSIME_UIREADY &&
56             WM_MSIME_RECONVERTREQUEST &&
57             WM_MSIME_RECONVERT &&
58             WM_MSIME_DOCUMENTFEED &&
59             WM_MSIME_QUERYPOSITION &&
60             WM_MSIME_MODEBIAS &&
61             WM_MSIME_SHOWIMEPAD &&
62             WM_MSIME_MOUSE &&
63             WM_MSIME_KEYMAP);
64 }
65 
66 /***********************************************************************/
67 
68 /// @implemented
69 CDefCompFrameGripper::CDefCompFrameGripper(
70     CDefCompFrameWindow *pDefCompFrameWindow,
71     LPCRECT prc,
72     DWORD style) : CUIFGripper(pDefCompFrameWindow, prc, style)
73 {
74     m_pDefCompFrameWindow = pDefCompFrameWindow;
75 }
76 
77 /***********************************************************************/
78 
79 /// @implemented
80 CCompFinalizeButton::CCompFinalizeButton(
81     CCompFrameWindow *pParent,
82     DWORD nObjectID,
83     LPCRECT prc,
84     DWORD style,
85     DWORD dwButtonFlags,
86     LPCWSTR pszText)
87     : CUIFToolbarButton(pParent, nObjectID, prc, style, dwButtonFlags, pszText)
88 {
89     m_pCompFrameWindow = pParent;
90 }
91 
92 /// @implemented
93 CCompFinalizeButton::~CCompFinalizeButton()
94 {
95     HICON hIcon = CUIFToolbarButton::GetIcon();
96     if (hIcon)
97     {
98         ::DestroyIcon(hIcon);
99         CUIFToolbarButton::SetIcon(NULL);
100     }
101 }
102 
103 /// @implemented
104 void CCompFinalizeButton::OnLeftClick()
105 {
106     HIMC hIMC = m_pCompFrameWindow->m_hIMC;
107     if (hIMC)
108         ::ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);
109 }
110 
111 /***********************************************************************/
112 
113 /// @implemented
114 CCompFrameWindow::CCompFrameWindow(HIMC hIMC, DWORD style)
115     : CUIFWindow(g_hInst, style)
116 {
117     m_hIMC = hIMC;
118 }
119 
120 /***********************************************************************/
121 
122 /// @implemented
123 CCompButtonFrameWindow::CCompButtonFrameWindow(HIMC hIMC, DWORD style)
124     : CCompFrameWindow(hIMC, style)
125 {
126 }
127 
128 /// @implemented
129 void CCompButtonFrameWindow::Init()
130 {
131     if (m_pFinalizeButton)
132         return;
133 
134     RECT rc = { 0, 0, 0, 0 };
135     m_pFinalizeButton = new(cicNoThrow) CCompFinalizeButton(this, 0, &rc, 0, 0x10000, NULL);
136 
137     m_pFinalizeButton->Initialize();
138     m_pFinalizeButton->Init();
139 
140     HICON hIcon = (HICON)::LoadImageW(g_hInst, MAKEINTRESOURCEW(IDI_DOWN), IMAGE_ICON, 16, 16, 0);
141     m_pFinalizeButton->SetIcon(hIcon);
142 
143     WCHAR szText[256];
144     LoadStringW(g_hInst, IDS_FINALIZE_STRING, szText, _countof(szText));
145     m_pFinalizeButton->SetToolTip(szText);
146 
147     AddUIObj(m_pFinalizeButton);
148 }
149 
150 /// @implemented
151 void CCompButtonFrameWindow::MoveShow(LONG x, LONG y, BOOL bShow)
152 {
153     INT nWidth = m_Margins.cxRightWidth + m_Margins.cxLeftWidth + 18;
154     INT nHeight = m_Margins.cyBottomHeight + m_Margins.cyTopHeight + 18;
155     Move(x, y, nWidth + 4, nHeight + 4);
156 
157     if (m_pFinalizeButton)
158     {
159         RECT rc = { 1, 1, nWidth + 1, nHeight + 1 };
160         m_pFinalizeButton->SetRect(&rc);
161     }
162 
163     Show(bShow);
164 }
165 
166 /// @implemented
167 STDMETHODIMP_(void) CCompButtonFrameWindow::OnCreate(HWND hWnd)
168 {
169     ::SetWindowTheme(hWnd, L"TOOLBAR", NULL);
170 
171     ZeroMemory(&m_Margins, sizeof(m_Margins));
172 
173     CUIFTheme theme;
174     theme.m_hTheme = NULL;
175     theme.m_iPartId = 1;
176     theme.m_iStateId = 0;
177     theme.m_pszClassList = L"TOOLBAR";
178     if (SUCCEEDED(theme.InternalOpenThemeData(hWnd)))
179         theme.GetThemeMargins(NULL, 1, 3602, NULL, &m_Margins);
180 }
181 
182 /***********************************************************************/
183 
184 /// @implemented
185 CDefCompFrameWindow::CDefCompFrameWindow(HIMC hIMC, DWORD style)
186     : CCompFrameWindow(hIMC, style)
187 {
188     LoadPosition();
189     m_iPartId = 1;
190     m_iStateId = 1;
191     m_pszClassList = L"TASKBAR";
192 }
193 
194 /// @implemented
195 CDefCompFrameWindow::~CDefCompFrameWindow()
196 {
197     SavePosition();
198 }
199 
200 /// @implemented
201 void CDefCompFrameWindow::Init()
202 {
203     RECT rc;
204 
205     if (!m_pGripper)
206     {
207         ZeroMemory(&rc, sizeof(rc));
208         m_pGripper = new(cicNoThrow) CDefCompFrameGripper(this, &rc, 0);
209         m_pGripper->Initialize();
210         AddUIObj(m_pGripper);
211     }
212 
213     if (!m_pFinalizeButton)
214     {
215         ZeroMemory(&rc, sizeof(rc));
216         m_pFinalizeButton = new(cicNoThrow) CCompFinalizeButton(this, 0, &rc, 0, 0x10000, NULL);
217         m_pFinalizeButton->Initialize();
218         m_pFinalizeButton->Init();
219 
220         HICON hIcon = (HICON)LoadImageW(g_hInst, MAKEINTRESOURCEW(IDI_DOWN), IMAGE_ICON, 16, 16, 0);
221         m_pFinalizeButton->SetIcon(hIcon);
222 
223         WCHAR szText[256];
224         ::LoadStringW(g_hInst, IDS_FINALIZE_STRING, szText, _countof(szText));
225         SetToolTip(szText);
226 
227         AddUIObj(m_pFinalizeButton);
228     }
229 }
230 
231 /// @implemented
232 INT CDefCompFrameWindow::GetGripperWidth()
233 {
234     if (!m_pGripper || FAILED(m_pGripper->EnsureThemeData(m_hWnd)))
235         return 5;
236 
237     INT ret = -1;
238     HDC hDC = ::GetDC(m_hWnd);
239     SIZE partSize;
240     if (SUCCEEDED(m_pGripper->GetThemePartSize(hDC, 1, 0, TS_TRUE, &partSize)))
241         ret = partSize.cx + 4;
242 
243     ::ReleaseDC(m_hWnd, hDC);
244 
245     return ((ret < 0) ? 5 : ret);
246 }
247 
248 /// @implemented
249 void CDefCompFrameWindow::MyScreenToClient(LPPOINT ppt, LPRECT prc)
250 {
251     if (ppt)
252         ::ScreenToClient(m_hWnd, ppt);
253 
254     if (prc)
255     {
256         ::ScreenToClient(m_hWnd, (LPPOINT)prc);
257         ::ScreenToClient(m_hWnd, (LPPOINT)&prc->right);
258     }
259 }
260 
261 /// @implemented
262 void CDefCompFrameWindow::SetCompStrRect(INT nWidth, INT nHeight, BOOL bShow)
263 {
264     INT GripperWidth = GetGripperWidth();
265 
266     RECT rc;
267     ::GetWindowRect(m_hWnd, &rc);
268 
269     Move(rc.left, rc.top, GripperWidth + nWidth + 24, nHeight + 10);
270 
271     if (m_pGripper)
272     {
273         rc = { 2, 3, GripperWidth + 2, nHeight + 7 };
274         m_pGripper->SetRect(&rc);
275     }
276 
277     if (m_pFinalizeButton)
278     {
279         rc = {
280             GripperWidth + nWidth + 4,
281             3,
282             m_Margins.cxLeftWidth + m_Margins.cxRightWidth + GripperWidth + nWidth + 22,
283             m_Margins.cyBottomHeight + m_Margins.cyTopHeight + 21
284         };
285         m_pFinalizeButton->SetRect(&rc);
286     }
287 
288     Show(bShow);
289 
290     ::MoveWindow(m_hwndCompStr, GripperWidth + 2, 7, nWidth, nHeight, TRUE);
291     ::ShowWindow(m_hwndCompStr, (bShow ? SW_SHOWNOACTIVATE : SW_HIDE));
292 }
293 
294 /// @implemented
295 void CDefCompFrameWindow::LoadPosition()
296 {
297     DWORD x = 0, y = 0;
298 
299     LSTATUS error;
300     CicRegKey regKey;
301     error = regKey.Open(HKEY_CURRENT_USER,
302                         TEXT("SOFTWARE\\Microsoft\\CTF\\CUAS\\DefaultCompositionWindow"));
303     if (error == ERROR_SUCCESS)
304     {
305         regKey.QueryDword(TEXT("Left"), &x);
306         regKey.QueryDword(TEXT("Top"), &y);
307     }
308 
309     Move(x, y, 0, 0);
310 }
311 
312 /// @implemented
313 void CDefCompFrameWindow::SavePosition()
314 {
315     LSTATUS error;
316     CicRegKey regKey;
317     error = regKey.Create(HKEY_CURRENT_USER,
318                           TEXT("SOFTWARE\\Microsoft\\CTF\\CUAS\\DefaultCompositionWindow"));
319     if (error == ERROR_SUCCESS)
320     {
321         regKey.SetDword(TEXT("Left"), m_nLeft);
322         regKey.SetDword(TEXT("Top"), m_nTop);
323     }
324 }
325 
326 /// @implemented
327 STDMETHODIMP_(void) CDefCompFrameWindow::OnCreate(HWND hWnd)
328 {
329     ::SetWindowTheme(hWnd, L"TASKBAR", NULL);
330 
331     ZeroMemory(&m_Margins, sizeof(m_Margins));
332 
333     CUIFTheme theme;
334     theme.m_hTheme = NULL;
335     theme.m_iPartId = 1;
336     theme.m_iStateId = 0;
337     theme.m_pszClassList = L"TOOLBAR";
338     if (SUCCEEDED(theme.InternalOpenThemeData(hWnd)))
339         GetThemeMargins(NULL, 1, 3602, NULL, &m_Margins);
340 }
341 
342 /// @implemented
343 STDMETHODIMP_(BOOL) CDefCompFrameWindow::OnSetCursor(UINT uMsg, LONG x, LONG y)
344 {
345     if (!::IsWindow(m_hwndCompStr))
346         return FALSE;
347 
348     RECT rc;
349     ::GetWindowRect(m_hwndCompStr, &rc);
350     MyScreenToClient(NULL, &rc);
351     POINT pt = { x, y };
352     return ::PtInRect(&rc, pt);
353 }
354 
355 /// @implemented
356 STDMETHODIMP_(LRESULT)
357 CDefCompFrameWindow::OnWindowPosChanged(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
358 {
359     CicIMCLock imcLock(m_hIMC);
360     if (SUCCEEDED(imcLock.m_hr))
361         ::SendMessage(imcLock.get().hWnd, WM_IME_NOTIFY, 0xF, (LPARAM)m_hIMC);
362     return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
363 }
364 
365 /// @implemented
366 STDMETHODIMP_(void) CDefCompFrameWindow::HandleMouseMsg(UINT uMsg, LONG x, LONG y)
367 {
368     if (::IsWindow(m_hwndCompStr))
369     {
370         RECT rc;
371         ::GetWindowRect(m_hwndCompStr, &rc);
372         MyScreenToClient(NULL, &rc);
373 
374         POINT pt = { x, y };
375         if (::PtInRect(&rc, pt))
376             ::SendMessage(m_hwndCompStr, 0x7E8, 0, 0);
377     }
378 
379     CUIFWindow::HandleMouseMsg(uMsg, x, y);
380 }
381 
382 /***********************************************************************/
383 
384 /// @implemented
385 POLYTEXTW *CPolyText::GetPolyAt(INT iItem)
386 {
387     return &m_PolyTextArray[iItem];
388 }
389 
390 /// @implemented
391 HRESULT CPolyText::ShiftPolyText(INT xDelta, INT yDelta)
392 {
393     for (size_t iItem = 0; iItem < m_PolyTextArray.size(); ++iItem)
394     {
395         POLYTEXTW *pPolyText = &m_PolyTextArray[iItem];
396         pPolyText->x += xDelta;
397         pPolyText->y += yDelta;
398         ::OffsetRect((LPRECT)&pPolyText->rcl, xDelta, yDelta);
399     }
400     return S_OK;
401 }
402 
403 /// @implemented
404 HRESULT CPolyText::RemoveLastLine(BOOL bHorizontal)
405 {
406     size_t iItem, cItems = m_PolyTextArray.size();
407     if (!cItems)
408         return E_FAIL;
409 
410     POLYTEXTW *pData1 = &m_PolyTextArray[cItems - 1];
411 
412     for (iItem = 0; iItem < cItems; ++iItem)
413     {
414         POLYTEXTW *pData2 = &m_PolyTextArray[iItem];
415         if (bHorizontal)
416         {
417             if (pData1->x == pData2->x)
418                 break;
419         }
420         else
421         {
422             if (pData1->y == pData2->y)
423                 break;
424         }
425     }
426 
427     if (iItem >= cItems)
428         return E_FAIL;
429 
430     m_PolyTextArray.Remove(iItem, cItems - iItem);
431     m_ValueArray.Remove(iItem, cItems - iItem);
432     return S_OK;
433 }
434 
435 /// @implemented
436 void CPolyText::RemoveAll()
437 {
438     m_PolyTextArray.clear();
439     m_ValueArray.clear();
440 }
441 
442 /***********************************************************************/
443 
444 /// @implemented
445 void COMPWND::_ClientToScreen(LPRECT prc)
446 {
447     ::ClientToScreen(m_hWnd, (LPPOINT)prc);
448     ::ClientToScreen(m_hWnd, (LPPOINT)&prc->right);
449 }
450 
451 /***********************************************************************/
452 
453 // For GetWindowLongPtr/SetWindowLongPtr
454 #define UICOMP_GWLP_INDEX 0
455 #define UICOMP_GWLP_SIZE  (UICOMP_GWLP_INDEX + sizeof(INT))
456 
457 /// @unimplemented
458 UIComposition::UIComposition(HWND hwndParent)
459 {
460 }
461 
462 /// @implemented
463 UIComposition::~UIComposition()
464 {
465     DestroyCompositionWindow();
466 
467     if (m_hFont1)
468     {
469         ::DeleteObject(m_hFont1);
470         m_hFont1 = NULL;
471     }
472 
473     if (m_hFont2)
474     {
475         ::DeleteObject(m_hFont2);
476         m_hFont2 = NULL;
477     }
478 
479     if (m_strCompStr)
480     {
481         cicMemFree(m_strCompStr);
482         m_strCompStr = NULL;
483     }
484 
485     m_cchCompStr = 0;
486 }
487 
488 // @implemented
489 BOOL UIComposition::SendMessageToUI(CicIMCLock& imcLock, WPARAM wParam, LPARAM lParam)
490 {
491     HWND hImeWnd = ImmGetDefaultIMEWnd(0);
492     if (!::IsWindow(hImeWnd))
493         return TRUE;
494     TLS *pTLS = TLS::GetTLS();
495     LRESULT ret;
496     if (pTLS && pTLS->m_cWnds > 1)
497         ret = ::SendMessage(imcLock.get().hWnd, WM_IME_NOTIFY, wParam, lParam);
498     else
499         ret = ::SendMessage(hImeWnd, WM_IME_NOTIFY, wParam, lParam);
500     return !ret;
501 }
502 
503 /// @implemented
504 HRESULT UIComposition::CreateDefFrameWnd(HWND hwndParent, HIMC hIMC)
505 {
506     if (!m_pDefCompFrameWindow)
507     {
508         m_pDefCompFrameWindow = new(cicNoThrow) CDefCompFrameWindow(hIMC, 0x800000A4);
509         if (!m_pDefCompFrameWindow)
510             return E_OUTOFMEMORY;
511         if (!m_pDefCompFrameWindow->Initialize())
512         {
513             delete m_pDefCompFrameWindow;
514             m_pDefCompFrameWindow = NULL;
515             return E_FAIL;
516         }
517 
518         m_pDefCompFrameWindow->Init();
519     }
520 
521     m_pDefCompFrameWindow->CreateWnd(hwndParent);
522     return S_OK;
523 }
524 
525 /// @implemented
526 HRESULT UIComposition::CreateCompButtonWnd(HWND hwndParent, HIMC hIMC)
527 {
528     TLS *pTLS = TLS::GetTLS();
529     if (!pTLS || !pTLS->NonEACompositionEnabled())
530         return S_OK;
531 
532     if (IsEALang(0))
533     {
534         if (m_pCompButtonFrameWindow)
535         {
536             delete m_pCompButtonFrameWindow;
537             m_pCompButtonFrameWindow = NULL;
538         }
539         return S_OK;
540     }
541 
542     if (!m_pCompButtonFrameWindow)
543     {
544         m_pCompButtonFrameWindow = new(cicNoThrow) CCompButtonFrameWindow(hIMC, 0x800000B4);
545         if (!m_pCompButtonFrameWindow)
546             return E_OUTOFMEMORY;
547 
548         if (!m_pCompButtonFrameWindow->Initialize())
549         {
550             if (m_pCompButtonFrameWindow)
551             {
552                 delete m_pCompButtonFrameWindow;
553                 m_pCompButtonFrameWindow = NULL;
554             }
555             return E_FAIL;
556         }
557 
558         m_pCompButtonFrameWindow->Init();
559     }
560 
561     m_pCompButtonFrameWindow->CreateWnd(hwndParent);
562     return S_OK;
563 }
564 
565 /// @implemented
566 HRESULT UIComposition::CreateCompositionWindow(CicIMCLock& imcLock, HWND hwndParent)
567 {
568     if (FAILED(imcLock.m_hr))
569         return imcLock.m_hr;
570 
571     if (!::IsWindow(hwndParent) || m_bHasCompWnd)
572         return E_FAIL;
573 
574     for (INT iCompStr = 0; iCompStr < 3; ++iCompStr)
575     {
576         DWORD style = WS_POPUP | WS_DISABLED;
577         HWND hwndCompStr = ::CreateWindowExW(0, L"MSCTFIME Composition", NULL, style,
578                                              0, 0, 0, 0, hwndParent, NULL, g_hInst, NULL);
579         m_CompStrs[iCompStr].m_hWnd = hwndCompStr;
580         ::SetWindowLongPtrW(hwndCompStr, GWLP_USERDATA, (LONG_PTR)this);
581         ::SetWindowLongPtrW(hwndCompStr, UICOMP_GWLP_INDEX, iCompStr);
582         m_CompStrs[iCompStr].m_Caret.CreateCaret(hwndCompStr, m_CaretSize);
583     }
584 
585     HRESULT hr = CreateCompButtonWnd(hwndParent, imcLock.m_hIMC);
586     if (FAILED(hr))
587     {
588         DestroyCompositionWindow();
589         return E_OUTOFMEMORY;
590     }
591 
592     hr = CreateDefFrameWnd(hwndParent, imcLock.m_hIMC);
593     if (FAILED(hr))
594     {
595         DestroyCompositionWindow();
596         return E_OUTOFMEMORY;
597     }
598 
599     DWORD style = WS_CHILD | WS_DISABLED;
600     HWND hwndCompStr = ::CreateWindowExW(WS_EX_CLIENTEDGE, L"MSCTFIME Composition", NULL, style,
601                                          0, 0, 0, 0, *m_pDefCompFrameWindow, NULL, g_hInst, NULL);
602     if (!hwndCompStr)
603     {
604         DestroyCompositionWindow();
605         return E_OUTOFMEMORY;
606     }
607 
608     m_CompStrs[3].m_hWnd = hwndCompStr;
609     m_pDefCompFrameWindow->m_hwndCompStr = hwndCompStr;
610     ::SetWindowLongPtrW(hwndCompStr, GWLP_USERDATA, (LONG_PTR)this);
611     ::SetWindowLongPtrW(hwndCompStr, UICOMP_GWLP_INDEX, -1);
612     m_CompStrs[3].m_Caret.CreateCaret(hwndCompStr, m_CaretSize);
613     m_bHasCompWnd = TRUE;
614 
615     return S_OK;
616 }
617 
618 /// @implemented
619 HRESULT UIComposition::DestroyCompositionWindow()
620 {
621     for (INT i = 0; i < 4; ++i)
622     {
623         COMPWND *pCompStr = &m_CompStrs[i];
624         pCompStr->m_Caret.DestroyCaret();
625         if (::IsWindow(pCompStr->m_hWnd))
626         {
627             DestroyWindow(pCompStr->m_hWnd);
628             pCompStr->m_PolyText.RemoveAll();
629         }
630         pCompStr->m_hWnd = NULL;
631     }
632 
633     if (m_pCompButtonFrameWindow)
634     {
635         ::DestroyWindow(*m_pCompButtonFrameWindow);
636         delete m_pCompButtonFrameWindow;
637         m_pCompButtonFrameWindow = NULL;
638     }
639 
640     if (m_pDefCompFrameWindow)
641     {
642         ::DestroyWindow(*m_pDefCompFrameWindow);
643         delete m_pDefCompFrameWindow;
644         m_pDefCompFrameWindow = NULL;
645     }
646 
647     return 0;
648 }
649 
650 // @implemented
651 BOOL UIComposition::InquireImeUIWndState(CicIMCLock& imcLock)
652 {
653     BOOL bValue = FALSE;
654     UIComposition::SendMessageToUI(imcLock, 0x11u, (LPARAM)&bValue);
655     return bValue;
656 }
657 
658 /// @implemented
659 HRESULT UIComposition::UpdateShowCompWndFlag(CicIMCLock& imcLock, DWORD *pdwCompStrLen)
660 {
661     if (FAILED(imcLock.m_hr))
662         return imcLock.m_hr;
663     if (!::IsWindow(imcLock.get().hWnd))
664         return E_FAIL;
665 
666     CicIMCCLock<COMPOSITIONSTRING> compStr(imcLock.get().hCompStr);
667     if (FAILED(compStr.m_hr))
668         return compStr.m_hr;
669 
670     if ((m_dwUnknown56[0] & 0x80000000) && compStr.get().dwCompStrLen)
671         m_bHasCompStr = TRUE;
672     else
673         m_bHasCompStr = FALSE;
674 
675     if (pdwCompStrLen)
676         *pdwCompStrLen = compStr.get().dwCompStrLen;
677 
678     return S_OK;
679 }
680 
681 /// @implemented
682 HRESULT UIComposition::UpdateFont(CicIMCLock& imcLock)
683 {
684     if (FAILED(imcLock.m_hr))
685         return imcLock.m_hr;
686 
687     if (m_hFont1)
688         ::DeleteObject(m_hFont1);
689     if (m_hFont2)
690         ::DeleteObject(m_hFont2);
691 
692     LOGFONTW lf = imcLock.get().lfFont.W;
693     m_hFont2 = ::CreateFontIndirectW(&lf);
694 
695     lf.lfEscapement = 0;
696     lf.lfOrientation = 0;
697     BOOL bVertical = (lf.lfFaceName[0] == L'@');
698     if (bVertical)
699     {
700         MoveMemory(lf.lfFaceName, &lf.lfFaceName[1], sizeof(lf.lfFaceName) - sizeof(WCHAR));
701         lf.lfFaceName[_countof(lf.lfFaceName) - 1] = UNICODE_NULL;
702     }
703     m_hFont1 = ::CreateFontIndirectW(&lf);
704 
705     return S_OK;
706 }
707 
708 // @implemented
709 void UIComposition::OnTimer(HWND hWnd)
710 {
711     INT iCompStr = (INT)::GetWindowLongPtrW(hWnd, UICOMP_GWLP_INDEX);
712     if (iCompStr == -1)
713         m_CompStrs[3].m_Caret.OnTimer();
714     else
715         m_CompStrs[iCompStr].m_Caret.OnTimer();
716 }
717 
718 /// @implemented
719 BOOL UIComposition::GetImeUIWndTextExtent(CicIMCLock& imcLock, LPARAM lParam)
720 {
721     return !UIComposition::SendMessageToUI(imcLock, 0x14, lParam);
722 }
723 
724 /// @implemented
725 LPWSTR UIComposition::GetCompStrBuffer(INT cchStr)
726 {
727     if (!m_strCompStr)
728     {
729         m_strCompStr = (LPWSTR)cicMemAllocClear((cchStr + 1) * sizeof(WCHAR));
730         m_cchCompStr = cchStr;
731     }
732     if (m_cchCompStr < cchStr)
733     {
734         m_strCompStr = (LPWSTR)cicMemReAlloc(m_strCompStr, (cchStr + 1) * sizeof(WCHAR));
735         m_cchCompStr = cchStr;
736     }
737     return m_strCompStr;
738 }
739 
740 /// @unimplemented
741 void UIComposition::OnImeStartComposition(CicIMCLock& imcLock, HWND hUIWnd)
742 {
743     //FIXME
744 }
745 
746 /// @implemented
747 HRESULT UIComposition::OnImeCompositionUpdate(CicIMCLock& imcLock)
748 {
749     m_dwUnknown56[0] |= 0x8000;
750     return UIComposition::UpdateShowCompWndFlag(imcLock, NULL);
751 }
752 
753 /// @unimplemented
754 HRESULT UIComposition::OnImeEndComposition()
755 {
756     m_dwUnknown56[0] = 0;
757     return DestroyCompositionWindow();
758 }
759 
760 /// @unimplemented
761 void UIComposition::OnImeSetContext(CicIMCLock& imcLock, HWND hUIWnd, WPARAM wParam, LPARAM lParam)
762 {
763     //FIXME
764 }
765 
766 /// @unimplemented
767 void UIComposition::OnPaintTheme(WPARAM wParam)
768 {
769     //FIXME
770 }
771 
772 /// @implemented
773 HRESULT UIComposition::OnDestroy()
774 {
775     return DestroyCompositionWindow();
776 }
777 
778 /// @unimplemented
779 LRESULT CALLBACK
780 UIComposition::CompWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
781 {
782     if (uMsg == WM_CREATE)
783         return -1; // FIXME
784     return 0;
785 }
786 
787 /// @implemented
788 HRESULT UIComposition::OnImeNotifySetCompositionWindow(CicIMCLock& imcLock)
789 {
790     return UpdateCompositionRect(imcLock);
791 }
792 
793 /// @unimplemented
794 HRESULT UIComposition::UpdateCompositionRect(CicIMCLock& imcLock)
795 {
796     return E_NOTIMPL;
797 }
798 
799 /// @implemented
800 INT UIComposition::GetLevelFromIMC(CicIMCLock& imcLock)
801 {
802     DWORD dwStyle = imcLock.get().cfCompForm.dwStyle;
803     if (dwStyle == CFS_DEFAULT)
804         return 1;
805     if (!(dwStyle & (CFS_FORCE_POSITION | CFS_POINT | CFS_RECT)))
806         return 0;
807 
808     RECT rc;
809     ::GetClientRect(imcLock.get().hWnd, &rc);
810     if (!::PtInRect(&rc, imcLock.get().cfCompForm.ptCurrentPos))
811         return 1;
812 
813     INPUTCONTEXT *pIC = &imcLock.get();
814     if ((pIC->cfCompForm.dwStyle & CFS_RECT) &&
815         (pIC->cfCompForm.rcArea.top == pIC->cfCompForm.rcArea.bottom) &&
816         (pIC->cfCompForm.rcArea.left == pIC->cfCompForm.rcArea.right))
817     {
818         return 1;
819     }
820 
821     return 2;
822 }
823 
824 /// @implemented
825 HRESULT UIComposition::OnImeSetContextAfter(CicIMCLock& imcLock)
826 {
827     if ((!m_pDefCompFrameWindow || !::IsWindow(*m_pDefCompFrameWindow)) && !::IsWindow(m_CompStrs[0].m_hWnd))
828     {
829         m_dwUnknown56[0] &= ~0x8000;
830         return S_OK;
831     }
832 
833     if (FAILED(imcLock.m_hr))
834         return imcLock.m_hr;
835 
836     INT Level = GetLevelFromIMC(imcLock);
837     if ((Level == 1 || Level == 2) && (m_dwUnknown56[0] & 0x80000000) && m_dwUnknown56[1])
838     {
839         DWORD dwCompStrLen = 0;
840         UpdateShowCompWndFlag(imcLock, &dwCompStrLen);
841 
842         if (Level == 1)
843         {
844             ::ShowWindow(*m_pDefCompFrameWindow, (m_bHasCompStr ? SW_SHOWNOACTIVATE : SW_HIDE));
845         }
846         else if (Level == 2 && !m_bHasCompStr && dwCompStrLen)
847         {
848             for (INT iCompStr = 0; iCompStr < 3; ++iCompStr)
849             {
850                 m_CompStrs[iCompStr].m_Caret.HideCaret();
851                 ::ShowWindow(m_CompStrs[iCompStr].m_Caret, SW_HIDE);
852             }
853         }
854     }
855     else
856     {
857         ::ShowWindow(*m_pDefCompFrameWindow, SW_HIDE);
858 
859         for (INT iCompStr = 0; iCompStr < 3; ++iCompStr)
860         {
861             m_CompStrs[iCompStr].m_Caret.HideCaret();
862             ::ShowWindow(m_CompStrs[iCompStr].m_Caret, SW_HIDE);
863         }
864     }
865 
866     return S_OK;
867 }
868 
869 /***********************************************************************/
870 
871 // For GetWindowLongPtr/SetWindowLongPtr
872 #define UI_GWLP_HIMC 0
873 #define UI_GWLP_UI   sizeof(HIMC)
874 #define UI_GWLP_SIZE (UI_GWLP_UI + sizeof(UI*))
875 
876 /// @implemented
877 UI::UI(HWND hWnd) : m_hWnd(hWnd)
878 {
879 }
880 
881 /// @implemented
882 UI::~UI()
883 {
884     delete m_pComp;
885 }
886 
887 /// @implemented
888 HRESULT UI::_Create()
889 {
890     m_pComp = new(cicNoThrow) UIComposition(m_hWnd);
891     if (!m_pComp)
892         return E_OUTOFMEMORY;
893 
894     ::SetWindowLongPtrW(m_hWnd, UI_GWLP_UI, (LONG_PTR)this);
895     return S_OK;
896 }
897 
898 /// @implemented
899 void UI::_Destroy()
900 {
901     m_pComp->OnDestroy();
902     ::SetWindowLongPtrW(m_hWnd, UI_GWLP_UI, 0);
903 }
904 
905 /// @implemented
906 void UI::OnCreate(HWND hWnd)
907 {
908     UI *pUI = (UI*)::GetWindowLongPtrW(hWnd, UI_GWLP_UI);
909     if (pUI)
910         return;
911     pUI = new(cicNoThrow) UI(hWnd);
912     if (pUI)
913         pUI->_Create();
914 }
915 
916 /// @implemented
917 void UI::OnDestroy(HWND hWnd)
918 {
919     UI *pUI = (UI*)::GetWindowLongPtrW(hWnd, UI_GWLP_UI);
920     if (!pUI)
921         return;
922 
923     pUI->_Destroy();
924     delete pUI;
925 }
926 
927 /// @implemented
928 void UI::OnImeSetContext(CicIMCLock& imcLock, WPARAM wParam, LPARAM lParam)
929 {
930     m_pComp->OnImeSetContext(imcLock, m_hWnd, wParam, lParam);
931 }
932 
933 /***********************************************************************/
934 
935 struct CIMEUIWindowHandler
936 {
937     static LRESULT CALLBACK ImeUIMsImeHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
938     static HRESULT CALLBACK ImeUIMsImeMouseHandler(HWND hWnd, WPARAM wParam, LPARAM lParam);
939     static LRESULT CALLBACK ImeUIMsImeModeBiasHandler(HWND hWnd, WPARAM wParam, LPARAM lParam);
940     static LRESULT CALLBACK ImeUIMsImeReconvertRequest(HWND hWnd, WPARAM wParam, LPARAM lParam);
941     static LRESULT CALLBACK ImeUIWndProcWorker(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
942     static HRESULT CALLBACK ImeUIDelayedReconvertFuncCall(HWND hWnd);
943     static HRESULT CALLBACK ImeUIOnLayoutChange(LPARAM lParam);
944     static HRESULT CALLBACK ImeUIPrivateHandler(UINT uMsg, WPARAM wParam, LPARAM lParam);
945     static LRESULT CALLBACK ImeUINotifyHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
946 };
947 
948 /// @implemented
949 HRESULT CALLBACK
950 CIMEUIWindowHandler::ImeUIMsImeMouseHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
951 {
952     if ((BYTE)wParam == 0xFF)
953         return TRUE;
954 
955     CicIMCLock imcLock((HIMC)lParam);
956     if (FAILED(imcLock.m_hr))
957         return imcLock.m_hr;
958 
959     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
960     if (FAILED(imeContext.m_hr))
961         return FALSE;
962 
963     HRESULT hr = E_FAIL;
964     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
965     if (pCicIC)
966     {
967         UINT keys = 0;
968         if (wParam & MK_LBUTTON)
969             keys |= 0x1;
970         if (wParam & MK_SHIFT)
971             keys |= 0x10;
972         if (wParam & MK_RBUTTON)
973             keys |= 0x2;
974         if (wParam & MK_MBUTTON)
975             keys |= 0x780000;
976         else if (wParam & MK_ALT)
977             keys |= 0xFF880000;
978         hr = pCicIC->MsImeMouseHandler(HIWORD(wParam), HIBYTE(LOWORD(wParam)), keys, imcLock);
979     }
980 
981     return hr;
982 }
983 
984 /// @implemented
985 HRESULT CALLBACK CIMEUIWindowHandler::ImeUIOnLayoutChange(LPARAM lParam)
986 {
987     CicIMCLock imcLock((HIMC)lParam);
988     if (FAILED(imcLock.m_hr))
989         return S_OK;
990 
991     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
992     if (FAILED(imeContext.m_hr))
993         return S_OK;
994 
995     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
996     if (pCicIC)
997     {
998         auto pContextOwnerServices = pCicIC->m_pContextOwnerServices;
999         pContextOwnerServices->AddRef();
1000         pContextOwnerServices->OnLayoutChange();
1001         pContextOwnerServices->Release();
1002     }
1003 
1004     return S_OK;
1005 }
1006 
1007 /// @implemented
1008 HRESULT CALLBACK
1009 CIMEUIWindowHandler::ImeUIPrivateHandler(UINT uMsg, WPARAM wParam, LPARAM lParam)
1010 {
1011     CicIMCLock imcLock((HIMC)lParam);
1012     if (FAILED(imcLock.m_hr))
1013         return imcLock.m_hr;
1014 
1015     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
1016     if (FAILED(imeContext.m_hr))
1017         return imeContext.m_hr;
1018 
1019     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
1020     if (pCicIC && wParam == 0x10)
1021         pCicIC->EscbClearDocFeedBuffer(imcLock, TRUE);
1022 
1023     return S_OK;
1024 }
1025 
1026 /// @implemented
1027 LRESULT CALLBACK
1028 CIMEUIWindowHandler::ImeUIMsImeModeBiasHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
1029 {
1030     if (!wParam)
1031         return TRUE;
1032 
1033     CicIMCLock imcLock((HIMC)lParam);
1034     if (FAILED(imcLock.m_hr))
1035         return imcLock.m_hr;
1036 
1037     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
1038     if (FAILED(imeContext.m_hr))
1039         return FALSE;
1040 
1041     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
1042     if (!pCicIC)
1043         return FALSE;
1044 
1045     if (wParam == 1)
1046     {
1047         if (lParam == 0 || lParam == 1 || lParam == 4 || lParam == 0x10000)
1048         {
1049             GUID guid = pCicIC->m_ModeBias.ConvertModeBias((DWORD)lParam);
1050             pCicIC->m_ModeBias.SetModeBias(guid);
1051 
1052             pCicIC->m_dwUnknown7[2] |= 1;
1053             pCicIC->m_pContextOwnerServices->AddRef();
1054             pCicIC->m_pContextOwnerServices->OnAttributeChange(GUID_PROP_MODEBIAS);
1055             pCicIC->m_pContextOwnerServices->Release();
1056             return TRUE;
1057         }
1058     }
1059     else if (wParam == 2)
1060     {
1061         return pCicIC->m_ModeBias.ConvertModeBias(pCicIC->m_ModeBias.m_guid);
1062     }
1063 
1064     return FALSE;
1065 }
1066 
1067 /// @implemented
1068 LRESULT CALLBACK
1069 CIMEUIWindowHandler::ImeUIMsImeReconvertRequest(HWND hWnd, WPARAM wParam, LPARAM lParam)
1070 {
1071     if (wParam == 0x10000000)
1072         return TRUE;
1073 
1074     HIMC hIMC = (HIMC)::GetWindowLongPtrW(hWnd, UI_GWLP_HIMC);
1075     CicIMCLock imcLock(hIMC);
1076     if (FAILED(imcLock.m_hr))
1077         return FALSE;
1078 
1079     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
1080     if (FAILED(imeContext.m_hr))
1081         return FALSE;
1082 
1083     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
1084     TLS *pTLS = TLS::GetTLS();
1085     if (!pCicIC || !pTLS)
1086         return FALSE;
1087 
1088     auto pThreadMgr = pTLS->m_pThreadMgr;
1089     auto pProfile = pTLS->m_pProfile;
1090     if (!pThreadMgr || !pProfile)
1091         return FALSE;
1092 
1093     UINT uCodePage = 0;
1094     pProfile->GetCodePageA(&uCodePage);
1095     pCicIC->SetupReconvertString(imcLock, pThreadMgr, uCodePage, WM_MSIME_RECONVERT, FALSE);
1096     pCicIC->EndReconvertString(imcLock);
1097     return TRUE;
1098 }
1099 
1100 /// @implemented
1101 LRESULT CALLBACK
1102 CIMEUIWindowHandler::ImeUIMsImeHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1103 {
1104     if (uMsg == WM_MSIME_MOUSE)
1105         return ImeUIMsImeMouseHandler(hWnd, wParam, lParam);
1106     if (uMsg == WM_MSIME_MODEBIAS)
1107         return ImeUIMsImeModeBiasHandler(hWnd, wParam, lParam);
1108     if (uMsg == WM_MSIME_RECONVERTREQUEST)
1109         return ImeUIMsImeReconvertRequest(hWnd, wParam, lParam);
1110     if (uMsg == WM_MSIME_SERVICE)
1111     {
1112         TLS *pTLS = TLS::GetTLS();
1113         if (pTLS && pTLS->m_pProfile)
1114         {
1115             LANGID LangID;
1116             pTLS->m_pProfile->GetLangId(&LangID);
1117             if (PRIMARYLANGID(LangID) == LANG_KOREAN)
1118                 return FALSE;
1119         }
1120         return TRUE;
1121     }
1122     return 0;
1123 }
1124 
1125 /// @implemented
1126 HRESULT CALLBACK
1127 CIMEUIWindowHandler::ImeUIDelayedReconvertFuncCall(HWND hWnd)
1128 {
1129     HIMC hIMC = (HIMC)::GetWindowLongPtrW(hWnd, UI_GWLP_HIMC);
1130     CicIMCLock imcLock(hIMC);
1131     if (FAILED(imcLock.m_hr))
1132         return imcLock.m_hr;
1133     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
1134     if (FAILED(imeContext.m_hr))
1135         return imeContext.m_hr;
1136     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
1137     if (pCicIC)
1138         pCicIC->DelayedReconvertFuncCall(imcLock);
1139     return S_OK;
1140 }
1141 
1142 /// @unimplemented
1143 LRESULT CALLBACK
1144 CIMEUIWindowHandler::ImeUINotifyHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1145 {
1146     HIMC hIMC = (HIMC)::GetWindowLongPtrW(hWnd, UI_GWLP_HIMC);
1147     CicIMCLock imcLock(hIMC);
1148     if (FAILED(imcLock.m_hr))
1149         return imcLock.m_hr;
1150     CicIMCCLock<CTFIMECONTEXT> imeContext(imcLock.get().hCtfImeContext);
1151     if (FAILED(imeContext.m_hr))
1152         return imeContext.m_hr;
1153 
1154     CicInputContext *pCicIC = imeContext.get().m_pCicIC;
1155     if (pCicIC)
1156     {
1157         switch (wParam)
1158         {
1159             case IMN_CLOSECANDIDATE:
1160             {
1161                 pCicIC->m_bCandidateOpen = FALSE;
1162                 HWND hImeWnd = ::ImmGetDefaultIMEWnd(NULL);
1163                 if (::IsWindow(hImeWnd))
1164                     ::PostMessage(hImeWnd, WM_IME_NOTIFY, 0x10, (LPARAM)hIMC);
1165                 break;
1166             }
1167             case IMN_OPENCANDIDATE:
1168             {
1169                 pCicIC->m_bCandidateOpen = TRUE;
1170                 pCicIC->ClearPrevCandidatePos();
1171                 break;
1172             }
1173             case IMN_SETCANDIDATEPOS:
1174             {
1175                 //FIXME
1176                 break;
1177             }
1178             case IMN_SETCOMPOSITIONFONT:
1179             {
1180                 //FIXME
1181                 break;
1182             }
1183             case IMN_SETCOMPOSITIONWINDOW:
1184             {
1185                 //FIXME
1186                 break;
1187             }
1188             case 0xF:
1189             {
1190                 CIMEUIWindowHandler::ImeUIOnLayoutChange(lParam);
1191                 break;
1192             }
1193             case 0x10:
1194             {
1195                 CIMEUIWindowHandler::ImeUIPrivateHandler(uMsg, 0x10, lParam);
1196                 break;
1197             }
1198             case 0x13:
1199             {
1200                 CIMEUIWindowHandler::ImeUIOnLayoutChange(lParam);
1201                 break;
1202             }
1203             case 0x14:
1204             {
1205                 //FIXME
1206                 break;
1207             }
1208             case 0x16:
1209             {
1210                 ::SetTimer(hWnd, 2, 100, NULL);
1211                 break;
1212             }
1213             case 0x17:
1214             {
1215                 return (LRESULT)hWnd;
1216             }
1217             case 0x10D:
1218             {
1219                 //FIXME
1220                 break;
1221             }
1222             case 0x10E:
1223                 pCicIC->m_dwQueryPos = 0;
1224                 break;
1225         }
1226     }
1227 
1228     return 0;
1229 }
1230 
1231 /// @implemented
1232 LRESULT CALLBACK
1233 CIMEUIWindowHandler::ImeUIWndProcWorker(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1234 {
1235     TLS *pTLS = TLS::GetTLS();
1236     if (pTLS && (pTLS->m_dwSystemInfoFlags & IME_SYSINFO_WINLOGON))
1237     {
1238         if (uMsg == WM_CREATE)
1239             return -1;
1240         return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
1241     }
1242 
1243     switch (uMsg)
1244     {
1245         case WM_CREATE:
1246         {
1247             UI::OnCreate(hWnd);
1248             break;
1249         }
1250         case WM_DESTROY:
1251         case WM_ENDSESSION:
1252         {
1253             UI::OnDestroy(hWnd);
1254             break;
1255         }
1256         case WM_IME_STARTCOMPOSITION:
1257         case WM_IME_COMPOSITION:
1258         case WM_IME_ENDCOMPOSITION:
1259         case WM_IME_SETCONTEXT:
1260         case WM_IME_NOTIFY:
1261         case WM_IME_SELECT:
1262         case WM_TIMER:
1263         {
1264             HIMC hIMC = (HIMC)GetWindowLongPtrW(hWnd, UI_GWLP_HIMC);
1265             UI* pUI = (UI*)GetWindowLongPtrW(hWnd, UI_GWLP_UI);
1266             CicIMCLock imcLock(hIMC);
1267             switch (uMsg)
1268             {
1269                 case WM_IME_STARTCOMPOSITION:
1270                 {
1271                     pUI->m_pComp->OnImeStartComposition(imcLock, pUI->m_hWnd);
1272                     break;
1273                 }
1274                 case WM_IME_COMPOSITION:
1275                 {
1276                     if (lParam & GCS_COMPSTR)
1277                     {
1278                         pUI->m_pComp->OnImeCompositionUpdate(imcLock);
1279                         ::SetTimer(hWnd, 0, 10, NULL);
1280                         pUI->m_pComp->m_bInComposition = TRUE;
1281                     }
1282                     break;
1283                 }
1284                 case WM_IME_ENDCOMPOSITION:
1285                 {
1286                     ::KillTimer(hWnd, 0);
1287                     pUI->m_pComp->OnImeEndComposition();
1288                     break;
1289                 }
1290                 case WM_IME_SETCONTEXT:
1291                 {
1292                     pUI->OnImeSetContext(imcLock, wParam, lParam);
1293                     ::KillTimer(hWnd, 1);
1294                     ::SetTimer(hWnd, 1, 300, NULL);
1295                     break;
1296                 }
1297                 case WM_TIMER:
1298                 {
1299                     switch (wParam)
1300                     {
1301                         case 0:
1302                             ::KillTimer(hWnd, wParam);
1303                             pUI->m_pComp->m_bInComposition = FALSE;
1304                             pUI->m_pComp->OnImeNotifySetCompositionWindow(imcLock);
1305                             break;
1306                         case 1:
1307                             ::KillTimer(hWnd, wParam);
1308                             pUI->m_pComp->OnImeSetContextAfter(imcLock);
1309                             break;
1310                         case 2:
1311                             ::KillTimer(hWnd, wParam);
1312                             CIMEUIWindowHandler::ImeUIDelayedReconvertFuncCall(hWnd);
1313                             break;
1314                         default:
1315                             break;
1316                     }
1317                     break;
1318                 }
1319                 case WM_IME_NOTIFY:
1320                 case WM_IME_SELECT:
1321                 default:
1322                 {
1323                     pUI->m_pComp->OnPaintTheme(wParam);
1324                     break;
1325                 }
1326             }
1327             break;
1328         }
1329         default:
1330         {
1331             if (IsMsImeMessage(uMsg))
1332                 return CIMEUIWindowHandler::ImeUIMsImeHandler(hWnd, uMsg, wParam, lParam);
1333             return ::DefWindowProcW(hWnd, uMsg, wParam, lParam);
1334         }
1335     }
1336 
1337     return 0;
1338 }
1339 
1340 /***********************************************************************/
1341 
1342 /// @implemented
1343 EXTERN_C LRESULT CALLBACK
1344 UIWndProc(
1345     _In_ HWND hWnd,
1346     _In_ UINT uMsg,
1347     _In_ WPARAM wParam,
1348     _In_ LPARAM lParam)
1349 {
1350     return CIMEUIWindowHandler::ImeUIWndProcWorker(hWnd, uMsg, wParam, lParam);
1351 }
1352 
1353 /***********************************************************************/
1354 
1355 /// @implemented
1356 BOOL RegisterImeClass(VOID)
1357 {
1358     WNDCLASSEXW wcx;
1359 
1360     if (!GetClassInfoExW(g_hInst, L"MSCTFIME UI", &wcx))
1361     {
1362         ZeroMemory(&wcx, sizeof(wcx));
1363         wcx.cbSize          = sizeof(WNDCLASSEXW);
1364         wcx.cbWndExtra      = UI_GWLP_SIZE;
1365         wcx.hIcon           = LoadIconW(0, (LPCWSTR)IDC_ARROW);
1366         wcx.hInstance       = g_hInst;
1367         wcx.hCursor         = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
1368         wcx.hbrBackground   = (HBRUSH)GetStockObject(NULL_BRUSH);
1369         wcx.style           = CS_IME | CS_GLOBALCLASS;
1370         wcx.lpfnWndProc     = UIWndProc;
1371         wcx.lpszClassName   = L"MSCTFIME UI";
1372         if (!RegisterClassExW(&wcx))
1373             return FALSE;
1374     }
1375 
1376     if (!GetClassInfoExW(g_hInst, L"MSCTFIME Composition", &wcx))
1377     {
1378         ZeroMemory(&wcx, sizeof(wcx));
1379         wcx.cbSize          = sizeof(WNDCLASSEXW);
1380         wcx.cbWndExtra      = UICOMP_GWLP_SIZE;
1381         wcx.hIcon           = NULL;
1382         wcx.hInstance       = g_hInst;
1383         wcx.hCursor         = LoadCursorW(NULL, (LPCWSTR)IDC_IBEAM);
1384         wcx.hbrBackground   = (HBRUSH)GetStockObject(NULL_BRUSH);
1385         wcx.style           = CS_IME | CS_HREDRAW | CS_VREDRAW;
1386         wcx.lpfnWndProc     = UIComposition::CompWndProc;
1387         wcx.lpszClassName   = L"MSCTFIME Composition";
1388         if (!RegisterClassExW(&wcx))
1389             return FALSE;
1390     }
1391 
1392     return TRUE;
1393 }
1394 
1395 /// @implemented
1396 VOID UnregisterImeClass(VOID)
1397 {
1398     WNDCLASSEXW wcx;
1399 
1400     GetClassInfoExW(g_hInst, L"MSCTFIME UI", &wcx);
1401     UnregisterClassW(L"MSCTFIME UI", g_hInst);
1402     DestroyIcon(wcx.hIcon);
1403     DestroyIcon(wcx.hIconSm);
1404 
1405     GetClassInfoExW(g_hInst, L"MSCTFIME Composition", &wcx);
1406     UnregisterClassW(L"MSCTFIME Composition", g_hInst);
1407     DestroyIcon(wcx.hIcon);
1408     DestroyIcon(wcx.hIconSm);
1409 }
1410