1 /*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing IME Soft Keyboard
5 * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6 */
7
8 #include "precomp.h"
9 #include "resource.h"
10
11 WINE_DEFAULT_DEBUG_CHANNEL(imm);
12
13 /*
14 * There are two types of IME Soft Keyboard: Type T1 and Type C1.
15 * T1 is created for Traditional Chinese but not limitted to it.
16 * C1 is created for Simplified Chinese but not limitted to it.
17 * Type C1 has SHIFT status while Type T1 hasn't.
18 */
19
20 static UINT guScanCode[256]; /* Mapping: virtual key --> scan code */
21 static POINT gptRaiseEdge; /* Border + Edge metrics */
22 static BOOL g_bWantSoftKBDMetrics = TRUE;
23
24 static inline BOOL
Imm32PtInRect(_In_ const POINT * ppt,_In_ LONG x,_In_ LONG y,_In_ LONG cx,_In_ LONG cy)25 Imm32PtInRect(
26 _In_ const POINT *ppt,
27 _In_ LONG x,
28 _In_ LONG y,
29 _In_ LONG cx,
30 _In_ LONG cy)
31 {
32 return (x <= ppt->x) && (ppt->x < x + cx) && (y <= ppt->y) && (ppt->y < y + cy);
33 }
34
35 static void
Imm32DrawBitmap(_In_ HDC hdc,_In_ INT x,_In_ INT y,_In_ INT width,_In_ INT height,_In_ INT nBitmapID)36 Imm32DrawBitmap(
37 _In_ HDC hdc,
38 _In_ INT x,
39 _In_ INT y,
40 _In_ INT width,
41 _In_ INT height,
42 _In_ INT nBitmapID)
43 {
44 HBITMAP hBitmap = LoadBitmapW(ghImm32Inst, MAKEINTRESOURCEW(nBitmapID));
45 HDC hMemDC = CreateCompatibleDC(hdc);
46 HGDIOBJ hbmOld = SelectObject(hMemDC, hBitmap);
47 BitBlt(hdc, x, y, width, height, hMemDC, 0, 0, SRCCOPY);
48 DeleteObject(SelectObject(hMemDC, hbmOld));
49 DeleteDC(hMemDC);
50 }
51
52 static inline INT
Imm32Clamp(_In_ INT x,_In_ INT xMin,_In_ INT xMax)53 Imm32Clamp(
54 _In_ INT x,
55 _In_ INT xMin,
56 _In_ INT xMax)
57 {
58 if (x < xMin)
59 return xMin;
60 if (x > xMax)
61 return xMax;
62 return x;
63 }
64
65 static VOID
Imm32GetAllMonitorSize(_Out_ LPRECT prcWork)66 Imm32GetAllMonitorSize(
67 _Out_ LPRECT prcWork)
68 {
69 if (GetSystemMetrics(SM_CMONITORS) == 1)
70 {
71 SystemParametersInfoW(SPI_GETWORKAREA, 0, prcWork, 0);
72 return;
73 }
74
75 prcWork->left = GetSystemMetrics(SM_XVIRTUALSCREEN);
76 prcWork->top = GetSystemMetrics(SM_YVIRTUALSCREEN);
77 prcWork->right = prcWork->left + GetSystemMetrics(SM_CXVIRTUALSCREEN);
78 prcWork->bottom = prcWork->top + GetSystemMetrics(SM_CYVIRTUALSCREEN);
79 }
80
81 static BOOL
Imm32GetNearestWorkArea(_In_opt_ HWND hwnd,_Out_ LPRECT prcWork)82 Imm32GetNearestWorkArea(
83 _In_opt_ HWND hwnd,
84 _Out_ LPRECT prcWork)
85 {
86 HMONITOR hMonitor;
87 MONITORINFO mi;
88
89 if (GetSystemMetrics(SM_CMONITORS) == 1)
90 {
91 Imm32GetAllMonitorSize(prcWork);
92 return TRUE;
93 }
94
95 hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
96 if (!hMonitor)
97 {
98 ERR("hwnd: %p\n", hwnd);
99 return FALSE;
100 }
101
102 ZeroMemory(&mi, sizeof(mi));
103 mi.cbSize = sizeof(mi);
104 GetMonitorInfoW(hMonitor, &mi);
105 *prcWork = mi.rcWork;
106 return TRUE;
107 }
108
109 /*****************************************************************************
110 * IME Soft Keyboard Type T1
111 */
112
113 #define T1_CLASSNAMEW L"SoftKBDClsT1"
114
115 #undef DEFINE_T1K
116 #define DEFINE_T1K(t1k_code, virtual_key_code, t1k_code_name, virtual_key_name, is_special) \
117 t1k_code_name = t1k_code,
118
119 /* Define T1 internal codes (T1K_...) */
120 typedef enum T1KEY
121 {
122 #include "t1keys.h"
123 } T1KEY;
124
125 #undef DEFINE_T1K
126 #define DEFINE_T1K(t1k_code, virtual_key_code, t1k_code_name, virtual_key_name, is_special) \
127 virtual_key_code,
128
129 #define T1K_MAX 60
130
131 /* Mapping: T1K --> Virtual Key */
132 const BYTE gT1K2VK[T1K_MAX] =
133 {
134 #include "t1keys.h"
135 };
136
137 typedef struct T1WINDOW
138 {
139 INT cxDefWidth; /* Regular key width */
140 INT cxWidth47; /* [BackSpace] width */
141 INT cxWidth48; /* [Tab] width */
142 INT cxWidth49; /* [Caps] width */
143 INT cxWidth50; /* [Enter] width */
144 INT cxWidth51or52; /* [Shift] width */
145 INT cxWidth53or54; /* [Ctrl] width */
146 INT cxWidth55or56; /* [Alt] width */
147 INT cxWidth57; /* [Esc] width */
148 INT cxWidth58; /* [Space] width */
149 INT cyDefHeight; /* Regular key height */
150 INT cyHeight50; /* [Enter] height */
151 POINT KeyPos[T1K_MAX]; /* T1K --> POINT */
152 WCHAR chKeyChar[48]; /* T1K --> WCHAR */
153 HBITMAP hbmKeyboard; /* The keyboard image */
154 DWORD CharSet; /* LOGFONT.lfCharSet */
155 UINT PressedKey; /* Currently pressed key */
156 POINT pt0, pt1; /* The soft keyboard window position */
157 LPARAM KeyboardSubType; /* See IMC_GETSOFTKBDSUBTYPE/IMC_SETSOFTKBDSUBTYPE */
158 } T1WINDOW, *PT1WINDOW;
159
160 #define T1_KEYPOS(iKey) pT1->KeyPos[iKey]
161
162 static LOGFONTW g_T1LogFont;
163
164 static void
T1_GetTextMetric(_Out_ LPTEXTMETRICW ptm)165 T1_GetTextMetric(_Out_ LPTEXTMETRICW ptm)
166 {
167 WCHAR wch;
168 SIZE textSize;
169 HFONT hFont;
170 HGDIOBJ hFontOld;
171 HDC hDC;
172 #ifndef NDEBUG
173 WCHAR szFace[LF_FACESIZE];
174 #endif
175
176 ZeroMemory(&g_T1LogFont, sizeof(g_T1LogFont));
177 g_T1LogFont.lfHeight = -12;
178 g_T1LogFont.lfWeight = FW_NORMAL;
179 g_T1LogFont.lfCharSet = CHINESEBIG5_CHARSET;
180 #ifdef NO_HACK /* FIXME: We lack proper Asian fonts! */
181 g_T1LogFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
182 g_T1LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
183 g_T1LogFont.lfQuality = PROOF_QUALITY;
184 g_T1LogFont.lfPitchAndFamily = FF_MODERN | FIXED_PITCH;
185 #else
186 StringCchCopyW(g_T1LogFont.lfFaceName, _countof(g_T1LogFont.lfFaceName), L"MS Shell Dlg");
187 #endif
188 hFont = CreateFontIndirectW(&g_T1LogFont);
189
190 hDC = GetDC(NULL);
191 hFontOld = SelectObject(hDC, hFont);
192
193 #ifndef NDEBUG
194 GetTextFaceW(hDC, _countof(szFace), szFace);
195 TRACE("szFace: %s\n", debugstr_w(szFace));
196 #endif
197
198 GetTextMetricsW(hDC, ptm);
199
200 wch = 0x4E11; /* U+4E11: 丑 */
201 if (GetTextExtentPoint32W(hDC, &wch, 1, &textSize) && textSize.cx > ptm->tmMaxCharWidth)
202 ptm->tmMaxCharWidth = textSize.cx;
203
204 DeleteObject(SelectObject(hDC, hFontOld));
205 ReleaseDC(NULL, hDC);
206 }
207
208 static void
T1_InitButtonPos(_Out_ PT1WINDOW pT1)209 T1_InitButtonPos(_Out_ PT1WINDOW pT1)
210 {
211 TEXTMETRICW tm;
212 LONG cxLarge, cyLarge;
213 LONG xKey1, yKey1, xKey2, yKey2, xKey3, yKey3;
214 LONG yKey4, xKey4, xKey5, yKey5, xKey6, xKey7;
215 INT iKey;
216
217 T1_GetTextMetric(&tm);
218
219 cxLarge = (3 * tm.tmMaxCharWidth + 18) / 2;
220 cyLarge = tm.tmHeight + 8;
221
222 /* key widths and heights */
223 pT1->cxDefWidth = (2 * tm.tmMaxCharWidth + 12) / 2;
224 pT1->cxWidth47 = (2 * tm.tmMaxCharWidth + 12) / 2 + 1;
225 pT1->cxWidth49 = (4 * tm.tmMaxCharWidth + 24) / 2 + 3;
226 pT1->cxWidth51or52 = (5 * tm.tmMaxCharWidth + 30) / 2 + 5;
227 pT1->cxWidth58 = 4 * (3 * tm.tmMaxCharWidth + 18) / 2 + 15;
228 pT1->cxWidth48 = pT1->cxWidth50 = cxLarge + 2;
229 pT1->cxWidth53or54 = pT1->cxWidth55or56 = cxLarge + 2;
230 pT1->cyHeight50 = 2 * (tm.tmHeight + 8) + 3;
231 pT1->cxWidth57 = cxLarge + 1;
232 pT1->cyDefHeight = cyLarge;
233
234 /* First row */
235 xKey1 = gptRaiseEdge.x + 3;
236 yKey1 = gptRaiseEdge.y + 3;
237 for (iKey = 0; iKey < T1K_Q; ++iKey)
238 {
239 T1_KEYPOS(iKey).x = xKey1;
240 T1_KEYPOS(iKey).y = yKey1;
241 xKey1 += pT1->cxDefWidth + 3;
242 }
243 T1_KEYPOS(T1K_BACKSPACE).y = yKey1;
244 T1_KEYPOS(T1K_BACKSPACE).x = xKey1;
245
246 /* 2nd row */
247 xKey2 = 3 + gptRaiseEdge.x + pT1->cxWidth48 + 3;
248 yKey2 = 3 + yKey1 + cyLarge;
249 T1_KEYPOS(T1K_TAB).x = gptRaiseEdge.x + 3;
250 T1_KEYPOS(T1K_TAB).y = yKey2;
251 for (iKey = T1K_Q; iKey < T1K_A; ++iKey)
252 {
253 T1_KEYPOS(iKey).x = xKey2;
254 T1_KEYPOS(iKey).y = yKey2;
255 xKey2 += pT1->cxDefWidth + 3;
256 }
257 T1_KEYPOS(T1K_ENTER).x = xKey2;
258 T1_KEYPOS(T1K_ENTER).y = yKey2;
259
260 /* 3rd row */
261 xKey3 = gptRaiseEdge.x + 3 + pT1->cxWidth49 + 3;
262 yKey3 = yKey2 + cyLarge + 3;
263 T1_KEYPOS(T1K_CAPS).x = gptRaiseEdge.x + 3;
264 T1_KEYPOS(T1K_CAPS).y = yKey3;
265 for (iKey = T1K_A; iKey < T1K_Z; ++iKey)
266 {
267 T1_KEYPOS(iKey).x = xKey3;
268 T1_KEYPOS(iKey).y = yKey3;
269 xKey3 += pT1->cxDefWidth + 3;
270 }
271
272 /* 4th row */
273 xKey4 = gptRaiseEdge.x + pT1->cxWidth51or52 + 3 + 3;
274 yKey4 = yKey3 + cyLarge + 3;
275 T1_KEYPOS(T1K_L_SHIFT).x = gptRaiseEdge.x + 3;
276 T1_KEYPOS(T1K_L_SHIFT).y = yKey4;
277 for (iKey = T1K_Z; iKey < T1K_BACKSPACE; ++iKey)
278 {
279 T1_KEYPOS(iKey).x = xKey4;
280 T1_KEYPOS(iKey).y = yKey4;
281 xKey4 += pT1->cxDefWidth + 3;
282 }
283 T1_KEYPOS(T1K_R_SHIFT).x = xKey4;
284 T1_KEYPOS(T1K_R_SHIFT).y = yKey4;
285
286 /* 5th row */
287 xKey5 = gptRaiseEdge.x + 3 + pT1->cxWidth53or54 + 3;
288 T1_KEYPOS(T1K_L_CTRL).x = gptRaiseEdge.x + 3;
289 T1_KEYPOS(T1K_ESCAPE).x = xKey5;
290 T1_KEYPOS(T1K_L_ALT).x = xKey5 + pT1->cxWidth57 + 3;
291
292 yKey5 = yKey4 + cyLarge + 3;
293 T1_KEYPOS(T1K_L_CTRL).y = T1_KEYPOS(T1K_ESCAPE).y = T1_KEYPOS(T1K_L_ALT).y = yKey5;
294 T1_KEYPOS(T1K_R_ALT).y = T1_KEYPOS(T1K_SPACE).y = T1_KEYPOS(T1K_R_CTRL).y = yKey5;
295
296 xKey6 = xKey5 + pT1->cxWidth57 + 3 + pT1->cxWidth55or56 + 3;
297 T1_KEYPOS(T1K_SPACE).x = xKey6;
298
299 xKey7 = xKey6 + pT1->cxWidth58 + 3;
300 T1_KEYPOS(T1K_R_ALT).x = xKey7;
301 T1_KEYPOS(T1K_R_CTRL).x = xKey7 + pT1->cxWidth57 + pT1->cxWidth55or56 + 6;
302 }
303
304 /* Draw keyboard key edge */
305 static void
T1_DrawConvexRect(_In_ HDC hDC,_In_ INT x,_In_ INT y,_In_ INT width,_In_ INT height)306 T1_DrawConvexRect(
307 _In_ HDC hDC,
308 _In_ INT x,
309 _In_ INT y,
310 _In_ INT width,
311 _In_ INT height)
312 {
313 HGDIOBJ hBlackPen = GetStockObject(BLACK_PEN);
314 HGDIOBJ hLtGrayBrush = GetStockObject(LTGRAY_BRUSH);
315 HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH);
316 INT dx = width + 4, dy = height + 4;
317 INT x0 = x - 2, y0 = y + height + 2;
318
319 /* Face */
320 SelectObject(hDC, hBlackPen);
321 SelectObject(hDC, hLtGrayBrush);
322 Rectangle(hDC, x0, y - 2, x0 + dx, y0);
323
324 /* Rounded corners */
325 PatBlt(hDC, x0, y - 2, 1, 1, PATCOPY);
326 PatBlt(hDC, x0, y0, 1, -1, PATCOPY);
327 PatBlt(hDC, x0 + dx, y - 2, -1, 1, PATCOPY);
328 PatBlt(hDC, x0 + dx, y0, -1, -1, PATCOPY);
329
330 /* Light edge */
331 PatBlt(hDC, x0 + 1, y + dy - 3, 1, 2 - dy, WHITENESS);
332 PatBlt(hDC, x0 + 1, y - 1, dx - 2, 1, WHITENESS);
333
334 /* Dark edge */
335 SelectObject(hDC, hGrayBrush);
336 PatBlt(hDC, x0 + 1, y + dy - 3, dx - 2, -1, PATCOPY);
337 PatBlt(hDC, x0 + dx - 1, y + dy - 3, -1, 2 - dy, PATCOPY);
338 }
339
340 static void
T1_DrawLabels(_In_ HDC hDC,_In_ const T1WINDOW * pT1,_In_ LPCWSTR pszBmpName)341 T1_DrawLabels(
342 _In_ HDC hDC,
343 _In_ const T1WINDOW *pT1,
344 _In_ LPCWSTR pszBmpName)
345 {
346 HBITMAP hBitmap = LoadBitmapW(ghImm32Inst, pszBmpName);
347 HDC hdcMem = CreateCompatibleDC(hDC);
348 HGDIOBJ hbmOld = SelectObject(hdcMem, hBitmap);
349 INT iKey;
350 for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey)
351 {
352 const POINT *ppt = &T1_KEYPOS(iKey);
353 BitBlt(hDC, ppt->x, ppt->y, 8, 8, hdcMem, iKey * 8, 0, SRCCOPY);
354 }
355 SelectObject(hdcMem, hbmOld);
356 DeleteDC(hdcMem);
357 DeleteObject(hBitmap);
358 }
359
360 static void
T1_InitBitmap(_In_ HWND hWnd,_Inout_ PT1WINDOW pT1)361 T1_InitBitmap(
362 _In_ HWND hWnd,
363 _Inout_ PT1WINDOW pT1)
364 {
365 HDC hDC, hMemDC;
366 HGDIOBJ hNullPen = GetStockObject(NULL_PEN), hbrLtGray = GetStockObject(LTGRAY_BRUSH);
367 RECT rc;
368 INT iKey;
369
370 /* Create the bitmap */
371 hDC = GetDC(hWnd);
372 hMemDC = CreateCompatibleDC(hDC);
373 GetClientRect(hWnd, &rc);
374 pT1->hbmKeyboard = CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - rc.top);
375 ReleaseDC(hWnd, hDC);
376
377 /* Draw keyboard face */
378 SelectObject(hMemDC, pT1->hbmKeyboard);
379 SelectObject(hMemDC, hNullPen);
380 SelectObject(hMemDC, hbrLtGray);
381 Rectangle(hMemDC, rc.left, rc.top, rc.right + 1, rc.bottom + 1);
382 DrawEdge(hMemDC, &rc, EDGE_RAISED, BF_RECT);
383
384 /* 53 --> Left [Ctrl] */
385 T1_DrawConvexRect(hMemDC,
386 T1_KEYPOS(T1K_L_CTRL).x, T1_KEYPOS(T1K_L_CTRL).y,
387 pT1->cxWidth53or54, pT1->cyDefHeight);
388 Imm32DrawBitmap(hMemDC,
389 pT1->cxWidth53or54 / 2 + T1_KEYPOS(T1K_L_CTRL).x - 8,
390 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_L_CTRL).y - 4,
391 16, 9, IDB_T1_CTRL);
392
393 /* 54 --> Right [Ctrl] */
394 T1_DrawConvexRect(hMemDC,
395 T1_KEYPOS(T1K_R_CTRL).x, T1_KEYPOS(T1K_R_CTRL).y,
396 pT1->cxWidth53or54, pT1->cyDefHeight);
397 Imm32DrawBitmap(hMemDC,
398 pT1->cxWidth53or54 / 2 + T1_KEYPOS(T1K_R_CTRL).x - 8,
399 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_R_CTRL).y - 4,
400 16, 9, IDB_T1_CTRL);
401
402 /* 57 --> [Esc] */
403 T1_DrawConvexRect(hMemDC,
404 T1_KEYPOS(T1K_ESCAPE).x, T1_KEYPOS(T1K_ESCAPE).y,
405 pT1->cxWidth57, pT1->cyDefHeight);
406 Imm32DrawBitmap(hMemDC,
407 pT1->cxWidth57 / 2 + T1_KEYPOS(T1K_ESCAPE).x - 9,
408 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_ESCAPE).y - 4,
409 18, 9, IDB_T1_ESCAPE);
410
411 /* 55 --> Left [Alt] */
412 T1_DrawConvexRect(hMemDC,
413 T1_KEYPOS(T1K_L_ALT).x, T1_KEYPOS(T1K_L_ALT).y,
414 pT1->cxWidth55or56, pT1->cyDefHeight);
415 Imm32DrawBitmap(hMemDC,
416 pT1->cxWidth55or56 / 2 + T1_KEYPOS(T1K_L_ALT).x - 8,
417 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_L_ALT).y - 4,
418 16, 9, IDB_T1_ALT);
419
420 /* 56 --> Right [Alt] */
421 T1_DrawConvexRect(hMemDC,
422 T1_KEYPOS(T1K_R_ALT).x, T1_KEYPOS(T1K_R_ALT).y,
423 pT1->cxWidth55or56, pT1->cyDefHeight);
424 Imm32DrawBitmap(hMemDC,
425 pT1->cxWidth55or56 / 2 + T1_KEYPOS(T1K_R_ALT).x - 8,
426 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_R_ALT).y - 4,
427 16, 9, IDB_T1_ALT);
428
429 /* 58 --> [Space] */
430 T1_DrawConvexRect(hMemDC,
431 T1_KEYPOS(T1K_SPACE).x, T1_KEYPOS(T1K_SPACE).y,
432 pT1->cxWidth58, pT1->cyDefHeight);
433
434 /* 51 --> Left [Shift] */
435 T1_DrawConvexRect(hMemDC,
436 T1_KEYPOS(T1K_L_SHIFT).x, T1_KEYPOS(T1K_L_SHIFT).y,
437 pT1->cxWidth51or52, pT1->cyDefHeight);
438 Imm32DrawBitmap(hMemDC,
439 pT1->cxWidth51or52 / 2 + T1_KEYPOS(T1K_L_SHIFT).x - 11,
440 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_L_SHIFT).y - 4,
441 23, 9, IDB_T1_SHIFT);
442
443 /* 52 --> Right [Shift] */
444 T1_DrawConvexRect(hMemDC,
445 T1_KEYPOS(T1K_R_SHIFT).x, T1_KEYPOS(T1K_R_SHIFT).y,
446 pT1->cxWidth51or52, pT1->cyDefHeight);
447 Imm32DrawBitmap(hMemDC,
448 pT1->cxWidth51or52 / 2 + T1_KEYPOS(T1K_R_SHIFT).x - 11,
449 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_R_SHIFT).y - 4,
450 23, 9, IDB_T1_SHIFT);
451
452 /* 49 --> [Caps] */
453 T1_DrawConvexRect(hMemDC,
454 T1_KEYPOS(T1K_CAPS).x, T1_KEYPOS(T1K_CAPS).y,
455 pT1->cxWidth49, pT1->cyDefHeight);
456 Imm32DrawBitmap(hMemDC,
457 pT1->cxWidth49 / 2 + T1_KEYPOS(T1K_CAPS).x - 11,
458 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_CAPS).y - 4,
459 22, 9, IDB_T1_CAPS);
460
461 /* 48 --> [Tab] */
462 T1_DrawConvexRect(hMemDC,
463 T1_KEYPOS(T1K_TAB).x, T1_KEYPOS(T1K_TAB).y,
464 pT1->cxWidth48, pT1->cyDefHeight);
465 Imm32DrawBitmap(hMemDC,
466 pT1->cxWidth48 / 2 + T1_KEYPOS(T1K_TAB).x - 8,
467 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_TAB).y - 4,
468 16, 9, IDB_T1_TAB);
469
470 /* 50 --> [Enter] */
471 T1_DrawConvexRect(hMemDC,
472 T1_KEYPOS(T1K_ENTER).x, T1_KEYPOS(T1K_ENTER).y,
473 pT1->cxWidth50, pT1->cyHeight50);
474 Imm32DrawBitmap(hMemDC,
475 pT1->cxWidth50 / 2 + T1_KEYPOS(T1K_ENTER).x - 13,
476 pT1->cyHeight50 / 2 + T1_KEYPOS(T1K_ENTER).y - 4,
477 26, 9, IDB_T1_ENTER);
478
479 /* 47 --> [BackSpace] */
480 T1_DrawConvexRect(hMemDC,
481 T1_KEYPOS(T1K_BACKSPACE).x, T1_KEYPOS(T1K_BACKSPACE).y,
482 pT1->cxWidth47, pT1->cyDefHeight);
483 Imm32DrawBitmap(hMemDC,
484 pT1->cxWidth47 / 2 + T1_KEYPOS(T1K_BACKSPACE).x - 8,
485 pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_BACKSPACE).y - 4,
486 16, 9, IDB_T1_BACKSPACE);
487
488 /* Regular keys */
489 for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey)
490 {
491 LPPOINT ppt = &T1_KEYPOS(iKey);
492 T1_DrawConvexRect(hMemDC, ppt->x, ppt->y, pT1->cxDefWidth, pT1->cyDefHeight);
493 }
494
495 T1_DrawLabels(hMemDC, pT1, MAKEINTRESOURCEW(IDB_T1_CHARS));
496 DeleteDC(hMemDC);
497 }
498
499 static INT
T1_OnCreate(_In_ HWND hWnd)500 T1_OnCreate(
501 _In_ HWND hWnd)
502 {
503 PT1WINDOW pT1;
504 HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(T1WINDOW));
505 if (!hGlobal)
506 return -1;
507
508 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
509 if (!pT1)
510 {
511 GlobalFree(hGlobal);
512 return -1;
513 }
514
515 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)hGlobal);
516 pT1->pt1.x = pT1->pt1.y = -1;
517 pT1->PressedKey = T1K_NONE;
518 pT1->CharSet = CHINESEBIG5_CHARSET;
519
520 T1_InitButtonPos(pT1);
521 T1_InitBitmap(hWnd, pT1);
522 GlobalUnlock(hGlobal);
523
524 return 0;
525 }
526
527 static void
T1_DrawDragBorder(_In_ HWND hWnd,_In_ const POINT * ppt1,_In_ const POINT * ppt2)528 T1_DrawDragBorder(
529 _In_ HWND hWnd,
530 _In_ const POINT *ppt1,
531 _In_ const POINT *ppt2)
532 {
533 INT cxBorder = GetSystemMetrics(SM_CXBORDER), cyBorder = GetSystemMetrics(SM_CYBORDER);
534 INT x = ppt1->x - ppt2->x, y = ppt1->y - ppt2->y;
535 HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH);
536 RECT rc;
537 HDC hDisplayDC;
538
539 GetWindowRect(hWnd, &rc);
540 hDisplayDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
541 SelectObject(hDisplayDC, hGrayBrush);
542 PatBlt(hDisplayDC, x, y, rc.right - rc.left - cxBorder, cyBorder, PATINVERT);
543 PatBlt(hDisplayDC, x, cyBorder + y, cxBorder, rc.bottom - rc.top - cyBorder, PATINVERT);
544 PatBlt(hDisplayDC, x + cxBorder, y + rc.bottom - rc.top, rc.right - rc.left - cxBorder, -cyBorder, PATINVERT);
545 PatBlt(hDisplayDC, x + rc.right - rc.left, y, -cxBorder, rc.bottom - rc.top - cyBorder, PATINVERT);
546 DeleteDC(hDisplayDC);
547 }
548
549 static void
T1_OnDestroy(_In_ HWND hWnd)550 T1_OnDestroy(
551 _In_ HWND hWnd)
552 {
553 HGLOBAL hGlobal;
554 PT1WINDOW pT1;
555 HWND hwndOwner;
556
557 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
558 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
559 if (!hGlobal || !pT1)
560 return;
561
562 if (pT1->pt1.x != -1 && pT1->pt1.y != -1)
563 T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1);
564
565 DeleteObject(pT1->hbmKeyboard);
566 GlobalUnlock(hGlobal);
567 GlobalFree(hGlobal);
568
569 hwndOwner = GetWindow(hWnd, GW_OWNER);
570 if (hwndOwner)
571 SendMessageW(hwndOwner, WM_IME_NOTIFY, IMN_SOFTKBDDESTROYED, 0);
572 }
573
574 static void
T1_InvertButton(_In_ HWND hWnd,_In_ HDC hDC,_In_ const T1WINDOW * pT1,_In_ UINT iPressed)575 T1_InvertButton(
576 _In_ HWND hWnd,
577 _In_ HDC hDC,
578 _In_ const T1WINDOW *pT1,
579 _In_ UINT iPressed)
580 {
581 INT cxWidth = pT1->cxDefWidth, cyHeight = pT1->cyDefHeight;
582 HDC hChoiceDC;
583
584 if (iPressed >= T1K_NONE)
585 return;
586
587 if (hDC)
588 hChoiceDC = hDC;
589 else
590 hChoiceDC = GetDC(hWnd);
591
592 if (iPressed >= T1K_BACKSPACE)
593 {
594 switch (iPressed)
595 {
596 case T1K_BACKSPACE:
597 cxWidth = pT1->cxWidth47;
598 break;
599 case T1K_TAB:
600 cxWidth = pT1->cxWidth48;
601 break;
602 case T1K_ENTER:
603 pT1 = pT1;
604 cxWidth = pT1->cxWidth50;
605 cyHeight = pT1->cyHeight50;
606 break;
607 case T1K_ESCAPE:
608 cxWidth = pT1->cxWidth57;
609 break;
610 case T1K_SPACE:
611 cxWidth = pT1->cxWidth58;
612 break;
613 default:
614 cxWidth = 0;
615 MessageBeep(0xFFFFFFFF);
616 break;
617 }
618 }
619
620 if (cxWidth > 0)
621 {
622 PatBlt(hChoiceDC,
623 T1_KEYPOS(iPressed).x - 1, T1_KEYPOS(iPressed).y - 1,
624 cxWidth + 2, cyHeight + 2,
625 DSTINVERT);
626 }
627
628 if (!hDC)
629 ReleaseDC(hWnd, hChoiceDC);
630 }
631
632 static void
T1_OnDraw(_In_ HDC hDC,_In_ HWND hWnd)633 T1_OnDraw(
634 _In_ HDC hDC,
635 _In_ HWND hWnd)
636 {
637 HGLOBAL hGlobal;
638 PT1WINDOW pT1;
639 HDC hMemDC;
640 RECT rc;
641
642 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
643 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
644 if (!hGlobal || !pT1)
645 return;
646
647 hMemDC = CreateCompatibleDC(hDC);
648 SelectObject(hMemDC, pT1->hbmKeyboard);
649 GetClientRect(hWnd, &rc);
650 BitBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 0, 0, SRCCOPY);
651 DeleteDC(hMemDC);
652
653 if (pT1->PressedKey < T1K_NONE)
654 T1_InvertButton(hWnd, hDC, pT1, pT1->PressedKey);
655
656 GlobalUnlock(hGlobal);
657 }
658
659 static UINT
T1_HitTest(_In_ const T1WINDOW * pT1,_In_ const POINT * ppt)660 T1_HitTest(
661 _In_ const T1WINDOW *pT1,
662 _In_ const POINT *ppt)
663 {
664 INT iKey;
665 for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey)
666 {
667 const POINT *pptKey = &T1_KEYPOS(iKey);
668 if (Imm32PtInRect(ppt, pptKey->x, pptKey->y, pT1->cxDefWidth, pT1->cyDefHeight))
669 return iKey;
670 }
671
672 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_BACKSPACE).x, T1_KEYPOS(T1K_BACKSPACE).y, pT1->cxWidth47, pT1->cyDefHeight))
673 return T1K_BACKSPACE;
674
675 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_TAB).x, T1_KEYPOS(T1K_TAB).y, pT1->cxWidth48, pT1->cyDefHeight))
676 return T1K_TAB;
677
678 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_CAPS).x, T1_KEYPOS(T1K_CAPS).y, pT1->cxWidth49, pT1->cyDefHeight))
679 return T1K_CAPS;
680
681 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_ENTER).x, T1_KEYPOS(T1K_ENTER).y, pT1->cxWidth50, pT1->cyHeight50))
682 return T1K_ENTER;
683
684 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_L_SHIFT).x, T1_KEYPOS(T1K_L_SHIFT).y, pT1->cxWidth51or52, pT1->cyDefHeight) ||
685 Imm32PtInRect(ppt, T1_KEYPOS(T1K_R_SHIFT).x, T1_KEYPOS(T1K_R_SHIFT).y, pT1->cxWidth51or52, pT1->cyDefHeight))
686 {
687 return T1K_L_SHIFT;
688 }
689
690 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_L_CTRL).x, T1_KEYPOS(T1K_L_CTRL).y, pT1->cxWidth53or54, pT1->cyDefHeight) ||
691 Imm32PtInRect(ppt, T1_KEYPOS(T1K_R_CTRL).x, T1_KEYPOS(T1K_R_CTRL).y, pT1->cxWidth53or54, pT1->cyDefHeight))
692 {
693 return T1K_L_CTRL;
694 }
695
696 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_L_ALT).x, T1_KEYPOS(T1K_L_ALT).y, pT1->cxWidth55or56, pT1->cyDefHeight) ||
697 Imm32PtInRect(ppt, T1_KEYPOS(T1K_R_ALT).x, T1_KEYPOS(T1K_R_ALT).y, pT1->cxWidth55or56, pT1->cyDefHeight))
698 {
699 return T1K_L_ALT;
700 }
701
702 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_ESCAPE).x, T1_KEYPOS(T1K_ESCAPE).y, pT1->cxWidth57, pT1->cyDefHeight))
703 return T1K_ESCAPE;
704
705 if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_SPACE).x, T1_KEYPOS(T1K_SPACE).y, pT1->cxWidth58, pT1->cyDefHeight))
706 return T1K_SPACE;
707
708 return T1K_NONE;
709 }
710
711 static BOOL
T1_IsValidButton(_In_ UINT iKey,_In_ const T1WINDOW * pT1)712 T1_IsValidButton(
713 _In_ UINT iKey,
714 _In_ const T1WINDOW *pT1)
715 {
716 if (iKey < T1K_BACKSPACE)
717 return !!pT1->chKeyChar[iKey];
718 return iKey <= T1K_TAB || iKey == T1K_ENTER || (T1K_ESCAPE <= iKey && iKey <= T1K_SPACE);
719 }
720
721 /**
722 * NOTE: The window that has WS_DISABLED style doesn't receive some mouse messages.
723 * Use WM_SETCURSOR handling to detect mouse events.
724 */
725 static BOOL
T1_OnSetCursor(_In_ HWND hWnd,_In_ LPARAM lParam)726 T1_OnSetCursor(
727 _In_ HWND hWnd,
728 _In_ LPARAM lParam)
729 {
730 HGLOBAL hGlobal;
731 PT1WINDOW pT1;
732 HCURSOR hCursor;
733 UINT iPressed, iKey;
734 RECT rc, rcWork;
735
736 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
737 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
738 if (!hGlobal || !pT1)
739 return FALSE;
740
741 if (pT1->pt1.x != -1 && pT1->pt1.y != -1)
742 {
743 SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL));
744 GlobalUnlock(hGlobal);
745 return TRUE;
746 }
747
748 GetCursorPos(&pT1->pt0);
749 ScreenToClient(hWnd, &pT1->pt0);
750
751 iKey = T1_HitTest(pT1, &pT1->pt0);
752 if (iKey >= T1K_NONE)
753 hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL);
754 else
755 hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_HAND);
756 SetCursor(hCursor);
757
758 if (HIWORD(lParam) == WM_LBUTTONDOWN)
759 {
760 SetCapture(hWnd);
761
762 iPressed = pT1->PressedKey;
763 if (iPressed < T1K_NONE)
764 {
765 UINT iVK = gT1K2VK[iPressed];
766 keybd_event(iVK, guScanCode[iVK], KEYEVENTF_KEYUP, 0);
767 T1_InvertButton(hWnd, NULL, pT1, pT1->PressedKey);
768 pT1->PressedKey = T1K_NONE;
769 }
770
771 if (iKey >= T1K_NONE)
772 {
773 Imm32GetAllMonitorSize(&rcWork);
774 GetCursorPos(&pT1->pt0);
775 GetWindowRect(hWnd, &rc);
776 pT1->pt1.x = pT1->pt0.x - rc.left;
777 pT1->pt1.y = pT1->pt0.y - rc.top;
778 T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1);
779 }
780 else if (T1_IsValidButton(iKey, pT1))
781 {
782 UINT iVK = gT1K2VK[iKey];
783 keybd_event(iVK, guScanCode[iVK], 0, 0);
784 pT1->PressedKey = iKey;
785 T1_InvertButton(hWnd, 0, pT1, iKey);
786 }
787 else
788 {
789 MessageBeep(0xFFFFFFFF);
790 }
791 }
792
793 return TRUE;
794 }
795
796 static BOOL
T1_OnMouseMove(_In_ HWND hWnd)797 T1_OnMouseMove(
798 _In_ HWND hWnd)
799 {
800 BOOL ret = FALSE;
801 HGLOBAL hGlobal;
802 PT1WINDOW pT1;
803
804 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
805 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
806 if (!hGlobal || !pT1)
807 return FALSE;
808
809 if (pT1->pt1.x != -1 && pT1->pt1.y != -1)
810 {
811 T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1);
812 GetCursorPos(&pT1->pt0);
813 T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1);
814 ret = TRUE;
815 }
816
817 GlobalUnlock(hGlobal);
818 return ret;
819 }
820
821 static BOOL
T1_OnButtonUp(_In_ HWND hWnd)822 T1_OnButtonUp(
823 _In_ HWND hWnd)
824 {
825 BOOL ret = FALSE;
826 HGLOBAL hGlobal;
827 PT1WINDOW pT1;
828 INT x, y, iPressed;
829 HWND hwndOwner, hwndCapture = GetCapture();
830 HIMC hIMC;
831 LPINPUTCONTEXT pIC;
832
833 if (hwndCapture == hWnd)
834 ReleaseCapture();
835
836 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
837 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
838 if (!hGlobal || !pT1)
839 return FALSE;
840
841 iPressed = pT1->PressedKey;
842 if (iPressed >= T1K_NONE)
843 {
844 if (pT1->pt1.x != -1 && pT1->pt1.y != -1)
845 {
846 T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1);
847 x = pT1->pt0.x - pT1->pt1.x;
848 y = pT1->pt0.y - pT1->pt1.y;
849 SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
850 pT1->pt1.x = pT1->pt1.y = -1;
851 pT1->PressedKey = T1K_NONE;
852 ret = TRUE;
853
854 hwndOwner = GetWindow(hWnd, GW_OWNER);
855 hIMC = (HIMC)GetWindowLongPtrW(hwndOwner, 0);
856 if (hIMC)
857 {
858 pIC = ImmLockIMC(hIMC);
859 if (pIC)
860 {
861 pIC->fdwInit |= INIT_SOFTKBDPOS;
862 pIC->ptSoftKbdPos.x = x;
863 pIC->ptSoftKbdPos.y = y;
864 ImmUnlockIMC(hIMC);
865 }
866 }
867 }
868 }
869 else
870 {
871 UINT iVK = gT1K2VK[iPressed];
872 keybd_event(iVK, guScanCode[iVK], KEYEVENTF_KEYUP, 0);
873
874 T1_InvertButton(hWnd, 0, pT1, pT1->PressedKey);
875 pT1->PressedKey = T1K_NONE;
876 ret = TRUE;
877 }
878
879 GlobalUnlock(hGlobal);
880 return ret;
881 }
882
883 static LRESULT
T1_SetData(_In_ HWND hWnd,_In_ const SOFTKBDDATA * pData)884 T1_SetData(
885 _In_ HWND hWnd,
886 _In_ const SOFTKBDDATA *pData)
887 {
888 HGLOBAL hGlobal;
889 PT1WINDOW pT1;
890 HDC hDC, hMemDC;
891 HFONT hFont;
892 HGDIOBJ hFontOld, hbmOld;
893 RECT rc;
894 INT iKey;
895
896 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
897 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
898 if (!hGlobal || !pT1)
899 return 1;
900
901 hDC = GetDC(hWnd);
902 hMemDC = CreateCompatibleDC(hDC);
903 ReleaseDC(hWnd, hDC);
904
905 hbmOld = SelectObject(hMemDC, pT1->hbmKeyboard);
906 #if 0 /* The default text color is black */
907 SetTextColor(hMemDC, RGB(0, 0, 0));
908 #endif
909 SetBkColor(hMemDC, RGB(192, 192, 192));
910
911 if (pT1->CharSet == DEFAULT_CHARSET)
912 {
913 hFont = CreateFontIndirectW(&g_T1LogFont);
914 }
915 else
916 {
917 LOGFONTW lf = g_T1LogFont;
918 lf.lfCharSet = (BYTE)pT1->CharSet;
919 hFont = CreateFontIndirectW(&lf);
920 }
921 hFontOld = SelectObject(hMemDC, hFont);
922
923 for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey)
924 {
925 INT x0 = T1_KEYPOS(iKey).x, y0 = T1_KEYPOS(iKey).y;
926 INT x = x0 + 6, y = y0 + 8;
927 WCHAR wch = pT1->chKeyChar[iKey] = pData->wCode[0][gT1K2VK[iKey]];
928 SetRect(&rc, x, y, x0 + pT1->cxDefWidth, y0 + pT1->cyDefHeight);
929 ExtTextOutW(hMemDC, x, y, ETO_OPAQUE, &rc, &wch, wch != 0, NULL);
930 }
931
932 DeleteObject(SelectObject(hMemDC, hFontOld));
933 SelectObject(hMemDC, hbmOld);
934 DeleteDC(hMemDC);
935 GlobalUnlock(hGlobal);
936 return 0;
937 }
938
939 static LRESULT
T1_OnImeControl(_In_ HWND hWnd,_Inout_ WPARAM wParam,_Inout_ LPARAM lParam)940 T1_OnImeControl(
941 _In_ HWND hWnd,
942 _Inout_ WPARAM wParam,
943 _Inout_ LPARAM lParam)
944 {
945 LRESULT ret = 1;
946 PT1WINDOW pT1;
947 HGLOBAL hGlobal;
948
949 switch (wParam)
950 {
951 case IMC_GETSOFTKBDFONT:
952 {
953 TRACE("IMC_GETSOFTKBDFONT: %p\n", lParam);
954 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
955 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
956 if (hGlobal && pT1)
957 {
958 LPLOGFONTW plf = (LPLOGFONTW)lParam;
959 DWORD CharSet = pT1->CharSet;
960 GlobalUnlock(hGlobal);
961
962 *plf = g_T1LogFont;
963 if (CharSet != DEFAULT_CHARSET)
964 plf->lfCharSet = (BYTE)CharSet;
965
966 ret = 0;
967 }
968 break;
969 }
970 case IMC_SETSOFTKBDFONT:
971 {
972 const LOGFONTW *plf = (LPLOGFONTW)lParam;
973 TRACE("IMC_SETSOFTKBDFONT: %p\n", lParam);
974 if (g_T1LogFont.lfCharSet == plf->lfCharSet)
975 return 0;
976
977 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
978 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
979 if (hGlobal && pT1)
980 {
981 pT1->CharSet = plf->lfCharSet;
982 GlobalUnlock(hGlobal);
983 return 0;
984 }
985
986 break;
987 }
988 case IMC_GETSOFTKBDPOS:
989 {
990 RECT rc;
991 TRACE("IMC_GETSOFTKBDPOS\n");
992 GetWindowRect(hWnd, &rc);
993 return MAKELRESULT(rc.left, rc.top);
994 }
995 case IMC_SETSOFTKBDPOS:
996 {
997 POINT pt;
998 HWND hwndParent;
999
1000 POINTSTOPOINT(pt, lParam);
1001 TRACE("IMC_SETSOFTKBDPOS(%ld, %ld)\n", pt.x, pt.y);
1002
1003 SetWindowPos(hWnd, NULL, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
1004
1005 hwndParent = GetParent(hWnd);
1006 if (hwndParent)
1007 {
1008 HIMC hIMC = (HIMC)GetWindowLongPtrW(hwndParent, 0);
1009 if (hIMC)
1010 {
1011 LPINPUTCONTEXT pIC = ImmLockIMC(hIMC);
1012 if (pIC)
1013 {
1014 pIC->ptSoftKbdPos.x = pt.x;
1015 pIC->ptSoftKbdPos.y = pt.y;
1016 ImmUnlockIMC(hIMC);
1017 return 0;
1018 }
1019 }
1020 }
1021 break;
1022 }
1023 case IMC_GETSOFTKBDSUBTYPE:
1024 case IMC_SETSOFTKBDSUBTYPE:
1025 {
1026 TRACE("IMC_GETSOFTKBDSUBTYPE/IMC_SETSOFTKBDSUBTYPE\n");
1027 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1028 pT1 = (PT1WINDOW)GlobalLock(hGlobal);
1029 if (!hGlobal || !pT1)
1030 return -1;
1031
1032 ret = pT1->KeyboardSubType;
1033
1034 if (wParam == IMC_SETSOFTKBDSUBTYPE)
1035 pT1->KeyboardSubType = lParam;
1036
1037 GlobalUnlock(hGlobal);
1038 break;
1039 }
1040 case IMC_SETSOFTKBDDATA:
1041 {
1042 TRACE("IMC_SETSOFTKBDDATA: %p\n", lParam);
1043 ret = T1_SetData(hWnd, (SOFTKBDDATA*)lParam);
1044 if (!ret)
1045 {
1046 InvalidateRect(hWnd, NULL, FALSE);
1047 PostMessageW(hWnd, WM_PAINT, 0, 0);
1048 }
1049 break;
1050 }
1051 }
1052
1053 return ret;
1054 }
1055
1056 static LRESULT CALLBACK
T1_WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1057 T1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1058 {
1059 switch (uMsg)
1060 {
1061 case WM_CREATE:
1062 {
1063 return T1_OnCreate(hWnd);
1064 }
1065 case WM_DESTROY:
1066 {
1067 T1_OnDestroy(hWnd);
1068 break;
1069 }
1070 case WM_SETCURSOR:
1071 {
1072 if (T1_OnSetCursor(hWnd, lParam))
1073 break;
1074 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1075 }
1076 case WM_MOUSEMOVE:
1077 {
1078 if (T1_OnMouseMove(hWnd))
1079 break;
1080 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1081 }
1082 case WM_PAINT:
1083 {
1084 PAINTSTRUCT ps;
1085 HDC hDC = BeginPaint(hWnd, &ps);
1086 T1_OnDraw(hDC, hWnd);
1087 EndPaint(hWnd, &ps);
1088 break;
1089 }
1090 case WM_SHOWWINDOW:
1091 {
1092 if (!lParam && wParam != SW_SHOWNORMAL)
1093 T1_OnButtonUp(hWnd);
1094 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1095 }
1096 case WM_MOUSEACTIVATE:
1097 {
1098 return MA_NOACTIVATE;
1099 }
1100 case WM_LBUTTONUP:
1101 {
1102 if (T1_OnButtonUp(hWnd))
1103 break;
1104 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1105 }
1106 case WM_IME_CONTROL:
1107 {
1108 return T1_OnImeControl(hWnd, wParam, lParam);
1109 }
1110 default:
1111 {
1112 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1113 }
1114 }
1115
1116 return 0;
1117 }
1118
1119 /*****************************************************************************
1120 * IME Soft Keyboard Type C1
1121 */
1122
1123 #define C1_CLASSNAMEW L"SoftKBDClsC1"
1124
1125 #define C1K_MAX 56
1126
1127 #undef DEFINE_C1K
1128 #define DEFINE_C1K(c1k_code, virtual_key_code, c1k_code_name, virtual_key_name, is_special) \
1129 c1k_code_name = c1k_code,
1130
1131 /* Define C1 internal codes (C1K_...) */
1132 typedef enum C1KEY
1133 {
1134 #include "c1keys.h"
1135 } C1KEY;
1136
1137 #undef DEFINE_C1K
1138 #define DEFINE_C1K(c1k_code, virtual_key_code, c1k_code_name, virtual_key_name, is_special) \
1139 virtual_key_code,
1140
1141 /* Mapping: C1K --> Virtual Key */
1142 const BYTE gC1K2VK[C1K_MAX] =
1143 {
1144 #include "c1keys.h"
1145 };
1146
1147 typedef struct C1WINDOW
1148 {
1149 WCHAR Data[2][47];
1150 DWORD dwFlags;
1151 HBITMAP hbmKeyboard;
1152 LPARAM SubType;
1153 INT iPressedKey;
1154 POINT pt1, pt2;
1155 DWORD CharSet;
1156 } C1WINDOW, *PC1WINDOW;
1157
1158 /* The flags for C1WINDOW.dwFlags */
1159 #define FLAG_SHIFT_PRESSED 1
1160 #define FLAG_DRAGGING 2
1161 #define FLAG_PRESSED 4
1162
1163 static BOOL gbC1ButtonInit = FALSE;
1164 static POINT gptC1ButtonPos[C1K_MAX];
1165
C1_InitButtonPos(void)1166 static void C1_InitButtonPos(void)
1167 {
1168 LONG x = 0, y = 0;
1169 INT iKey;
1170
1171 /* 1st row */
1172 for (iKey = C1K_OEM_3; iKey < C1K_Q; ++iKey)
1173 {
1174 gptC1ButtonPos[iKey].x = x;
1175 gptC1ButtonPos[iKey].y = y;
1176 x += 24;
1177 }
1178 gptC1ButtonPos[C1K_BACKSPACE].x = x;
1179 gptC1ButtonPos[C1K_BACKSPACE].y = y;
1180
1181 /* 2nd row */
1182 y = 28;
1183 gptC1ButtonPos[C1K_TAB].x = 0;
1184 gptC1ButtonPos[C1K_TAB].y = y;
1185 x = 36;
1186 for (; iKey < C1K_A; ++iKey)
1187 {
1188 gptC1ButtonPos[iKey].x = x;
1189 gptC1ButtonPos[iKey].y = y;
1190 x += 24;
1191 }
1192
1193 /* 3rd row */
1194 y = 56;
1195 gptC1ButtonPos[C1K_CAPS].x = 0;
1196 gptC1ButtonPos[C1K_CAPS].y = y;
1197 x = 42;
1198 for (; iKey < C1K_Z; ++iKey)
1199 {
1200 gptC1ButtonPos[iKey].x = x;
1201 gptC1ButtonPos[iKey].y = y;
1202 x += 24;
1203 }
1204 gptC1ButtonPos[C1K_ENTER].x = x;
1205 gptC1ButtonPos[C1K_ENTER].y = y;
1206
1207 /* 4th row */
1208 y = 84;
1209 gptC1ButtonPos[C1K_SHIFT].x = 0;
1210 gptC1ButtonPos[C1K_SHIFT].y = y;
1211 x = 60;
1212 for (; iKey < C1K_BACKSPACE; ++iKey)
1213 {
1214 gptC1ButtonPos[iKey].x = x;
1215 gptC1ButtonPos[iKey].y = y;
1216 x += 24;
1217 }
1218
1219 /* 5th row */
1220 y = 112;
1221 gptC1ButtonPos[C1K_INSERT].x = 0;
1222 gptC1ButtonPos[C1K_INSERT].y = y;
1223 gptC1ButtonPos[C1K_DELETE].x = 58;
1224 gptC1ButtonPos[C1K_DELETE].y = y;
1225 gptC1ButtonPos[C1K_SPACE].x = 96;
1226 gptC1ButtonPos[C1K_SPACE].y = y;
1227 gptC1ButtonPos[C1K_ESCAPE].x = 310;
1228 gptC1ButtonPos[C1K_ESCAPE].y = y;
1229 }
1230
1231 static void
C1_DrawConvexRect(_In_ HDC hDC,_In_ INT x,_In_ INT y,_In_ INT width,_In_ INT height)1232 C1_DrawConvexRect(
1233 _In_ HDC hDC,
1234 _In_ INT x,
1235 _In_ INT y,
1236 _In_ INT width,
1237 _In_ INT height)
1238 {
1239 HGDIOBJ hLtGrayBrush = GetStockObject(LTGRAY_BRUSH);
1240 HGDIOBJ hBlackPen = GetStockObject(BLACK_PEN);
1241 HGDIOBJ hWhiteBrush = GetStockObject(WHITE_BRUSH);
1242 HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH);
1243 INT y2 = y + height - 1;
1244
1245 /* Draw face */
1246 SelectObject(hDC, hLtGrayBrush);
1247 SelectObject(hDC, hBlackPen);
1248 Rectangle(hDC, x, y, x + width, y + height);
1249
1250 /* Draw light edge */
1251 SelectObject(hDC, hWhiteBrush);
1252 PatBlt(hDC, x, y2, 2, 1 - height, PATCOPY);
1253 PatBlt(hDC, x, y, width - 1, 2, PATCOPY);
1254
1255 /* Draw dark edge */
1256 SelectObject(hDC, hGrayBrush);
1257 PatBlt(hDC, x + 1, y2, width - 2, -1, PATCOPY);
1258 PatBlt(hDC, x + width - 1, y2, -1, 2 - height, PATCOPY);
1259 }
1260
1261 static void
C1_InvertButton(_In_ HDC hDC,_In_ INT iKey)1262 C1_InvertButton(
1263 _In_ HDC hDC,
1264 _In_ INT iKey)
1265 {
1266 INT width = 24, height = 28;
1267
1268 if (iKey < 0)
1269 return;
1270
1271 switch (iKey)
1272 {
1273 case C1K_BACKSPACE: case C1K_TAB:
1274 width = 36;
1275 break;
1276 case C1K_CAPS: case C1K_ENTER:
1277 width = 42;
1278 break;
1279 case C1K_SHIFT:
1280 width = 60;
1281 break;
1282 case C1K_INSERT: case C1K_DELETE: case C1K_ESCAPE:
1283 width = 38;
1284 height = 24;
1285 break;
1286 case C1K_SPACE:
1287 width = 172;
1288 height = 24;
1289 break;
1290 default:
1291 break;
1292 }
1293
1294 BitBlt(hDC, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, width, height,
1295 hDC, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, DSTINVERT);
1296 }
1297
1298 static void
C1_DrawLabel(_In_ HDC hDC,_In_ INT nBitmapID)1299 C1_DrawLabel(
1300 _In_ HDC hDC,
1301 _In_ INT nBitmapID)
1302 {
1303 HBITMAP hBitmap;
1304 HGDIOBJ hbmOld;
1305 HDC hMemDC;
1306 INT iKey;
1307
1308 hBitmap = LoadBitmapW(ghImm32Inst, MAKEINTRESOURCEW(nBitmapID));
1309 hMemDC = CreateCompatibleDC(hDC);
1310 hbmOld = SelectObject(hMemDC, hBitmap);
1311 for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
1312 {
1313 BitBlt(hDC, gptC1ButtonPos[iKey].x + 2, gptC1ButtonPos[iKey].y + 2, 8, 8,
1314 hMemDC, iKey * 8, 0, SRCCOPY);
1315 }
1316 DeleteObject(SelectObject(hMemDC, hbmOld));
1317 DeleteDC(hMemDC);
1318 }
1319
1320 static void
C1_InitBitmap(_In_ HDC hDC,_In_ INT x,_In_ INT y,_In_ INT width,_In_ INT height)1321 C1_InitBitmap(
1322 _In_ HDC hDC,
1323 _In_ INT x,
1324 _In_ INT y,
1325 _In_ INT width,
1326 _In_ INT height)
1327 {
1328 HGDIOBJ hLtGrayBrush = GetStockObject(LTGRAY_BRUSH);
1329 HGDIOBJ hNullPen = GetStockObject(NULL_PEN);
1330 INT iKey;
1331
1332 /* Draw keyboard frame */
1333 SelectObject(hDC, hLtGrayBrush);
1334 SelectObject(hDC, hNullPen);
1335 Rectangle(hDC, x, y, width + 1, height + 1);
1336
1337 for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
1338 {
1339 C1_DrawConvexRect(hDC, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, 24, 28);
1340 }
1341
1342 C1_DrawLabel(hDC, IDB_C1_CHARS);
1343
1344 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_BACKSPACE].x, gptC1ButtonPos[C1K_BACKSPACE].y, 36, 28);
1345 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_BACKSPACE].x + 2, gptC1ButtonPos[C1K_BACKSPACE].y + 2, 32, 24, IDB_C1_BACKSPACE);
1346
1347 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_TAB].x, gptC1ButtonPos[C1K_TAB].y, 36, 28);
1348 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_TAB].x + 2, gptC1ButtonPos[C1K_TAB].y + 2, 32, 24, IDB_C1_TAB);
1349
1350 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_CAPS].x, gptC1ButtonPos[C1K_CAPS].y, 42, 28);
1351 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_CAPS].x + 2, gptC1ButtonPos[C1K_CAPS].y + 2, 38, 24, IDB_C1_CAPS);
1352
1353 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_ENTER].x, gptC1ButtonPos[C1K_ENTER].y, 42, 28);
1354 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_ENTER].x + 2, gptC1ButtonPos[C1K_ENTER].y + 2, 38, 24, IDB_C1_ENTER);
1355
1356 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_SHIFT].x, gptC1ButtonPos[C1K_SHIFT].y, 60, 28);
1357 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_SHIFT].x + 2, gptC1ButtonPos[C1K_SHIFT].y + 2, 56, 24, IDB_C1_SHIFT);
1358
1359 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_INSERT].x, gptC1ButtonPos[C1K_INSERT].y, 38, 24);
1360 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_INSERT].x + 2, gptC1ButtonPos[C1K_INSERT].y + 2, 34, 20, IDB_C1_INS);
1361
1362 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_DELETE].x, gptC1ButtonPos[C1K_DELETE].y, 38, 24);
1363 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_DELETE].x + 2, gptC1ButtonPos[C1K_DELETE].y + 2, 34, 20, IDB_C1_DEL);
1364
1365 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_SPACE].x, gptC1ButtonPos[C1K_SPACE].y, 172, 24);
1366
1367 C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_ESCAPE].x, gptC1ButtonPos[C1K_ESCAPE].y , 38, 24);
1368 Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_ESCAPE].x + 2, gptC1ButtonPos[C1K_ESCAPE].y + 2, 34, 20, IDB_C1_ESCAPE);
1369 }
1370
1371 static INT
C1_OnCreate(_In_ HWND hWnd)1372 C1_OnCreate(
1373 _In_ HWND hWnd)
1374 {
1375 HGLOBAL hGlobal;
1376 PC1WINDOW pC1;
1377 HDC hDC, hMemDC;
1378 RECT rc;
1379 HGDIOBJ hbmOld;
1380 HBITMAP hbmKeyboard;
1381
1382 hGlobal = GlobalAlloc(GHND, sizeof(C1WINDOW));
1383 if (!hGlobal)
1384 return -1;
1385
1386 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1387 if (!pC1)
1388 {
1389 GlobalFree(hGlobal);
1390 return -1;
1391 }
1392 SetWindowLongPtrW(hWnd, 0, (LONG_PTR)hGlobal);
1393
1394 if (!gbC1ButtonInit)
1395 {
1396 C1_InitButtonPos();
1397 gbC1ButtonInit = TRUE;
1398 }
1399
1400 pC1->iPressedKey = -1;
1401 pC1->CharSet = GB2312_CHARSET;
1402
1403 GetClientRect(hWnd, &rc);
1404
1405 hDC = GetDC(hWnd);
1406 hMemDC = CreateCompatibleDC(hDC);
1407 hbmKeyboard = CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - rc.top);
1408 ReleaseDC(hWnd, hDC);
1409
1410 hbmOld = SelectObject(hMemDC, hbmKeyboard);
1411 C1_InitBitmap(hMemDC, rc.left, rc.top, rc.right, rc.bottom);
1412 SelectObject(hMemDC, hbmOld);
1413 pC1->hbmKeyboard = hbmKeyboard;
1414 DeleteDC(hMemDC);
1415
1416 GlobalUnlock(hGlobal);
1417 return 0;
1418 }
1419
1420 static void
C1_OnDraw(_In_ HDC hDC,_In_ HWND hWnd)1421 C1_OnDraw(
1422 _In_ HDC hDC,
1423 _In_ HWND hWnd)
1424 {
1425 HGLOBAL hGlobal;
1426 PC1WINDOW pC1;
1427 HDC hMemDC;
1428 RECT rc;
1429 HGDIOBJ hbmOld;
1430
1431 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1432 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1433 if (!hGlobal || !pC1)
1434 return;
1435
1436 GetClientRect(hWnd, &rc);
1437
1438 hMemDC = CreateCompatibleDC(hDC);
1439 hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
1440 BitBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 0, 0, SRCCOPY);
1441 SelectObject(hMemDC, hbmOld);
1442 DeleteDC(hMemDC);
1443
1444 GlobalUnlock(hGlobal);
1445 }
1446
1447 static BOOL
C1_SetData(_In_ HWND hWnd,_In_ const SOFTKBDDATA * pData)1448 C1_SetData(
1449 _In_ HWND hWnd,
1450 _In_ const SOFTKBDDATA *pData)
1451 {
1452 HGLOBAL hGlobal;
1453 PC1WINDOW pC1;
1454 HDC hDC, hMemDC;
1455 INT iKey;
1456 BOOL bDisabled;
1457 HBITMAP hbmKeyboard;
1458 HGDIOBJ hbmOld, hFontOld;
1459 HFONT hFont;
1460 RECT rc;
1461 LOGFONTW lf;
1462
1463 if (pData->uCount != 2)
1464 return 0;
1465
1466 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1467 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1468 if (!hGlobal || !pC1)
1469 return FALSE;
1470
1471 hDC = GetDC(hWnd);
1472 hMemDC = CreateCompatibleDC(hDC);
1473
1474 hbmKeyboard = pC1->hbmKeyboard;
1475 hbmOld = SelectObject(hMemDC, hbmKeyboard);
1476
1477 GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
1478 lf.lfHeight = -12;
1479 if (pC1->CharSet != DEFAULT_CHARSET)
1480 lf.lfCharSet = (BYTE)pC1->CharSet;
1481
1482 hFont = CreateFontIndirectW(&lf);
1483 hFontOld = SelectObject(hMemDC, hFont);
1484 for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
1485 {
1486 pC1->Data[1][iKey] = pData->wCode[0][(BYTE)gC1K2VK[iKey]];
1487 pC1->Data[0][iKey] = pData->wCode[1][(BYTE)gC1K2VK[iKey]];
1488 }
1489
1490 SetBkColor(hMemDC, RGB(191, 191, 191));
1491 for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
1492 {
1493 /* Upper right */
1494 rc.right = gptC1ButtonPos[iKey].x + 24 - 2;
1495 rc.top = gptC1ButtonPos[iKey].y + 2;
1496 rc.left = rc.right - 14;
1497 rc.bottom = rc.top + 14;
1498 bDisabled = (pC1->Data[0][iKey] == 0);
1499 DrawTextW(hMemDC, &pC1->Data[0][iKey], !bDisabled, &rc,
1500 DT_RIGHT | DT_TOP | DT_SINGLELINE);
1501
1502 /* Lower left */
1503 rc.left = gptC1ButtonPos[iKey].x + 2;
1504 rc.bottom = gptC1ButtonPos[iKey].y + 28 - 2;
1505 rc.right = rc.left + 14;
1506 rc.top = rc.bottom - 14;
1507 bDisabled = (pC1->Data[1][iKey] == 0);
1508 DrawTextW(hMemDC, &pC1->Data[1][iKey], !bDisabled, &rc,
1509 DT_LEFT | DT_BOTTOM | DT_SINGLELINE);
1510 }
1511
1512 if (pC1->dwFlags & FLAG_SHIFT_PRESSED)
1513 C1_InvertButton(hMemDC, C1K_SHIFT);
1514
1515 pC1->dwFlags = 0;
1516
1517 SelectObject(hMemDC, hbmOld);
1518 DeleteObject(SelectObject(hMemDC, hFontOld));
1519
1520 DeleteDC(hMemDC);
1521 ReleaseDC(hWnd, hDC);
1522
1523 GlobalUnlock(hGlobal);
1524 return TRUE;
1525 }
1526
1527 static void
C1_DrawDragBorder(_In_ HWND hWnd,_In_ LPPOINT ppt1,_Inout_ LPPOINT ppt2)1528 C1_DrawDragBorder(
1529 _In_ HWND hWnd,
1530 _In_ LPPOINT ppt1,
1531 _Inout_ LPPOINT ppt2)
1532 {
1533 HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH);
1534 INT x, y;
1535 RECT rc, rcWork;
1536 INT cxBorder = GetSystemMetrics(SM_CXBORDER), cyBorder = GetSystemMetrics(SM_CYBORDER);
1537 HDC hDisplayDC;
1538
1539 Imm32GetAllMonitorSize(&rcWork);
1540 hDisplayDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
1541
1542 SelectObject(hDisplayDC, hGrayBrush);
1543 x = ppt1->x - ppt2->x;
1544 y = ppt1->y - ppt2->y;
1545 if (x < rcWork.left)
1546 x = rcWork.left;
1547 if (y < rcWork.top)
1548 y = rcWork.top;
1549
1550 GetWindowRect(hWnd, &rc);
1551
1552 if (rc.right - rc.left + x > rcWork.right)
1553 x = rc.left + rcWork.right - rc.right;
1554 if (y + rc.bottom - rc.top > rcWork.bottom)
1555 y = rc.top + rcWork.bottom - rc.bottom;
1556
1557 ppt2->x = ppt1->x - x;
1558 ppt2->y = ppt1->y - y;
1559
1560 PatBlt(hDisplayDC, x, y, rc.right - rc.left - cxBorder, cyBorder, PATINVERT);
1561 PatBlt(hDisplayDC, x, y + cyBorder, cxBorder, rc.bottom - rc.top - cyBorder, PATINVERT);
1562 PatBlt(hDisplayDC, x + cxBorder, y + rc.bottom - rc.top, rc.right - rc.left - cxBorder, -cyBorder, PATINVERT);
1563 PatBlt(hDisplayDC, x + rc.right - rc.left, y, -cxBorder, rc.bottom - rc.top - cyBorder, PATINVERT);
1564
1565 DeleteDC(hDisplayDC);
1566 }
1567
1568 static INT
C1_HitTest(_In_ const POINT * ppt)1569 C1_HitTest(
1570 _In_ const POINT *ppt)
1571 {
1572 INT iKey;
1573
1574 for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
1575 {
1576 if (Imm32PtInRect(ppt, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, 24, 28))
1577 return iKey;
1578 }
1579
1580 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_BACKSPACE].x, gptC1ButtonPos[C1K_BACKSPACE].y, 36, 28))
1581 return C1K_BACKSPACE;
1582 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_TAB].x, gptC1ButtonPos[C1K_TAB].y, 36, 28))
1583 return C1K_TAB;
1584 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_CAPS].x, gptC1ButtonPos[C1K_CAPS].y, 42, 28))
1585 return C1K_CAPS;
1586 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_ENTER].x, gptC1ButtonPos[C1K_ENTER].y, 42, 28))
1587 return C1K_ENTER;
1588 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_SHIFT].x, gptC1ButtonPos[C1K_SHIFT].y, 60, 28))
1589 return C1K_SHIFT;
1590 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_ESCAPE].x, gptC1ButtonPos[C1K_ESCAPE].y, 38, 24))
1591 return C1K_ESCAPE;
1592 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_SPACE].x, gptC1ButtonPos[C1K_SPACE].y, 172, 24))
1593 return C1K_SPACE;
1594 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_INSERT].x, gptC1ButtonPos[C1K_INSERT].y, 38, 24))
1595 return C1K_INSERT;
1596 if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_DELETE].x, gptC1ButtonPos[C1K_DELETE].y, 38, 24))
1597 return C1K_DELETE;
1598
1599 return -1;
1600 }
1601
1602 static void
C1_OnButtonDown(_In_ HWND hWnd,_Inout_ PC1WINDOW pC1)1603 C1_OnButtonDown(
1604 _In_ HWND hWnd,
1605 _Inout_ PC1WINDOW pC1)
1606 {
1607 INT iPressedKey;
1608 HDC hMemDC;
1609 WCHAR wch = 0xFF;
1610 HGDIOBJ hbmOld;
1611 HDC hDC;
1612
1613 SetCapture(hWnd);
1614
1615 iPressedKey = pC1->iPressedKey;
1616 if (iPressedKey == -1)
1617 {
1618 pC1->dwFlags |= FLAG_DRAGGING;
1619 C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
1620 return;
1621 }
1622
1623 if (iPressedKey < C1K_BACKSPACE)
1624 {
1625 wch = pC1->Data[!(pC1->dwFlags & 1)][iPressedKey];
1626 if (!wch)
1627 {
1628 MessageBeep(0xFFFFFFFF);
1629 pC1->iPressedKey = -1;
1630 return;
1631 }
1632 }
1633
1634 if ((iPressedKey != C1K_SHIFT) || !(pC1->dwFlags & FLAG_SHIFT_PRESSED))
1635 {
1636 hDC = GetDC(hWnd);
1637 hMemDC = CreateCompatibleDC(hDC);
1638 hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
1639 C1_InvertButton(hDC, pC1->iPressedKey);
1640 C1_InvertButton(hMemDC, pC1->iPressedKey);
1641 SelectObject(hMemDC, hbmOld);
1642 DeleteDC(hMemDC);
1643 ReleaseDC(hWnd, hDC);
1644 }
1645
1646 pC1->dwFlags |= FLAG_PRESSED;
1647 }
1648
1649 static BOOL
C1_OnSetCursor(_In_ HWND hWnd,_In_ LPARAM lParam)1650 C1_OnSetCursor(
1651 _In_ HWND hWnd,
1652 _In_ LPARAM lParam)
1653 {
1654 HGLOBAL hGlobal;
1655 PC1WINDOW pC1;
1656 HCURSOR hCursor;
1657 INT iKey;
1658 POINT pt1, pt2;
1659
1660 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1661 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1662 if (!hGlobal || !pC1)
1663 return FALSE;
1664
1665 if (pC1->dwFlags & FLAG_DRAGGING)
1666 {
1667 hCursor = LoadCursorW(0, (LPCWSTR)IDC_SIZEALL);
1668 SetCursor(hCursor);
1669 GlobalUnlock(hGlobal);
1670 return TRUE;
1671 }
1672
1673 GetCursorPos(&pt1);
1674 pt2 = pt1;
1675 ScreenToClient(hWnd, &pt2);
1676
1677 iKey = C1_HitTest(&pt2);
1678 if (iKey == -1)
1679 hCursor = LoadCursorW(0, (LPCWSTR)IDC_SIZEALL);
1680 else
1681 hCursor = LoadCursorW(0, (LPCWSTR)IDC_HAND);
1682 SetCursor(hCursor);
1683
1684 if (HIWORD(lParam) == WM_LBUTTONDOWN)
1685 {
1686 pC1->pt1 = pt1;
1687 pC1->pt2 = pt2;
1688 pC1->iPressedKey = iKey;
1689 C1_OnButtonDown(hWnd, pC1);
1690 }
1691
1692 GlobalUnlock(hGlobal);
1693 return TRUE;
1694 }
1695
1696 static BOOL
C1_OnMouseMove(_In_ HWND hWnd,_In_ WPARAM wParam,_In_ LPARAM lParam)1697 C1_OnMouseMove(
1698 _In_ HWND hWnd,
1699 _In_ WPARAM wParam,
1700 _In_ LPARAM lParam)
1701 {
1702 HGLOBAL hGlobal;
1703 PC1WINDOW pC1;
1704 HDC hMemDC;
1705 DWORD dwFlags;
1706 INT iPressedKey;
1707 POINT pt;
1708 HGDIOBJ hbmOld;
1709 HDC hDC;
1710 INT iKey;
1711
1712 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1713 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1714 if (!hGlobal || !pC1)
1715 return FALSE;
1716
1717 if (pC1->dwFlags & FLAG_DRAGGING)
1718 {
1719 C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
1720 GetCursorPos(&pC1->pt1);
1721 C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
1722 GlobalUnlock(hGlobal);
1723 return TRUE;
1724 }
1725
1726 if (pC1->iPressedKey != -1)
1727 {
1728 GetCursorPos(&pt);
1729 ScreenToClient(hWnd, &pt);
1730 iKey = C1_HitTest(&pt);
1731
1732 hDC = GetDC(hWnd);
1733 hMemDC = CreateCompatibleDC(hDC);
1734 hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
1735 dwFlags = pC1->dwFlags;
1736
1737 iPressedKey = pC1->iPressedKey;
1738 if (!!(dwFlags & FLAG_PRESSED) == (iKey != iPressedKey))
1739 {
1740 if (iPressedKey != C1K_SHIFT || !(dwFlags & FLAG_SHIFT_PRESSED))
1741 {
1742 C1_InvertButton(hDC, iPressedKey);
1743 C1_InvertButton(hMemDC, pC1->iPressedKey);
1744 }
1745
1746 pC1->dwFlags ^= FLAG_PRESSED;
1747 }
1748
1749 SelectObject(hMemDC, hbmOld);
1750 DeleteDC(hMemDC);
1751 ReleaseDC(hWnd, hDC);
1752 }
1753
1754 GlobalUnlock(hGlobal);
1755 return TRUE;
1756 }
1757
1758 static BOOL
C1_OnButtonUp(_In_ HWND hWnd,_In_ WPARAM wParam,_In_ LPARAM lParam)1759 C1_OnButtonUp(
1760 _In_ HWND hWnd,
1761 _In_ WPARAM wParam,
1762 _In_ LPARAM lParam)
1763 {
1764 HGLOBAL hGlobal;
1765 PC1WINDOW pC1;
1766 BOOL ret = FALSE;
1767 INT x, y, iKey;
1768 HDC hDC, hMemDC;
1769 HGDIOBJ hbmOld;
1770 HIMC hIMC;
1771 HWND hwndOwner;
1772 LPINPUTCONTEXT pIC;
1773
1774 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1775 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1776 if (!hGlobal || !pC1)
1777 return FALSE;
1778
1779 ReleaseCapture();
1780
1781 if (pC1->dwFlags & FLAG_DRAGGING)
1782 {
1783 pC1->dwFlags &= ~FLAG_DRAGGING;
1784 C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
1785 x = pC1->pt1.x - pC1->pt2.x;
1786 y = pC1->pt1.y - pC1->pt2.y;
1787 SetWindowPos(hWnd, 0, x, y, 0, 0, 0x15u);
1788 ret = TRUE;
1789
1790 hwndOwner = GetWindow(hWnd, GW_OWNER);
1791 hIMC = (HIMC)GetWindowLongPtrW(hwndOwner, 0);
1792 if (hIMC)
1793 {
1794 pIC = ImmLockIMC(hIMC);
1795 if (pIC)
1796 {
1797 pIC->fdwInit |= INIT_SOFTKBDPOS;
1798 pIC->ptSoftKbdPos.x = x;
1799 pIC->ptSoftKbdPos.y = y;
1800 ImmUnlockIMC(hIMC);
1801 }
1802 }
1803
1804 GlobalUnlock(hGlobal);
1805 return ret;
1806 }
1807
1808 iKey = pC1->iPressedKey;
1809 if (iKey == -1)
1810 return FALSE;
1811
1812 if (!(pC1->dwFlags & FLAG_PRESSED))
1813 {
1814 pC1->iPressedKey = -1;
1815 GlobalUnlock(hGlobal);
1816 return ret;
1817 }
1818
1819 if (iKey == C1K_SHIFT)
1820 {
1821 if (!(pC1->dwFlags & FLAG_SHIFT_PRESSED))
1822 {
1823 pC1->dwFlags |= FLAG_SHIFT_PRESSED;
1824 pC1->dwFlags &= ~FLAG_PRESSED;
1825 pC1->iPressedKey = -1;
1826 GlobalUnlock(hGlobal);
1827 return ret;
1828 }
1829 }
1830 else if (iKey < C1K_BACKSPACE && (pC1->dwFlags & FLAG_SHIFT_PRESSED))
1831 {
1832 INT iVK = gC1K2VK[pC1->iPressedKey];
1833 keybd_event(VK_SHIFT, guScanCode[C1K_SHIFT], 0, 0);
1834 keybd_event(iVK, guScanCode[(BYTE)iVK], 0, 0);
1835 keybd_event(iVK, guScanCode[(BYTE)iVK], KEYEVENTF_KEYUP, 0);
1836 keybd_event(VK_SHIFT, guScanCode[C1K_SHIFT], KEYEVENTF_KEYUP, 0);
1837 }
1838 else
1839 {
1840 INT iVK = gC1K2VK[iKey];
1841 keybd_event(iVK, guScanCode[iVK], 0, 0);
1842 keybd_event(iVK, guScanCode[iVK], KEYEVENTF_KEYUP, 0);
1843 }
1844
1845 ret = TRUE;
1846
1847 hDC = GetDC(hWnd);
1848 hMemDC = CreateCompatibleDC(hDC);
1849 hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
1850
1851 C1_InvertButton(hDC, pC1->iPressedKey);
1852 C1_InvertButton(hMemDC, pC1->iPressedKey);
1853
1854 if (pC1->iPressedKey < C1K_BACKSPACE && (pC1->dwFlags & FLAG_SHIFT_PRESSED))
1855 {
1856 C1_InvertButton(hDC, C1K_SHIFT);
1857 C1_InvertButton(hMemDC, C1K_SHIFT);
1858 }
1859
1860 if (pC1->iPressedKey < C1K_BACKSPACE || pC1->iPressedKey == C1K_SHIFT)
1861 pC1->dwFlags &= ~FLAG_SHIFT_PRESSED;
1862
1863 SelectObject(hMemDC, hbmOld);
1864 DeleteDC(hMemDC);
1865 ReleaseDC(hWnd, hDC);
1866
1867 pC1->dwFlags &= ~FLAG_PRESSED;
1868 pC1->iPressedKey = -1;
1869 GlobalUnlock(hGlobal);
1870 return ret;
1871 }
1872
1873 static void
C1_OnDestroy(_In_ HWND hWnd)1874 C1_OnDestroy(
1875 _In_ HWND hWnd)
1876 {
1877 HGLOBAL hGlobal;
1878 PC1WINDOW pC1;
1879 HWND hwndOwner;
1880
1881 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1882 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1883 if (!hGlobal || !pC1)
1884 return;
1885
1886 if (pC1->dwFlags & FLAG_DRAGGING)
1887 C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
1888
1889 DeleteObject(pC1->hbmKeyboard);
1890 GlobalUnlock(hGlobal);
1891 GlobalFree(hGlobal);
1892
1893 hwndOwner = GetWindow(hWnd, GW_OWNER);
1894 if (hwndOwner)
1895 SendMessageW(hwndOwner, WM_IME_NOTIFY, IMN_SOFTKBDDESTROYED, 0);
1896 }
1897
1898 static LRESULT
C1_OnImeControl(_In_ HWND hWnd,_In_ WPARAM wParam,_In_ LPARAM lParam)1899 C1_OnImeControl(
1900 _In_ HWND hWnd,
1901 _In_ WPARAM wParam,
1902 _In_ LPARAM lParam)
1903 {
1904 HGLOBAL hGlobal;
1905 PC1WINDOW pC1;
1906 LOGFONTW lf;
1907 RECT rc;
1908 LRESULT ret = 0;
1909 HDC hDC;
1910
1911 switch (wParam)
1912 {
1913 case IMC_GETSOFTKBDFONT:
1914 {
1915 TRACE("IMC_GETSOFTKBDFONT: %p\n", lParam);
1916 hDC = GetDC(hWnd);
1917 GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), &lf);
1918 ReleaseDC(hWnd, hDC);
1919 *(LPLOGFONTW)lParam = lf;
1920 break;
1921 }
1922 case IMC_SETSOFTKBDFONT:
1923 {
1924 LPLOGFONTW plf = (LPLOGFONTW)lParam;
1925 LOGFONTW lf;
1926 TRACE("IMC_SETSOFTKBDFONT: %p\n", lParam);
1927 GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), &lf);
1928 if (lf.lfCharSet == plf->lfCharSet)
1929 return 0;
1930
1931 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1932 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1933 if (!hGlobal || !pC1)
1934 return 1;
1935
1936 pC1->CharSet = plf->lfCharSet;
1937 GlobalUnlock(hGlobal);
1938 break;
1939 }
1940 case IMC_GETSOFTKBDPOS:
1941 {
1942 TRACE("IMC_GETSOFTKBDPOS\n");
1943 GetWindowRect(hWnd, &rc);
1944 return MAKELRESULT(rc.left, rc.top);
1945 }
1946 case IMC_SETSOFTKBDPOS:
1947 {
1948 POINT pt;
1949 POINTSTOPOINT(pt, lParam);
1950 TRACE("IMC_SETSOFTKBDPOS: %d, %d\n", pt.x, pt.y);
1951 SetWindowPos(hWnd, NULL, pt.x, pt.y, 0, 0,
1952 (SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE));
1953 break;
1954 }
1955 case IMC_GETSOFTKBDSUBTYPE:
1956 case IMC_SETSOFTKBDSUBTYPE:
1957 {
1958 TRACE("IMC_GETSOFTKBDSUBTYPE/IMC_SETSOFTKBDSUBTYPE: %p, %p\n", wParam, lParam);
1959 hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
1960 pC1 = (PC1WINDOW)GlobalLock(hGlobal);
1961 if (!hGlobal || !pC1)
1962 return -1;
1963 ret = pC1->SubType;
1964 if (wParam == IMC_SETSOFTKBDSUBTYPE)
1965 pC1->SubType = lParam;
1966 GlobalUnlock(hGlobal);
1967 break;
1968 }
1969 case IMC_SETSOFTKBDDATA:
1970 {
1971 TRACE("IMC_SETSOFTKBDDATA: %p\n", lParam);
1972 if (C1_SetData(hWnd, (SOFTKBDDATA*)lParam))
1973 return -1;
1974
1975 InvalidateRect(hWnd, 0, 0);
1976 }
1977 default:
1978 break;
1979 }
1980
1981 return ret;
1982 }
1983
1984 static LRESULT CALLBACK
C1_WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)1985 C1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1986 {
1987 switch (uMsg)
1988 {
1989 case WM_CREATE:
1990 {
1991 return C1_OnCreate(hWnd);
1992 }
1993 case WM_DESTROY:
1994 {
1995 C1_OnDestroy(hWnd);
1996 break;
1997 }
1998 case WM_SETCURSOR:
1999 {
2000 if (C1_OnSetCursor(hWnd, lParam))
2001 break;
2002 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
2003 }
2004 case WM_MOUSEMOVE:
2005 {
2006 if (C1_OnMouseMove(hWnd, wParam, lParam))
2007 break;
2008 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
2009 }
2010 case WM_LBUTTONUP:
2011 {
2012 if (C1_OnButtonUp(hWnd, wParam, lParam))
2013 break;
2014 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
2015 }
2016 case WM_PAINT:
2017 {
2018 PAINTSTRUCT ps;
2019 HDC hDC = BeginPaint(hWnd, &ps);
2020 C1_OnDraw(hDC, hWnd);
2021 EndPaint(hWnd, &ps);
2022 break;
2023 }
2024 case WM_IME_CONTROL:
2025 {
2026 return C1_OnImeControl(hWnd, wParam, lParam);
2027 }
2028 case WM_MOUSEACTIVATE:
2029 {
2030 return MA_NOACTIVATE;
2031 }
2032 default:
2033 {
2034 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
2035 }
2036 }
2037 return 0;
2038 }
2039
2040 /*****************************************************************************/
2041
2042 static BOOL
Imm32RegisterSoftKeyboard(_In_ UINT uType)2043 Imm32RegisterSoftKeyboard(
2044 _In_ UINT uType)
2045 {
2046 WNDCLASSEXW wcx;
2047 LPCWSTR pszClass = ((uType == SOFTKEYBOARD_TYPE_T1) ? T1_CLASSNAMEW : C1_CLASSNAMEW);
2048 if (GetClassInfoExW(ghImm32Inst, pszClass, &wcx))
2049 return TRUE;
2050
2051 ZeroMemory(&wcx, sizeof(wcx));
2052 wcx.cbSize = sizeof(wcx);
2053 wcx.style = CS_IME;
2054 wcx.cbWndExtra = sizeof(PT1WINDOW);
2055 wcx.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION);
2056 wcx.hInstance = ghImm32Inst;
2057 wcx.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL);
2058 wcx.lpszClassName = pszClass;
2059
2060 if (uType == SOFTKEYBOARD_TYPE_T1)
2061 {
2062 wcx.lpfnWndProc = T1_WindowProc;
2063 wcx.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
2064 }
2065 else
2066 {
2067 wcx.lpfnWndProc = C1_WindowProc;
2068 wcx.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
2069 }
2070
2071 return !!RegisterClassExW(&wcx);
2072 }
2073
2074 static void
Imm32GetSoftKeyboardDimension(_In_ UINT uType,_Out_ LPINT pcx,_Out_ LPINT pcy)2075 Imm32GetSoftKeyboardDimension(
2076 _In_ UINT uType,
2077 _Out_ LPINT pcx,
2078 _Out_ LPINT pcy)
2079 {
2080 if (uType == SOFTKEYBOARD_TYPE_T1)
2081 {
2082 TEXTMETRICW tm;
2083 T1_GetTextMetric(&tm);
2084 *pcx = 15 * tm.tmMaxCharWidth + 2 * gptRaiseEdge.x + 139;
2085 *pcy = 5 * tm.tmHeight + 2 * gptRaiseEdge.y + 58;
2086 }
2087 else
2088 {
2089 INT cxEdge = GetSystemMetrics(SM_CXEDGE), cyEdge = GetSystemMetrics(SM_CXEDGE);
2090 *pcx = 2 * (GetSystemMetrics(SM_CXBORDER) + cxEdge) + 348;
2091 *pcy = 2 * (GetSystemMetrics(SM_CYBORDER) + cyEdge) + 136;
2092 }
2093 }
2094
2095 /***********************************************************************
2096 * ImmCreateSoftKeyboard (IMM32.@)
2097 *
2098 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImmCreateSoftKeyboard.html
2099 */
2100 HWND WINAPI
ImmCreateSoftKeyboard(_In_ UINT uType,_In_ HWND hwndParent,_In_ INT x,_In_ INT y)2101 ImmCreateSoftKeyboard(
2102 _In_ UINT uType,
2103 _In_ HWND hwndParent,
2104 _In_ INT x,
2105 _In_ INT y)
2106 {
2107 HKL hKL;
2108 PIMEDPI pImeDpi;
2109 UINT iVK;
2110 INT xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD, cxEdge, cyEdge;
2111 HWND hwndSoftKBD;
2112 DWORD Style, ExStyle, UICaps;
2113 LPCWSTR pszClass;
2114 RECT rcWorkArea;
2115
2116 TRACE("(%u, %p, %d, %d)\n", uType, hwndParent, x, y);
2117
2118 if ((uType != SOFTKEYBOARD_TYPE_T1) && (uType != SOFTKEYBOARD_TYPE_C1))
2119 {
2120 ERR("uType: %u\n", uType);
2121 return NULL; /* Invalid keyboard type */
2122 }
2123
2124 /* Check IME */
2125 hKL = GetKeyboardLayout(0);
2126 pImeDpi = ImmLockImeDpi(hKL);
2127 if (IS_NULL_UNEXPECTEDLY(pImeDpi))
2128 return NULL; /* No IME */
2129
2130 UICaps = pImeDpi->ImeInfo.fdwUICaps;
2131 ImmUnlockImeDpi(pImeDpi);
2132
2133 /* Check IME capability */
2134 if (!(UICaps & UI_CAP_SOFTKBD))
2135 {
2136 ERR("UICaps: 0x%X\n", UICaps);
2137 return NULL; /* No capability for soft keyboard */
2138 }
2139
2140 /* Want metrics? */
2141 if (g_bWantSoftKBDMetrics)
2142 {
2143 for (iVK = 0; iVK < 0xFF; ++iVK)
2144 {
2145 guScanCode[iVK] = MapVirtualKeyW(iVK, 0);
2146 }
2147
2148 cxEdge = GetSystemMetrics(SM_CXEDGE);
2149 cyEdge = GetSystemMetrics(SM_CYEDGE);
2150 gptRaiseEdge.x = GetSystemMetrics(SM_CXBORDER) + cxEdge;
2151 gptRaiseEdge.y = GetSystemMetrics(SM_CYBORDER) + cyEdge;
2152
2153 g_bWantSoftKBDMetrics = FALSE;
2154 }
2155
2156 if (!Imm32GetNearestWorkArea(hwndParent, &rcWorkArea))
2157 return NULL;
2158
2159 /* Register the window class */
2160 if (!Imm32RegisterSoftKeyboard(uType))
2161 {
2162 ERR("\n");
2163 return NULL;
2164 }
2165
2166 /* Calculate keyboard size */
2167 Imm32GetSoftKeyboardDimension(uType, &cxSoftKBD, &cySoftKBD);
2168
2169 /* Adjust keyboard position */
2170 xSoftKBD = Imm32Clamp(x, rcWorkArea.left, rcWorkArea.right - cxSoftKBD);
2171 ySoftKBD = Imm32Clamp(y, rcWorkArea.top , rcWorkArea.bottom - cySoftKBD);
2172
2173 /* Create soft keyboard window */
2174 if (uType == SOFTKEYBOARD_TYPE_T1)
2175 {
2176 Style = (WS_POPUP | WS_DISABLED);
2177 ExStyle = 0;
2178 pszClass = T1_CLASSNAMEW;
2179 }
2180 else
2181 {
2182 Style = (WS_POPUP | WS_DISABLED | WS_BORDER);
2183 ExStyle = (WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME);
2184 pszClass = C1_CLASSNAMEW;
2185 }
2186 hwndSoftKBD = CreateWindowExW(ExStyle, pszClass, NULL, Style,
2187 xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD,
2188 hwndParent, NULL, ghImm32Inst, NULL);
2189 /* Initial is hidden */
2190 ShowWindow(hwndSoftKBD, SW_HIDE);
2191 UpdateWindow(hwndSoftKBD);
2192
2193 return hwndSoftKBD;
2194 }
2195
2196 /***********************************************************************
2197 * ImmShowSoftKeyboard (IMM32.@)
2198 *
2199 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImmShowSoftKeyboard.html
2200 */
2201 BOOL WINAPI
ImmShowSoftKeyboard(_In_ HWND hwndSoftKBD,_In_ INT nCmdShow)2202 ImmShowSoftKeyboard(
2203 _In_ HWND hwndSoftKBD,
2204 _In_ INT nCmdShow)
2205 {
2206 TRACE("(%p, %d)\n", hwndSoftKBD, nCmdShow);
2207
2208 if (nCmdShow != SW_HIDE && nCmdShow != SW_SHOWNOACTIVATE)
2209 WARN("nCmdShow %d is unexpected\n", nCmdShow);
2210
2211 return hwndSoftKBD && ShowWindow(hwndSoftKBD, nCmdShow);
2212 }
2213
2214 /***********************************************************************
2215 * ImmDestroySoftKeyboard (IMM32.@)
2216 *
2217 * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImmDestroySoftKeyboard.html
2218 */
2219 BOOL WINAPI
ImmDestroySoftKeyboard(_In_ HWND hwndSoftKBD)2220 ImmDestroySoftKeyboard(
2221 _In_ HWND hwndSoftKBD)
2222 {
2223 TRACE("(%p)\n", hwndSoftKBD);
2224 return DestroyWindow(hwndSoftKBD);
2225 }
2226