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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 2220 ImmDestroySoftKeyboard( 2221 _In_ HWND hwndSoftKBD) 2222 { 2223 TRACE("(%p)\n", hwndSoftKBD); 2224 return DestroyWindow(hwndSoftKBD); 2225 } 2226