https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6783061894743604dd057858f5ae3b1d38f238f7

commit 6783061894743604dd057858f5ae3b1d38f238f7
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Sat Nov 25 18:56:33 2023 +0900
Commit:     GitHub <[email protected]>
CommitDate: Sat Nov 25 18:56:33 2023 +0900

    [IMM32] Implement Soft Keyboard Type C1 (#6036)
    
    Follow-up to #6021. This PR will finish ImmCreateSoftKeyboard 
implementation.
    
    - Add c1key.h to define C1 internal codes.
    - The tests are done, using FreeCJ2004 on Chinese/Taiwanese system.
    
    FreeCJ2004: 
https://web.archive.org/web/20061208204431/http://input.foruto.com/download/Forum/freecj2004.exe
    
    CORE-19268
---
 dll/win32/imm32/c1keys.h  |   64 +++
 dll/win32/imm32/softkbd.c | 1029 ++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 1027 insertions(+), 66 deletions(-)

diff --git a/dll/win32/imm32/c1keys.h b/dll/win32/imm32/c1keys.h
new file mode 100644
index 00000000000..34f1ea3049e
--- /dev/null
+++ b/dll/win32/imm32/c1keys.h
@@ -0,0 +1,64 @@
+/*
+ * PROJECT:     ReactOS IMM32
+ * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
+ * PURPOSE:     Defining internal codes (C1K_...) of IME Soft Keyboard Type C1
+ * COPYRIGHT:   Copyright 2023 Katayama Hirofumi MZ 
<[email protected]>
+ */
+
+/* DEFINE_C1K(c1k_code, virtual_key_code, c1k_code_name, virtual_key_name, 
is_special) */
+DEFINE_C1K( 0, 0xC0, C1K_OEM_3,     VK_OEM_3,      FALSE)
+DEFINE_C1K( 1, 0x31, C1K_1,         VK_1,          FALSE)
+DEFINE_C1K( 2, 0x32, C1K_2,         VK_2,          FALSE)
+DEFINE_C1K( 3, 0x33, C1K_3,         VK_3,          FALSE)
+DEFINE_C1K( 4, 0x34, C1K_4,         VK_4,          FALSE)
+DEFINE_C1K( 5, 0x35, C1K_5,         VK_5,          FALSE)
+DEFINE_C1K( 6, 0x36, C1K_6,         VK_6,          FALSE)
+DEFINE_C1K( 7, 0x37, C1K_7,         VK_7,          FALSE)
+DEFINE_C1K( 8, 0x38, C1K_8,         VK_8,          FALSE)
+DEFINE_C1K( 9, 0x39, C1K_9,         VK_9,          FALSE)
+DEFINE_C1K(10, 0x30, C1K_0,         VK_0,          FALSE)
+DEFINE_C1K(11, 0xBD, C1K_OEM_MINUS, VK_OEM_MINUS,  FALSE)
+DEFINE_C1K(12, 0xBB, C1K_OEM_PLUS,  VK_OEM_PLUS,   FALSE)
+DEFINE_C1K(13, 0x51, C1K_Q,         VK_Q,          FALSE)
+DEFINE_C1K(14, 0x57, C1K_W,         VK_W,          FALSE)
+DEFINE_C1K(15, 0x45, C1K_E,         VK_E,          FALSE)
+DEFINE_C1K(16, 0x52, C1K_R,         VK_R,          FALSE)
+DEFINE_C1K(17, 0x54, C1K_T,         VK_T,          FALSE)
+DEFINE_C1K(18, 0x59, C1K_Y,         VK_Y,          FALSE)
+DEFINE_C1K(19, 0x55, C1K_U,         VK_U,          FALSE)
+DEFINE_C1K(20, 0x49, C1K_I,         VK_I,          FALSE)
+DEFINE_C1K(21, 0x4F, C1K_O,         VK_O,          FALSE)
+DEFINE_C1K(22, 0x50, C1K_P,         VK_P,          FALSE)
+DEFINE_C1K(23, 0xDB, C1K_OEM_4,     VK_OEM_4,      FALSE)
+DEFINE_C1K(24, 0xDD, C1K_OEM_6,     VK_OEM_6,      FALSE)
+DEFINE_C1K(25, 0xDC, C1K_OEM_5,     VK_OEM_5,      FALSE)
+DEFINE_C1K(26, 0x41, C1K_A,         VK_A,          FALSE)
+DEFINE_C1K(27, 0x53, C1K_S,         VK_S,          FALSE)
+DEFINE_C1K(28, 0x44, C1K_D,         VK_D,          FALSE)
+DEFINE_C1K(29, 0x46, C1K_F,         VK_F,          FALSE)
+DEFINE_C1K(30, 0x47, C1K_G,         VK_G,          FALSE)
+DEFINE_C1K(31, 0x48, C1K_H,         VK_H,          FALSE)
+DEFINE_C1K(32, 0x4A, C1K_J,         VK_J,          FALSE)
+DEFINE_C1K(33, 0x4B, C1K_K,         VK_K,          FALSE)
+DEFINE_C1K(34, 0x4C, C1K_L,         VK_L,          FALSE)
+DEFINE_C1K(35, 0xBA, C1K_OEM_1,     VK_OEM_1,      FALSE)
+DEFINE_C1K(36, 0xDE, C1K_OEM_7,     VK_OEM_7,      FALSE)
+DEFINE_C1K(37, 0x5A, C1K_Z,         VK_Z,          FALSE)
+DEFINE_C1K(38, 0x58, C1K_X,         VK_X,          FALSE)
+DEFINE_C1K(39, 0x43, C1K_C,         VK_C,          FALSE)
+DEFINE_C1K(40, 0x56, C1K_V,         VK_V,          FALSE)
+DEFINE_C1K(41, 0x42, C1K_B,         VK_B,          FALSE)
+DEFINE_C1K(42, 0x4E, C1K_N,         VK_N,          FALSE)
+DEFINE_C1K(43, 0x4D, C1K_M,         VK_M,          FALSE)
+DEFINE_C1K(44, 0xBC, C1K_OEM_COMMA, VK_OEM_COMMA,  FALSE)
+DEFINE_C1K(45, 0xBE, C1K_OEM_DOT,   VK_OEM_PERIOD, FALSE)
+DEFINE_C1K(46, 0xBF, C1K_OEM_2,     VK_OEM_2,      FALSE)
+DEFINE_C1K(47, 0x08, C1K_BACKSPACE, VK_BACK,       TRUE)
+DEFINE_C1K(48, 0x09, C1K_TAB,       VK_TAB,        TRUE)
+DEFINE_C1K(49, 0x14, C1K_CAPS,      VK_CAPITAL,    TRUE)
+DEFINE_C1K(50, 0x0D, C1K_ENTER,     VK_RETURN,     TRUE)
+DEFINE_C1K(51, 0x10, C1K_SHIFT,     VK_SHIFT,      TRUE)
+DEFINE_C1K(52, 0x2D, C1K_INSERT,    VK_INSERT,     TRUE)
+DEFINE_C1K(53, 0x2E, C1K_DELETE,    VK_DELETE,     TRUE)
+DEFINE_C1K(54, 0x20, C1K_SPACE,     VK_SPACE,      TRUE)
+DEFINE_C1K(55, 0x1B, C1K_ESCAPE,    VK_ESCAPE,     TRUE)
diff --git a/dll/win32/imm32/softkbd.c b/dll/win32/imm32/softkbd.c
index 8cf17248760..522ff99185c 100644
--- a/dll/win32/imm32/softkbd.c
+++ b/dll/win32/imm32/softkbd.c
@@ -32,6 +32,23 @@ Imm32PtInRect(
     return (x <= ppt->x) && (ppt->x < x + cx) && (y <= ppt->y) && (ppt->y < y 
+ cy);
 }
 
+static void
+Imm32DrawBitmap(
+    _In_ HDC hdc,
+    _In_ INT x,
+    _In_ INT y,
+    _In_ INT width,
+    _In_ INT height,
+    _In_ INT nBitmapID)
+{
+    HBITMAP hBitmap = LoadBitmapW(ghImm32Inst, MAKEINTRESOURCEW(nBitmapID));
+    HDC hMemDC = CreateCompatibleDC(hdc);
+    HGDIOBJ hbmOld = SelectObject(hMemDC, hBitmap);
+    BitBlt(hdc, x, y, width, height, hMemDC, 0, 0, SRCCOPY);
+    DeleteObject(SelectObject(hMemDC, hbmOld));
+    DeleteDC(hMemDC);
+}
+
 static inline INT
 Imm32Clamp(
     _In_ INT x,
@@ -320,24 +337,6 @@ T1_DrawConvexRect(
     PatBlt(hDC, x0 + dx - 1, y + dy - 3, -1, 2 - dy, PATCOPY);
 }
 
-static void
-T1_DrawBitmap(
-    _In_ HDC hDC,
-    _In_ INT x,
-    _In_ INT y,
-    _In_ INT cx,
-    _In_ INT cy,
-    _In_ INT nBitmapID)
-{
-    HBITMAP hBitmap = LoadBitmapW(ghImm32Inst, MAKEINTRESOURCEW(nBitmapID));
-    HDC hMemDC = CreateCompatibleDC(hDC);
-    HGDIOBJ hbmOld = SelectObject(hMemDC, hBitmap);
-    BitBlt(hDC, x, y, cx, cy, hMemDC, 0, 0, SRCCOPY);
-    SelectObject(hMemDC, hbmOld);
-    DeleteObject(hBitmap);
-    DeleteDC(hMemDC);
-}
-
 static void
 T1_DrawLabels(
     _In_ HDC hDC,
@@ -386,46 +385,46 @@ T1_InitBitmap(
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_L_CTRL).x, T1_KEYPOS(T1K_L_CTRL).y,
                       pT1->cxWidth53or54, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth53or54 / 2 + T1_KEYPOS(T1K_L_CTRL).x - 8,
-                  pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_L_CTRL).y - 4,
-                  16, 9, IDB_T1_CTRL);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth53or54 / 2 + T1_KEYPOS(T1K_L_CTRL).x - 8,
+                    pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_L_CTRL).y - 4,
+                    16, 9, IDB_T1_CTRL);
 
     /* 54 --> Right [Ctrl] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_R_CTRL).x, T1_KEYPOS(T1K_R_CTRL).y,
                       pT1->cxWidth53or54, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth53or54 / 2 + T1_KEYPOS(T1K_R_CTRL).x - 8,
-                  pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_R_CTRL).y - 4,
-                  16, 9, IDB_T1_CTRL);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth53or54 / 2 + T1_KEYPOS(T1K_R_CTRL).x - 8,
+                    pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_R_CTRL).y - 4,
+                    16, 9, IDB_T1_CTRL);
 
     /* 57 --> [Esc] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_ESCAPE).x, T1_KEYPOS(T1K_ESCAPE).y,
                       pT1->cxWidth57, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth57   / 2 + T1_KEYPOS(T1K_ESCAPE).x - 9,
-                  pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_ESCAPE).y - 4,
-                  18, 9, IDB_T1_ESCAPE);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth57   / 2 + T1_KEYPOS(T1K_ESCAPE).x - 9,
+                    pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_ESCAPE).y - 4,
+                    18, 9, IDB_T1_ESCAPE);
 
     /* 55 --> Left [Alt] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_L_ALT).x, T1_KEYPOS(T1K_L_ALT).y,
                       pT1->cxWidth55or56, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth55or56 / 2 + T1_KEYPOS(T1K_L_ALT).x - 8,
-                  pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_L_ALT).y - 4,
-                  16, 9, IDB_T1_ALT);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth55or56 / 2 + T1_KEYPOS(T1K_L_ALT).x - 8,
+                    pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_L_ALT).y - 4,
+                    16, 9, IDB_T1_ALT);
 
     /* 56 --> Right [Alt] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_R_ALT).x, T1_KEYPOS(T1K_R_ALT).y,
                       pT1->cxWidth55or56, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth55or56 / 2 + T1_KEYPOS(T1K_R_ALT).x - 8,
-                  pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_R_ALT).y - 4,
-                  16, 9, IDB_T1_ALT);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth55or56 / 2 + T1_KEYPOS(T1K_R_ALT).x - 8,
+                    pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_R_ALT).y - 4,
+                    16, 9, IDB_T1_ALT);
 
     /* 58 --> [Space] */
     T1_DrawConvexRect(hMemDC,
@@ -436,55 +435,55 @@ T1_InitBitmap(
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_L_SHIFT).x, T1_KEYPOS(T1K_L_SHIFT).y,
                       pT1->cxWidth51or52, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth51or52 / 2 + T1_KEYPOS(T1K_L_SHIFT).x - 11,
-                  pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_L_SHIFT).y - 4,
-                  23, 9, IDB_T1_SHIFT);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth51or52 / 2 + T1_KEYPOS(T1K_L_SHIFT).x - 11,
+                    pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_L_SHIFT).y - 4,
+                    23, 9, IDB_T1_SHIFT);
 
     /* 52 --> Right [Shift] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_R_SHIFT).x, T1_KEYPOS(T1K_R_SHIFT).y,
                       pT1->cxWidth51or52, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth51or52 / 2 + T1_KEYPOS(T1K_R_SHIFT).x - 11,
-                  pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_R_SHIFT).y - 4,
-                  23, 9, IDB_T1_SHIFT);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth51or52 / 2 + T1_KEYPOS(T1K_R_SHIFT).x - 11,
+                    pT1->cyDefHeight   / 2 + T1_KEYPOS(T1K_R_SHIFT).y - 4,
+                    23, 9, IDB_T1_SHIFT);
 
     /* 49 --> [Caps] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_CAPS).x, T1_KEYPOS(T1K_CAPS).y,
                       pT1->cxWidth49, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth49   / 2 + T1_KEYPOS(T1K_CAPS).x - 11,
-                  pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_CAPS).y - 4,
-                  22, 9, IDB_T1_CAPS);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth49   / 2 + T1_KEYPOS(T1K_CAPS).x - 11,
+                    pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_CAPS).y - 4,
+                    22, 9, IDB_T1_CAPS);
 
     /* 48 --> [Tab] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_TAB).x, T1_KEYPOS(T1K_TAB).y,
                       pT1->cxWidth48, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth48   / 2 + T1_KEYPOS(T1K_TAB).x - 8,
-                  pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_TAB).y - 4,
-                  16, 9, IDB_T1_TAB);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth48   / 2 + T1_KEYPOS(T1K_TAB).x - 8,
+                    pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_TAB).y - 4,
+                    16, 9, IDB_T1_TAB);
 
     /* 50 --> [Enter] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_ENTER).x, T1_KEYPOS(T1K_ENTER).y,
                       pT1->cxWidth50, pT1->cyHeight50);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth50  / 2 + T1_KEYPOS(T1K_ENTER).x - 13,
-                  pT1->cyHeight50 / 2 + T1_KEYPOS(T1K_ENTER).y - 4,
-                  26, 9, IDB_T1_ENTER);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth50  / 2 + T1_KEYPOS(T1K_ENTER).x - 13,
+                    pT1->cyHeight50 / 2 + T1_KEYPOS(T1K_ENTER).y - 4,
+                    26, 9, IDB_T1_ENTER);
 
     /* 47 --> [BackSpace] */
     T1_DrawConvexRect(hMemDC,
                       T1_KEYPOS(T1K_BACKSPACE).x, T1_KEYPOS(T1K_BACKSPACE).y,
                       pT1->cxWidth47, pT1->cyDefHeight);
-    T1_DrawBitmap(hMemDC,
-                  pT1->cxWidth47   / 2 + T1_KEYPOS(T1K_BACKSPACE).x - 8,
-                  pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_BACKSPACE).y - 4,
-                  16, 9, IDB_T1_BACKSPACE);
+    Imm32DrawBitmap(hMemDC,
+                    pT1->cxWidth47   / 2 + T1_KEYPOS(T1K_BACKSPACE).x - 8,
+                    pT1->cyDefHeight / 2 + T1_KEYPOS(T1K_BACKSPACE).y - 4,
+                    16, 9, IDB_T1_BACKSPACE);
 
     /* Regular keys */
     for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey)
@@ -842,7 +841,7 @@ T1_OnButtonUp(
     iPressed = pT1->PressedKey;
     if (iPressed >= T1K_NONE)
     {
-        if (pT1->pt1.x != -1 && pT1->pt1.y != -1 )
+        if (pT1->pt1.x != -1 && pT1->pt1.y != -1)
         {
             T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1);
             x = pT1->pt0.x - pT1->pt1.x;
@@ -1123,6 +1122,865 @@ T1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, 
LPARAM lParam)
 
 #define C1_CLASSNAMEW L"SoftKBDClsC1"
 
+#define C1K_MAX 56
+
+#undef DEFINE_C1K
+#define DEFINE_C1K(c1k_code, virtual_key_code, c1k_code_name, 
virtual_key_name, is_special) \
+    c1k_code_name = c1k_code,
+
+/* Define C1 internal codes (C1K_...) */
+typedef enum C1KEY
+{
+#include "c1keys.h"
+} C1KEY;
+
+#undef DEFINE_C1K
+#define DEFINE_C1K(c1k_code, virtual_key_code, c1k_code_name, 
virtual_key_name, is_special) \
+    virtual_key_code,
+
+/* Mapping: C1K --> Virtual Key */
+const BYTE gC1K2VK[C1K_MAX] =
+{
+#include "c1keys.h"
+};
+
+typedef struct C1WINDOW
+{
+    WCHAR Data[2][47];
+    DWORD dwFlags;
+    HBITMAP hbmKeyboard;
+    LPARAM SubType;
+    INT iPressedKey;
+    POINT pt1, pt2;
+    DWORD CharSet;
+} C1WINDOW, *PC1WINDOW;
+
+/* The flags for C1WINDOW.dwFlags */
+#define FLAG_SHIFT_PRESSED 1
+#define FLAG_DRAGGING 2
+#define FLAG_PRESSED 4
+
+static BOOL gbC1ButtonInit = FALSE;
+static POINT gptC1ButtonPos[C1K_MAX];
+
+static void C1_InitButtonPos(void)
+{
+    LONG x = 0, y = 0;
+    INT iKey;
+
+    /* 1st row */
+    for (iKey = C1K_OEM_3; iKey < C1K_Q; ++iKey)
+    {
+        gptC1ButtonPos[iKey].x = x;
+        gptC1ButtonPos[iKey].y = y;
+        x += 24;
+    }
+    gptC1ButtonPos[C1K_BACKSPACE].x = x;
+    gptC1ButtonPos[C1K_BACKSPACE].y = y;
+
+    /* 2nd row */
+    y = 28;
+    gptC1ButtonPos[C1K_TAB].x = 0;
+    gptC1ButtonPos[C1K_TAB].y = y;
+    x = 36;
+    for (; iKey < C1K_A; ++iKey)
+    {
+        gptC1ButtonPos[iKey].x = x;
+        gptC1ButtonPos[iKey].y = y;
+        x += 24;
+    }
+
+    /* 3rd row */
+    y = 56;
+    gptC1ButtonPos[C1K_CAPS].x = 0;
+    gptC1ButtonPos[C1K_CAPS].y = y;
+    x = 42;
+    for (; iKey < C1K_Z; ++iKey)
+    {
+        gptC1ButtonPos[iKey].x = x;
+        gptC1ButtonPos[iKey].y = y;
+        x += 24;
+    }
+    gptC1ButtonPos[C1K_ENTER].x = x;
+    gptC1ButtonPos[C1K_ENTER].y = y;
+
+    /* 4th row */
+    y = 84;
+    gptC1ButtonPos[C1K_SHIFT].x = 0;
+    gptC1ButtonPos[C1K_SHIFT].y = y;
+    x = 60;
+    for (; iKey < C1K_BACKSPACE; ++iKey)
+    {
+        gptC1ButtonPos[iKey].x = x;
+        gptC1ButtonPos[iKey].y = y;
+        x += 24;
+    }
+
+    /* 5th row */
+    y = 112;
+    gptC1ButtonPos[C1K_INSERT].x = 0;
+    gptC1ButtonPos[C1K_INSERT].y = y;
+    gptC1ButtonPos[C1K_DELETE].x = 58;
+    gptC1ButtonPos[C1K_DELETE].y = y;
+    gptC1ButtonPos[C1K_SPACE].x = 96;
+    gptC1ButtonPos[C1K_SPACE].y = y;
+    gptC1ButtonPos[C1K_ESCAPE].x = 310;
+    gptC1ButtonPos[C1K_ESCAPE].y = y;
+}
+
+static void
+C1_DrawConvexRect(
+    _In_ HDC hDC,
+    _In_ INT x,
+    _In_ INT y,
+    _In_ INT width,
+    _In_ INT height)
+{
+    HGDIOBJ hLtGrayBrush = GetStockObject(LTGRAY_BRUSH);
+    HGDIOBJ hBlackPen = GetStockObject(BLACK_PEN);
+    HGDIOBJ hWhiteBrush = GetStockObject(WHITE_BRUSH);
+    HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH);
+    INT y2 = y + height - 1;
+
+    /* Draw face */
+    SelectObject(hDC, hLtGrayBrush);
+    SelectObject(hDC, hBlackPen);
+    Rectangle(hDC, x, y, x + width, y + height);
+
+    /* Draw light edge */
+    SelectObject(hDC, hWhiteBrush);
+    PatBlt(hDC, x, y2, 2, 1 - height, PATCOPY);
+    PatBlt(hDC, x, y, width - 1, 2, PATCOPY);
+
+    /* Draw dark edge */
+    SelectObject(hDC, hGrayBrush);
+    PatBlt(hDC, x + 1, y2, width - 2, -1, PATCOPY);
+    PatBlt(hDC, x + width - 1, y2, -1, 2 - height, PATCOPY);
+}
+
+static void
+C1_InvertButton(
+    _In_ HDC hDC,
+    _In_ INT iKey)
+{
+    INT width = 24, height = 28;
+
+    if (iKey < 0)
+        return;
+
+    switch (iKey)
+    {
+        case C1K_BACKSPACE: case C1K_TAB:
+            width = 36;
+            break;
+        case C1K_CAPS: case C1K_ENTER:
+            width = 42;
+            break;
+        case C1K_SHIFT:
+            width = 60;
+            break;
+        case C1K_INSERT: case C1K_DELETE: case C1K_ESCAPE:
+            width = 38;
+            height = 24;
+            break;
+        case C1K_SPACE:
+            width = 172;
+            height = 24;
+            break;
+        default:
+            break;
+    }
+
+    BitBlt(hDC, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, width, height,
+           hDC, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, DSTINVERT);
+}
+
+static void
+C1_DrawLabel(
+    _In_ HDC hDC,
+    _In_ INT nBitmapID)
+{
+    HBITMAP hBitmap;
+    HGDIOBJ hbmOld;
+    HDC hMemDC;
+    INT iKey;
+
+    hBitmap = LoadBitmapW(ghImm32Inst, MAKEINTRESOURCEW(nBitmapID));
+    hMemDC = CreateCompatibleDC(hDC);
+    hbmOld = SelectObject(hMemDC, hBitmap);
+    for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
+    {
+        BitBlt(hDC, gptC1ButtonPos[iKey].x + 2, gptC1ButtonPos[iKey].y + 2, 8, 
8,
+               hMemDC, iKey * 8, 0, SRCCOPY);
+    }
+    DeleteObject(SelectObject(hMemDC, hbmOld));
+    DeleteDC(hMemDC);
+}
+
+static void
+C1_InitBitmap(
+    _In_ HDC hDC,
+    _In_ INT x,
+    _In_ INT y,
+    _In_ INT width,
+    _In_ INT height)
+{
+    HGDIOBJ hLtGrayBrush = GetStockObject(LTGRAY_BRUSH);
+    HGDIOBJ hNullPen = GetStockObject(NULL_PEN);
+    INT iKey;
+
+    /* Draw keyboard frame */
+    SelectObject(hDC, hLtGrayBrush);
+    SelectObject(hDC, hNullPen);
+    Rectangle(hDC, x, y, width + 1, height + 1);
+
+    for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
+    {
+        C1_DrawConvexRect(hDC, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, 
24, 28);
+    }
+
+    C1_DrawLabel(hDC, IDB_C1_CHARS);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_BACKSPACE].x, 
gptC1ButtonPos[C1K_BACKSPACE].y, 36, 28);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_BACKSPACE].x + 2, 
gptC1ButtonPos[C1K_BACKSPACE].y + 2, 32, 24, IDB_C1_BACKSPACE);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_TAB].x, 
gptC1ButtonPos[C1K_TAB].y, 36, 28);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_TAB].x + 2, 
gptC1ButtonPos[C1K_TAB].y + 2, 32, 24, IDB_C1_TAB);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_CAPS].x, 
gptC1ButtonPos[C1K_CAPS].y, 42, 28);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_CAPS].x + 2, 
gptC1ButtonPos[C1K_CAPS].y + 2, 38, 24, IDB_C1_CAPS);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_ENTER].x, 
gptC1ButtonPos[C1K_ENTER].y, 42, 28);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_ENTER].x + 2, 
gptC1ButtonPos[C1K_ENTER].y + 2, 38, 24, IDB_C1_ENTER);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_SHIFT].x, 
gptC1ButtonPos[C1K_SHIFT].y, 60, 28);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_SHIFT].x + 2, 
gptC1ButtonPos[C1K_SHIFT].y + 2, 56, 24, IDB_C1_SHIFT);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_INSERT].x, 
gptC1ButtonPos[C1K_INSERT].y, 38, 24);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_INSERT].x + 2, 
gptC1ButtonPos[C1K_INSERT].y + 2, 34, 20, IDB_C1_INS);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_DELETE].x, 
gptC1ButtonPos[C1K_DELETE].y, 38, 24);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_DELETE].x + 2, 
gptC1ButtonPos[C1K_DELETE].y + 2, 34, 20, IDB_C1_DEL);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_SPACE].x, 
gptC1ButtonPos[C1K_SPACE].y, 172, 24);
+
+    C1_DrawConvexRect(hDC, gptC1ButtonPos[C1K_ESCAPE].x, 
gptC1ButtonPos[C1K_ESCAPE].y , 38, 24);
+    Imm32DrawBitmap(hDC, gptC1ButtonPos[C1K_ESCAPE].x + 2, 
gptC1ButtonPos[C1K_ESCAPE].y + 2, 34, 20, IDB_C1_ESCAPE);
+}
+
+static INT
+C1_OnCreate(
+    _In_ HWND hWnd)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    HDC hDC, hMemDC;
+    RECT rc;
+    HGDIOBJ hbmOld;
+    HBITMAP hbmKeyboard;
+
+    hGlobal = GlobalAlloc(GHND, sizeof(C1WINDOW));
+    if (!hGlobal)
+        return -1;
+
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!pC1)
+    {
+        GlobalFree(hGlobal);
+        return -1;
+    }
+    SetWindowLongPtrW(hWnd, 0, (LONG_PTR)hGlobal);
+
+    if (!gbC1ButtonInit)
+    {
+        C1_InitButtonPos();
+        gbC1ButtonInit = TRUE;
+    }
+
+    pC1->iPressedKey = -1;
+    pC1->CharSet = GB2312_CHARSET;
+
+    GetClientRect(hWnd, &rc);
+
+    hDC = GetDC(hWnd);
+    hMemDC = CreateCompatibleDC(hDC);
+    hbmKeyboard = CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - 
rc.top);
+    ReleaseDC(hWnd, hDC);
+
+    hbmOld = SelectObject(hMemDC, hbmKeyboard);
+    C1_InitBitmap(hMemDC, rc.left, rc.top, rc.right, rc.bottom);
+    SelectObject(hMemDC, hbmOld);
+    pC1->hbmKeyboard = hbmKeyboard;
+    DeleteDC(hMemDC);
+
+    GlobalUnlock(hGlobal);
+    return 0;
+}
+
+static void
+C1_OnDraw(
+    _In_ HDC hDC,
+    _In_ HWND hWnd)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    HDC hMemDC;
+    RECT rc;
+    HGDIOBJ hbmOld;
+
+    hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!hGlobal || !pC1)
+        return;
+
+    GetClientRect(hWnd, &rc);
+
+    hMemDC = CreateCompatibleDC(hDC);
+    hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
+    BitBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 0, 0, 
SRCCOPY);
+    SelectObject(hMemDC, hbmOld);
+    DeleteDC(hMemDC);
+
+    GlobalUnlock(hGlobal);
+}
+
+static BOOL
+C1_SetData(
+    _In_ HWND hWnd,
+    _In_ const SOFTKBDDATA *pData)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    HDC hDC, hMemDC;
+    INT iKey;
+    BOOL bDisabled;
+    HBITMAP hbmKeyboard;
+    HGDIOBJ hbmOld, hFontOld;
+    HFONT hFont;
+    RECT rc;
+    LOGFONTW lf;
+
+    if (pData->uCount != 2)
+        return 0;
+
+    hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!hGlobal || !pC1)
+        return FALSE;
+
+    hDC = GetDC(hWnd);
+    hMemDC = CreateCompatibleDC(hDC);
+
+    hbmKeyboard = pC1->hbmKeyboard;
+    hbmOld = SelectObject(hMemDC, hbmKeyboard);
+
+    GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(lf), &lf);
+    lf.lfHeight = -12;
+    if (pC1->CharSet != DEFAULT_CHARSET)
+        lf.lfCharSet = (BYTE)pC1->CharSet;
+
+    hFont = CreateFontIndirectW(&lf);
+    hFontOld = SelectObject(hMemDC, hFont);
+    for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
+    {
+        pC1->Data[1][iKey] = pData->wCode[0][(BYTE)gC1K2VK[iKey]];
+        pC1->Data[0][iKey] = pData->wCode[1][(BYTE)gC1K2VK[iKey]];
+    }
+
+    SetBkColor(hMemDC, RGB(191, 191, 191));
+    for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
+    {
+        /* Upper right */
+        rc.right = gptC1ButtonPos[iKey].x + 24 - 2;
+        rc.top = gptC1ButtonPos[iKey].y + 2;
+        rc.left = rc.right - 14;
+        rc.bottom = rc.top + 14;
+        bDisabled = (pC1->Data[0][iKey] == 0);
+        DrawTextW(hMemDC, &pC1->Data[0][iKey], !bDisabled, &rc,
+                  DT_RIGHT | DT_TOP | DT_SINGLELINE);
+
+        /* Lower left */
+        rc.left = gptC1ButtonPos[iKey].x + 2;
+        rc.bottom = gptC1ButtonPos[iKey].y + 28 - 2;
+        rc.right = rc.left + 14;
+        rc.top = rc.bottom - 14;
+        bDisabled = (pC1->Data[1][iKey] == 0);
+        DrawTextW(hMemDC, &pC1->Data[1][iKey], !bDisabled, &rc,
+                  DT_LEFT | DT_BOTTOM | DT_SINGLELINE);
+    }
+
+    if (pC1->dwFlags & FLAG_SHIFT_PRESSED)
+        C1_InvertButton(hMemDC, C1K_SHIFT);
+
+    pC1->dwFlags = 0;
+
+    SelectObject(hMemDC, hbmOld);
+    DeleteObject(SelectObject(hMemDC, hFontOld));
+
+    DeleteDC(hMemDC);
+    ReleaseDC(hWnd, hDC);
+
+    GlobalUnlock(hGlobal);
+    return TRUE;
+}
+
+static void
+C1_DrawDragBorder(
+    _In_ HWND hWnd,
+    _In_ LPPOINT ppt1,
+    _Inout_ LPPOINT ppt2)
+{
+    HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH);
+    INT x, y;
+    RECT rc, rcWork;
+    INT cxBorder = GetSystemMetrics(SM_CXBORDER), cyBorder = 
GetSystemMetrics(SM_CYBORDER);
+    HDC hDisplayDC;
+
+    Imm32GetAllMonitorSize(&rcWork);
+    hDisplayDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
+
+    SelectObject(hDisplayDC, hGrayBrush);
+    x = ppt1->x - ppt2->x;
+    y = ppt1->y - ppt2->y;
+    if (x < rcWork.left)
+        x = rcWork.left;
+    if (y < rcWork.top)
+        y = rcWork.top;
+
+    GetWindowRect(hWnd, &rc);
+
+    if (rc.right - rc.left + x > rcWork.right)
+        x = rc.left + rcWork.right - rc.right;
+    if (y + rc.bottom - rc.top > rcWork.bottom)
+        y = rc.top + rcWork.bottom - rc.bottom;
+
+    ppt2->x = ppt1->x - x;
+    ppt2->y = ppt1->y - y;
+
+    PatBlt(hDisplayDC, x, y, rc.right - rc.left - cxBorder, cyBorder, 
PATINVERT);
+    PatBlt(hDisplayDC, x, y + cyBorder, cxBorder, rc.bottom - rc.top - 
cyBorder, PATINVERT);
+    PatBlt(hDisplayDC, x + cxBorder, y + rc.bottom - rc.top, rc.right - 
rc.left - cxBorder, -cyBorder, PATINVERT);
+    PatBlt(hDisplayDC, x + rc.right - rc.left, y, -cxBorder, rc.bottom - 
rc.top - cyBorder, PATINVERT);
+
+    DeleteDC(hDisplayDC);
+}
+
+static INT
+C1_HitTest(
+    _In_ const POINT *ppt)
+{
+    INT iKey;
+
+    for (iKey = C1K_OEM_3; iKey < C1K_BACKSPACE; ++iKey)
+    {
+        if (Imm32PtInRect(ppt, gptC1ButtonPos[iKey].x, gptC1ButtonPos[iKey].y, 
24, 28))
+            return iKey;
+    }
+
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_BACKSPACE].x, 
gptC1ButtonPos[C1K_BACKSPACE].y, 36, 28))
+        return C1K_BACKSPACE;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_TAB].x, 
gptC1ButtonPos[C1K_TAB].y, 36, 28))
+        return C1K_TAB;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_CAPS].x, 
gptC1ButtonPos[C1K_CAPS].y, 42, 28))
+        return C1K_CAPS;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_ENTER].x, 
gptC1ButtonPos[C1K_ENTER].y, 42, 28))
+        return C1K_ENTER;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_SHIFT].x, 
gptC1ButtonPos[C1K_SHIFT].y, 60, 28))
+        return C1K_SHIFT;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_ESCAPE].x, 
gptC1ButtonPos[C1K_ESCAPE].y, 38, 24))
+        return C1K_ESCAPE;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_SPACE].x, 
gptC1ButtonPos[C1K_SPACE].y, 172, 24))
+        return C1K_SPACE;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_INSERT].x, 
gptC1ButtonPos[C1K_INSERT].y, 38, 24))
+        return C1K_INSERT;
+    if (Imm32PtInRect(ppt, gptC1ButtonPos[C1K_DELETE].x, 
gptC1ButtonPos[C1K_DELETE].y, 38, 24))
+        return C1K_DELETE;
+
+    return -1;
+}
+
+static void
+C1_OnButtonDown(
+    _In_ HWND hWnd,
+    _Inout_ PC1WINDOW pC1)
+{
+    INT iPressedKey;
+    HDC hMemDC;
+    WCHAR wch = 0xFF;
+    HGDIOBJ hbmOld;
+    HDC hDC;
+
+    SetCapture(hWnd);
+
+    iPressedKey = pC1->iPressedKey;
+    if (iPressedKey == -1)
+    {
+        pC1->dwFlags |= FLAG_DRAGGING;
+        C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
+        return;
+    }
+
+    if (iPressedKey < C1K_BACKSPACE)
+    {
+        wch = pC1->Data[!(pC1->dwFlags & 1)][iPressedKey];
+        if (!wch)
+        {
+            MessageBeep(0xFFFFFFFF);
+            pC1->iPressedKey = -1;
+            return;
+        }
+    }
+
+    if ((iPressedKey != C1K_SHIFT) || !(pC1->dwFlags & FLAG_SHIFT_PRESSED))
+    {
+        hDC = GetDC(hWnd);
+        hMemDC = CreateCompatibleDC(hDC);
+        hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
+        C1_InvertButton(hDC, pC1->iPressedKey);
+        C1_InvertButton(hMemDC, pC1->iPressedKey);
+        SelectObject(hMemDC, hbmOld);
+        DeleteDC(hMemDC);
+        ReleaseDC(hWnd, hDC);
+    }
+
+    pC1->dwFlags |= FLAG_PRESSED;
+}
+
+static BOOL
+C1_OnSetCursor(
+    _In_ HWND hWnd,
+    _In_ LPARAM lParam)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    HCURSOR hCursor;
+    INT iKey;
+    POINT pt1, pt2;
+
+    hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!hGlobal || !pC1)
+        return FALSE;
+
+    if (pC1->dwFlags & FLAG_DRAGGING)
+    {
+        hCursor = LoadCursorW(0, (LPCWSTR)IDC_SIZEALL);
+        SetCursor(hCursor);
+        GlobalUnlock(hGlobal);
+        return TRUE;
+    }
+
+    GetCursorPos(&pt1);
+    pt2 = pt1;
+    ScreenToClient(hWnd, &pt2);
+
+    iKey = C1_HitTest(&pt2);
+    if (iKey == -1)
+        hCursor = LoadCursorW(0, (LPCWSTR)IDC_SIZEALL);
+    else
+        hCursor = LoadCursorW(0, (LPCWSTR)IDC_HAND);
+    SetCursor(hCursor);
+
+    if (HIWORD(lParam) == WM_LBUTTONDOWN)
+    {
+        pC1->pt1 = pt1;
+        pC1->pt2 = pt2;
+        pC1->iPressedKey = iKey;
+        C1_OnButtonDown(hWnd, pC1);
+    }
+
+    GlobalUnlock(hGlobal);
+    return TRUE;
+}
+
+static BOOL
+C1_OnMouseMove(
+    _In_ HWND hWnd,
+    _In_ WPARAM wParam,
+    _In_ LPARAM lParam)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    HDC hMemDC;
+    DWORD dwFlags;
+    INT iPressedKey;
+    POINT pt;
+    HGDIOBJ hbmOld;
+    HDC hDC;
+    INT iKey;
+
+    hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!hGlobal || !pC1)
+        return FALSE;
+
+    if (pC1->dwFlags & FLAG_DRAGGING)
+    {
+        C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
+        GetCursorPos(&pC1->pt1);
+        C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
+        GlobalUnlock(hGlobal);
+        return TRUE;
+    }
+
+    if (pC1->iPressedKey != -1)
+    {
+        GetCursorPos(&pt);
+        ScreenToClient(hWnd, &pt);
+        iKey = C1_HitTest(&pt);
+
+        hDC = GetDC(hWnd);
+        hMemDC = CreateCompatibleDC(hDC);
+        hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
+        dwFlags = pC1->dwFlags;
+
+        iPressedKey = pC1->iPressedKey;
+        if (!!(dwFlags & FLAG_PRESSED) == (iKey != iPressedKey))
+        {
+            if (iPressedKey != C1K_SHIFT || !(dwFlags & FLAG_SHIFT_PRESSED))
+            {
+                C1_InvertButton(hDC, iPressedKey);
+                C1_InvertButton(hMemDC, pC1->iPressedKey);
+            }
+
+            pC1->dwFlags ^= FLAG_PRESSED;
+        }
+
+        SelectObject(hMemDC, hbmOld);
+        DeleteDC(hMemDC);
+        ReleaseDC(hWnd, hDC);
+    }
+
+    GlobalUnlock(hGlobal);
+    return TRUE;
+}
+
+static BOOL
+C1_OnButtonUp(
+    _In_ HWND hWnd,
+    _In_ WPARAM wParam,
+    _In_ LPARAM lParam)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    BOOL ret = FALSE;
+    INT x, y, iKey;
+    HDC hDC, hMemDC;
+    HGDIOBJ hbmOld;
+    HIMC hIMC;
+    HWND hwndOwner;
+    LPINPUTCONTEXT pIC;
+
+    hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!hGlobal || !pC1)
+        return FALSE;
+
+    ReleaseCapture();
+
+    if (pC1->dwFlags & FLAG_DRAGGING)
+    {
+        pC1->dwFlags &= ~FLAG_DRAGGING;
+        C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
+        x = pC1->pt1.x - pC1->pt2.x;
+        y = pC1->pt1.y - pC1->pt2.y;
+        SetWindowPos(hWnd, 0, x, y, 0, 0, 0x15u);
+        ret = TRUE;
+
+        hwndOwner = GetWindow(hWnd, GW_OWNER);
+        hIMC = (HIMC)GetWindowLongPtrW(hwndOwner, 0);
+        if (hIMC)
+        {
+            pIC = ImmLockIMC(hIMC);
+            if (pIC)
+            {
+                pIC->fdwInit |= INIT_SOFTKBDPOS;
+                pIC->ptSoftKbdPos.x = x;
+                pIC->ptSoftKbdPos.y = y;
+                ImmUnlockIMC(hIMC);
+            }
+        }
+
+        GlobalUnlock(hGlobal);
+        return ret;
+    }
+
+    iKey = pC1->iPressedKey;
+    if (iKey == -1)
+        return FALSE;
+
+    if (!(pC1->dwFlags & FLAG_PRESSED))
+    {
+        pC1->iPressedKey = -1;
+        GlobalUnlock(hGlobal);
+        return ret;
+    }
+
+    if (iKey == C1K_SHIFT)
+    {
+        if (!(pC1->dwFlags & FLAG_SHIFT_PRESSED))
+        {
+            pC1->dwFlags |= FLAG_SHIFT_PRESSED;
+            pC1->dwFlags &= ~FLAG_PRESSED;
+            pC1->iPressedKey = -1;
+            GlobalUnlock(hGlobal);
+            return ret;
+        }
+    }
+    else if (iKey < C1K_BACKSPACE && (pC1->dwFlags & FLAG_SHIFT_PRESSED))
+    {
+        INT iVK = gC1K2VK[pC1->iPressedKey];
+        keybd_event(VK_SHIFT, guScanCode[C1K_SHIFT], 0, 0);
+        keybd_event(iVK, guScanCode[(BYTE)iVK], 0, 0);
+        keybd_event(iVK, guScanCode[(BYTE)iVK], KEYEVENTF_KEYUP, 0);
+        keybd_event(VK_SHIFT, guScanCode[C1K_SHIFT], KEYEVENTF_KEYUP, 0);
+    }
+    else
+    {
+        INT iVK = gC1K2VK[iKey];
+        keybd_event(iVK, guScanCode[iVK], 0, 0);
+        keybd_event(iVK, guScanCode[iVK], KEYEVENTF_KEYUP, 0);
+    }
+
+    ret = TRUE;
+
+    hDC = GetDC(hWnd);
+    hMemDC = CreateCompatibleDC(hDC);
+    hbmOld = SelectObject(hMemDC, pC1->hbmKeyboard);
+
+    C1_InvertButton(hDC, pC1->iPressedKey);
+    C1_InvertButton(hMemDC, pC1->iPressedKey);
+
+    if (pC1->iPressedKey < C1K_BACKSPACE && (pC1->dwFlags & 
FLAG_SHIFT_PRESSED))
+    {
+        C1_InvertButton(hDC, C1K_SHIFT);
+        C1_InvertButton(hMemDC, C1K_SHIFT);
+    }
+
+    if (pC1->iPressedKey < C1K_BACKSPACE || pC1->iPressedKey == C1K_SHIFT)
+        pC1->dwFlags &= ~FLAG_SHIFT_PRESSED;
+
+    SelectObject(hMemDC, hbmOld);
+    DeleteDC(hMemDC);
+    ReleaseDC(hWnd, hDC);
+
+    pC1->dwFlags &= ~FLAG_PRESSED;
+    pC1->iPressedKey = -1;
+    GlobalUnlock(hGlobal);
+    return ret;
+}
+
+static void
+C1_OnDestroy(
+    _In_ HWND hWnd)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    HWND hwndOwner;
+
+    hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+    pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+    if (!hGlobal || !pC1)
+        return;
+
+    if (pC1->dwFlags & FLAG_DRAGGING)
+        C1_DrawDragBorder(hWnd, &pC1->pt1, &pC1->pt2);
+
+    DeleteObject(pC1->hbmKeyboard);
+    GlobalUnlock(hGlobal);
+    GlobalFree(hGlobal);
+
+    hwndOwner = GetWindow(hWnd, GW_OWNER);
+    if (hwndOwner)
+        SendMessageW(hwndOwner, WM_IME_NOTIFY, IMN_SOFTKBDDESTROYED, 0);
+}
+
+static LRESULT
+C1_OnImeControl(
+    _In_ HWND hWnd,
+    _In_ WPARAM wParam,
+    _In_ LPARAM lParam)
+{
+    HGLOBAL hGlobal;
+    PC1WINDOW pC1;
+    LOGFONTW lf;
+    RECT rc;
+    LRESULT ret = 0;
+    HDC hDC;
+
+    switch (wParam)
+    {
+        case IMC_GETSOFTKBDFONT:
+        {
+            TRACE("IMC_GETSOFTKBDFONT: %p\n", lParam);
+            hDC = GetDC(hWnd);
+            GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), 
&lf);
+            ReleaseDC(hWnd, hDC);
+            *(LPLOGFONTW)lParam = lf;
+            break;
+        }
+        case IMC_SETSOFTKBDFONT:
+        {
+            LPLOGFONTW plf = (LPLOGFONTW)lParam;
+            LOGFONTW lf;
+            TRACE("IMC_SETSOFTKBDFONT: %p\n", lParam);
+            GetObjectW(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONTW), 
&lf);
+            if (lf.lfCharSet == plf->lfCharSet)
+                return 0;
+
+            hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+            pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+            if (!hGlobal || !pC1)
+                return 1;
+
+            pC1->CharSet = plf->lfCharSet;
+            GlobalUnlock(hGlobal);
+            break;
+        }
+        case IMC_GETSOFTKBDPOS:
+        {
+            TRACE("IMC_GETSOFTKBDPOS\n");
+            GetWindowRect(hWnd, &rc);
+            return MAKELRESULT(rc.left, rc.top);
+        }
+        case IMC_SETSOFTKBDPOS:
+        {
+            POINT pt;
+            POINTSTOPOINT(pt, lParam);
+            TRACE("IMC_SETSOFTKBDPOS: %d, %d\n", pt.x, pt.y);
+            SetWindowPos(hWnd, NULL, pt.x, pt.y, 0, 0,
+                         (SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE));
+            break;
+        }
+        case IMC_GETSOFTKBDSUBTYPE:
+        case IMC_SETSOFTKBDSUBTYPE:
+        {
+            TRACE("IMC_GETSOFTKBDSUBTYPE/IMC_SETSOFTKBDSUBTYPE: %p, %p\n", 
wParam, lParam);
+            hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0);
+            pC1 = (PC1WINDOW)GlobalLock(hGlobal);
+            if (!hGlobal || !pC1)
+                return -1;
+            ret = pC1->SubType;
+            if (wParam == IMC_SETSOFTKBDSUBTYPE)
+                pC1->SubType = lParam;
+            GlobalUnlock(hGlobal);
+            break;
+        }
+        case IMC_SETSOFTKBDDATA:
+        {
+            TRACE("IMC_SETSOFTKBDDATA: %p\n", lParam);
+            if (C1_SetData(hWnd, (SOFTKBDDATA*)lParam))
+                return -1;
+
+            InvalidateRect(hWnd, 0, 0);
+        }
+        default:
+            break;
+    }
+
+    return ret;
+}
+
 static LRESULT CALLBACK
 C1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 {
@@ -1130,10 +1988,47 @@ C1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, 
LPARAM lParam)
     {
         case WM_CREATE:
         {
-            FIXME("stub\n");
-            return -1;
+            return C1_OnCreate(hWnd);
+        }
+        case WM_DESTROY:
+        {
+            C1_OnDestroy(hWnd);
+            break;
+        }
+        case WM_SETCURSOR:
+        {
+            if (C1_OnSetCursor(hWnd, lParam))
+                break;
+            return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+        }
+        case WM_MOUSEMOVE:
+        {
+            if (C1_OnMouseMove(hWnd, wParam, lParam))
+                break;
+            return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+        }
+        case WM_LBUTTONUP:
+        {
+            if (C1_OnButtonUp(hWnd, wParam, lParam))
+                break;
+            return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+        }
+        case WM_PAINT:
+        {
+            PAINTSTRUCT ps;
+            HDC hDC = BeginPaint(hWnd, &ps);
+            C1_OnDraw(hDC, hWnd);
+            EndPaint(hWnd, &ps);
+            break;
+        }
+        case WM_IME_CONTROL:
+        {
+            return C1_OnImeControl(hWnd, wParam, lParam);
+        }
+        case WM_MOUSEACTIVATE:
+        {
+            return MA_NOACTIVATE;
         }
-
         default:
         {
             return DefWindowProcW(hWnd, uMsg, wParam, lParam);
@@ -1218,6 +2113,8 @@ ImmCreateSoftKeyboard(
     LPCWSTR pszClass;
     RECT rcWorkArea;
 
+    TRACE("(%u, %p, %d, %d)\n", uType, hwndParent, x, y);
+
     if ((uType != SOFTKEYBOARD_TYPE_T1) && (uType != SOFTKEYBOARD_TYPE_C1))
     {
         ERR("uType: %u\n", uType);

Reply via email to