diff --git a/dll/win32/imm32/CMakeLists.txt b/dll/win32/imm32/CMakeLists.txt index d5b2ea12af4..b765ec172ab 100644 --- a/dll/win32/imm32/CMakeLists.txt +++ b/dll/win32/imm32/CMakeLists.txt @@ -22,8 +22,29 @@ list(APPEND SOURCE ${CMAKE_CURRENT_BINARY_DIR}/imm32_stubs.c ${CMAKE_CURRENT_BINARY_DIR}/imm32.def) -add_library(imm32 MODULE ${SOURCE} version.rc) +list(APPEND imm32_rc_deps + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_100.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_101.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_102.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_103.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_104.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_105.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_106.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_107.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/1033_Bitmap_108.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_201.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_202.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_203.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_204.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_205.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_206.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_207.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_208.bmp + ${CMAKE_CURRENT_SOURCE_DIR}/res/2052_Bitmap_209.bmp) + +add_library(imm32 MODULE ${SOURCE} imm32.rc) set_module_type(imm32 win32dll UNICODE ENTRYPOINT ImmDllInitialize 12) +set_source_files_properties(imm32.rc PROPERTIES OBJECT_DEPENDS "${imm32_rc_deps}") target_link_libraries(imm32 wine win32ksys) add_importlibs(imm32 advapi32 user32 gdi32 kernel32 ntdll) add_cd_file(TARGET imm32 DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/imm32/version.rc b/dll/win32/imm32/imm32.rc similarity index 51% rename from dll/win32/imm32/version.rc rename to dll/win32/imm32/imm32.rc index ae821025c01..317f986b7f2 100644 --- a/dll/win32/imm32/version.rc +++ b/dll/win32/imm32/imm32.rc @@ -24,3 +24,29 @@ #define WINE_PRODUCTVERSION_STR "5.1.2600.2180" #include "wine/wine_common_ver.rc" + +#include "resource.h" + +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL + +IDB_T1_BACKSPACE BITMAP "res/1033_Bitmap_100.bmp" +IDB_T1_TAB BITMAP "res/1033_Bitmap_101.bmp" +IDB_T1_CAPS BITMAP "res/1033_Bitmap_102.bmp" +IDB_T1_ENTER BITMAP "res/1033_Bitmap_103.bmp" +IDB_T1_SHIFT BITMAP "res/1033_Bitmap_104.bmp" +IDB_T1_CTRL BITMAP "res/1033_Bitmap_105.bmp" +IDB_T1_ESCAPE BITMAP "res/1033_Bitmap_106.bmp" +IDB_T1_ALT BITMAP "res/1033_Bitmap_107.bmp" +IDB_T1_CHARS BITMAP "res/1033_Bitmap_108.bmp" + +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED + +IDB_C1_BACKSPACE BITMAP "res/2052_Bitmap_201.bmp" +IDB_C1_TAB BITMAP "res/2052_Bitmap_202.bmp" +IDB_C1_CAPS BITMAP "res/2052_Bitmap_203.bmp" +IDB_C1_ENTER BITMAP "res/2052_Bitmap_204.bmp" +IDB_C1_SHIFT BITMAP "res/2052_Bitmap_205.bmp" +IDB_C1_INS BITMAP "res/2052_Bitmap_206.bmp" +IDB_C1_DEL BITMAP "res/2052_Bitmap_207.bmp" +IDB_C1_ESCAPE BITMAP "res/2052_Bitmap_208.bmp" +IDB_C1_CHARS BITMAP "res/2052_Bitmap_209.bmp" diff --git a/dll/win32/imm32/res/1033_Bitmap_100.bmp b/dll/win32/imm32/res/1033_Bitmap_100.bmp new file mode 100644 index 00000000000..79684fd689d Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_100.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_101.bmp b/dll/win32/imm32/res/1033_Bitmap_101.bmp new file mode 100644 index 00000000000..25cbf71f15c Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_101.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_102.bmp b/dll/win32/imm32/res/1033_Bitmap_102.bmp new file mode 100644 index 00000000000..063dbf4361b Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_102.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_103.bmp b/dll/win32/imm32/res/1033_Bitmap_103.bmp new file mode 100644 index 00000000000..44fdf073c2f Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_103.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_104.bmp b/dll/win32/imm32/res/1033_Bitmap_104.bmp new file mode 100644 index 00000000000..384b6cae779 Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_104.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_105.bmp b/dll/win32/imm32/res/1033_Bitmap_105.bmp new file mode 100644 index 00000000000..49dc2b9bc84 Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_105.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_106.bmp b/dll/win32/imm32/res/1033_Bitmap_106.bmp new file mode 100644 index 00000000000..01890744f87 Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_106.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_107.bmp b/dll/win32/imm32/res/1033_Bitmap_107.bmp new file mode 100644 index 00000000000..755312a30fc Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_107.bmp differ diff --git a/dll/win32/imm32/res/1033_Bitmap_108.bmp b/dll/win32/imm32/res/1033_Bitmap_108.bmp new file mode 100644 index 00000000000..d98a6107674 Binary files /dev/null and b/dll/win32/imm32/res/1033_Bitmap_108.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_201.bmp b/dll/win32/imm32/res/2052_Bitmap_201.bmp new file mode 100644 index 00000000000..d38078fa5bd Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_201.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_202.bmp b/dll/win32/imm32/res/2052_Bitmap_202.bmp new file mode 100644 index 00000000000..ea86471d6f4 Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_202.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_203.bmp b/dll/win32/imm32/res/2052_Bitmap_203.bmp new file mode 100644 index 00000000000..d2def3fe5a7 Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_203.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_204.bmp b/dll/win32/imm32/res/2052_Bitmap_204.bmp new file mode 100644 index 00000000000..b40316891af Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_204.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_205.bmp b/dll/win32/imm32/res/2052_Bitmap_205.bmp new file mode 100644 index 00000000000..6a3e43bea2e Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_205.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_206.bmp b/dll/win32/imm32/res/2052_Bitmap_206.bmp new file mode 100644 index 00000000000..f86ae147591 Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_206.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_207.bmp b/dll/win32/imm32/res/2052_Bitmap_207.bmp new file mode 100644 index 00000000000..baa4c76d272 Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_207.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_208.bmp b/dll/win32/imm32/res/2052_Bitmap_208.bmp new file mode 100644 index 00000000000..e29b9c40973 Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_208.bmp differ diff --git a/dll/win32/imm32/res/2052_Bitmap_209.bmp b/dll/win32/imm32/res/2052_Bitmap_209.bmp new file mode 100644 index 00000000000..485074a9469 Binary files /dev/null and b/dll/win32/imm32/res/2052_Bitmap_209.bmp differ diff --git a/dll/win32/imm32/resource.h b/dll/win32/imm32/resource.h new file mode 100644 index 00000000000..9dba6404099 --- /dev/null +++ b/dll/win32/imm32/resource.h @@ -0,0 +1,19 @@ +/* Bitmap IDs */ +#define IDB_T1_BACKSPACE 100 +#define IDB_T1_TAB 101 +#define IDB_T1_CAPS 102 +#define IDB_T1_ENTER 103 +#define IDB_T1_SHIFT 104 +#define IDB_T1_CTRL 105 +#define IDB_T1_ESCAPE 106 +#define IDB_T1_ALT 107 +#define IDB_T1_CHARS 108 +#define IDB_C1_BACKSPACE 201 +#define IDB_C1_TAB 202 +#define IDB_C1_CAPS 203 +#define IDB_C1_ENTER 204 +#define IDB_C1_SHIFT 205 +#define IDB_C1_INS 206 +#define IDB_C1_DEL 207 +#define IDB_C1_ESCAPE 208 +#define IDB_C1_CHARS 209 diff --git a/dll/win32/imm32/softkbd.c b/dll/win32/imm32/softkbd.c index 551331ffe40..8cf17248760 100644 --- a/dll/win32/imm32/softkbd.c +++ b/dll/win32/imm32/softkbd.c @@ -1,22 +1,53 @@ /* * PROJECT: ReactOS IMM32 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) - * PURPOSE: Implementing IMM Software Keyboard + * PURPOSE: Implementing IME Soft Keyboard * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ */ #include "precomp.h" +#include "resource.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); -static UINT s_uScanCode[256]; -static RECT s_rcWorkArea; -static POINT s_ptRaiseEdge; -static LOGFONTW s_lfSKT1Font; -static BOOL s_bWannaInitSoftKBD = TRUE; +/* + * There are two types of IME Soft Keyboard: Type T1 and Type C1. + * T1 is created for Traditional Chinese but not limitted to it. + * C1 is created for Simplified Chinese but not limitted to it. + * Type C1 has SHIFT status while Type T1 hasn't. + */ + +static UINT guScanCode[256]; /* Mapping: virtual key --> scan code */ +static POINT gptRaiseEdge; /* Border + Edge metrics */ +static BOOL g_bWantSoftKBDMetrics = TRUE; + +static inline BOOL +Imm32PtInRect( + _In_ const POINT *ppt, + _In_ LONG x, + _In_ LONG y, + _In_ LONG cx, + _In_ LONG cy) +{ + return (x <= ppt->x) && (ppt->x < x + cx) && (y <= ppt->y) && (ppt->y < y + cy); +} + +static inline INT +Imm32Clamp( + _In_ INT x, + _In_ INT xMin, + _In_ INT xMax) +{ + if (x < xMin) + return xMin; + if (x > xMax) + return xMax; + return x; +} static VOID -Imm32GetAllMonitorSize(_Out_ LPRECT prcWork) +Imm32GetAllMonitorSize( + _Out_ LPRECT prcWork) { if (GetSystemMetrics(SM_CMONITORS) == 1) { @@ -31,8 +62,8 @@ Imm32GetAllMonitorSize(_Out_ LPRECT prcWork) } static BOOL -Imm32GetNearestMonitorSize( - _In_ HWND hwnd, +Imm32GetNearestWorkArea( + _In_opt_ HWND hwnd, _Out_ LPRECT prcWork) { HMONITOR hMonitor; @@ -46,146 +77,1121 @@ Imm32GetNearestMonitorSize( hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); if (!hMonitor) + { + ERR("hwnd: %p\n", hwnd); return FALSE; + } ZeroMemory(&mi, sizeof(mi)); mi.cbSize = sizeof(mi); GetMonitorInfoW(hMonitor, &mi); - *prcWork = mi.rcWork; return TRUE; } -/* Software keyboard window procedure (Traditional Chinese) */ -static LRESULT CALLBACK -SKWndProcT1(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) - { - case WM_CREATE: - { - FIXME("stub\n"); - return -1; - } +/***************************************************************************** + * IME Soft Keyboard Type T1 + */ - default: - { - return DefWindowProcW(hwnd, uMsg, wParam, lParam); - } +#define T1_CLASSNAMEW L"SoftKBDClsT1" + +#undef DEFINE_T1K +#define DEFINE_T1K(t1k_code, virtual_key_code, t1k_code_name, virtual_key_name, is_special) \ + t1k_code_name = t1k_code, + +/* Define T1 internal codes (T1K_...) */ +typedef enum T1KEY +{ +#include "t1keys.h" +} T1KEY; + +#undef DEFINE_T1K +#define DEFINE_T1K(t1k_code, virtual_key_code, t1k_code_name, virtual_key_name, is_special) \ + virtual_key_code, + +#define T1K_MAX 60 + +/* Mapping: T1K --> Virtual Key */ +const BYTE gT1K2VK[T1K_MAX] = +{ +#include "t1keys.h" +}; + +typedef struct T1WINDOW +{ + INT cxDefWidth; /* Regular key width */ + INT cxWidth47; /* [BackSpace] width */ + INT cxWidth48; /* [Tab] width */ + INT cxWidth49; /* [Caps] width */ + INT cxWidth50; /* [Enter] width */ + INT cxWidth51or52; /* [Shift] width */ + INT cxWidth53or54; /* [Ctrl] width */ + INT cxWidth55or56; /* [Alt] width */ + INT cxWidth57; /* [Esc] width */ + INT cxWidth58; /* [Space] width */ + INT cyDefHeight; /* Regular key height */ + INT cyHeight50; /* [Enter] height */ + POINT KeyPos[T1K_MAX]; /* T1K --> POINT */ + WCHAR chKeyChar[48]; /* T1K --> WCHAR */ + HBITMAP hbmKeyboard; /* The keyboard image */ + DWORD CharSet; /* LOGFONT.lfCharSet */ + UINT PressedKey; /* Currently pressed key */ + POINT pt0, pt1; /* The soft keyboard window position */ + LPARAM KeyboardSubType; /* See IMC_GETSOFTKBDSUBTYPE/IMC_SETSOFTKBDSUBTYPE */ +} T1WINDOW, *PT1WINDOW; + +#define T1_KEYPOS(iKey) pT1->KeyPos[iKey] + +static LOGFONTW g_T1LogFont; + +static void +T1_GetTextMetric(_Out_ LPTEXTMETRICW ptm) +{ + WCHAR wch; + SIZE textSize; + HFONT hFont; + HGDIOBJ hFontOld; + HDC hDC; +#ifndef NDEBUG + WCHAR szFace[LF_FACESIZE]; +#endif + + ZeroMemory(&g_T1LogFont, sizeof(g_T1LogFont)); + g_T1LogFont.lfHeight = -12; + g_T1LogFont.lfWeight = FW_NORMAL; + g_T1LogFont.lfCharSet = CHINESEBIG5_CHARSET; +#ifdef NO_HACK /* FIXME: We lack proper Asian fonts! */ + g_T1LogFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; + g_T1LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + g_T1LogFont.lfQuality = PROOF_QUALITY; + g_T1LogFont.lfPitchAndFamily = FF_MODERN | FIXED_PITCH; +#else + StringCchCopyW(g_T1LogFont.lfFaceName, _countof(g_T1LogFont.lfFaceName), L"MS Shell Dlg"); +#endif + hFont = CreateFontIndirectW(&g_T1LogFont); + + hDC = GetDC(NULL); + hFontOld = SelectObject(hDC, hFont); + +#ifndef NDEBUG + GetTextFaceW(hDC, _countof(szFace), szFace); + TRACE("szFace: %s\n", debugstr_w(szFace)); +#endif + + GetTextMetricsW(hDC, ptm); + + wch = 0x4E11; /* U+4E11: δΈ‘ */ + if (GetTextExtentPoint32W(hDC, &wch, 1, &textSize) && textSize.cx > ptm->tmMaxCharWidth) + ptm->tmMaxCharWidth = textSize.cx; + + DeleteObject(SelectObject(hDC, hFontOld)); + ReleaseDC(NULL, hDC); +} + +static void +T1_InitButtonPos(_Out_ PT1WINDOW pT1) +{ + TEXTMETRICW tm; + LONG cxLarge, cyLarge; + LONG xKey1, yKey1, xKey2, yKey2, xKey3, yKey3; + LONG yKey4, xKey4, xKey5, yKey5, xKey6, xKey7; + INT iKey; + + T1_GetTextMetric(&tm); + + cxLarge = (3 * tm.tmMaxCharWidth + 18) / 2; + cyLarge = tm.tmHeight + 8; + + /* key widths and heights */ + pT1->cxDefWidth = (2 * tm.tmMaxCharWidth + 12) / 2; + pT1->cxWidth47 = (2 * tm.tmMaxCharWidth + 12) / 2 + 1; + pT1->cxWidth49 = (4 * tm.tmMaxCharWidth + 24) / 2 + 3; + pT1->cxWidth51or52 = (5 * tm.tmMaxCharWidth + 30) / 2 + 5; + pT1->cxWidth58 = 4 * (3 * tm.tmMaxCharWidth + 18) / 2 + 15; + pT1->cxWidth48 = pT1->cxWidth50 = cxLarge + 2; + pT1->cxWidth53or54 = pT1->cxWidth55or56 = cxLarge + 2; + pT1->cyHeight50 = 2 * (tm.tmHeight + 8) + 3; + pT1->cxWidth57 = cxLarge + 1; + pT1->cyDefHeight = cyLarge; + + /* First row */ + xKey1 = gptRaiseEdge.x + 3; + yKey1 = gptRaiseEdge.y + 3; + for (iKey = 0; iKey < T1K_Q; ++iKey) + { + T1_KEYPOS(iKey).x = xKey1; + T1_KEYPOS(iKey).y = yKey1; + xKey1 += pT1->cxDefWidth + 3; } + T1_KEYPOS(T1K_BACKSPACE).y = yKey1; + T1_KEYPOS(T1K_BACKSPACE).x = xKey1; + + /* 2nd row */ + xKey2 = 3 + gptRaiseEdge.x + pT1->cxWidth48 + 3; + yKey2 = 3 + yKey1 + cyLarge; + T1_KEYPOS(T1K_TAB).x = gptRaiseEdge.x + 3; + T1_KEYPOS(T1K_TAB).y = yKey2; + for (iKey = T1K_Q; iKey < T1K_A; ++iKey) + { + T1_KEYPOS(iKey).x = xKey2; + T1_KEYPOS(iKey).y = yKey2; + xKey2 += pT1->cxDefWidth + 3; + } + T1_KEYPOS(T1K_ENTER).x = xKey2; + T1_KEYPOS(T1K_ENTER).y = yKey2; + + /* 3rd row */ + xKey3 = gptRaiseEdge.x + 3 + pT1->cxWidth49 + 3; + yKey3 = yKey2 + cyLarge + 3; + T1_KEYPOS(T1K_CAPS).x = gptRaiseEdge.x + 3; + T1_KEYPOS(T1K_CAPS).y = yKey3; + for (iKey = T1K_A; iKey < T1K_Z; ++iKey) + { + T1_KEYPOS(iKey).x = xKey3; + T1_KEYPOS(iKey).y = yKey3; + xKey3 += pT1->cxDefWidth + 3; + } + + /* 4th row */ + xKey4 = gptRaiseEdge.x + pT1->cxWidth51or52 + 3 + 3; + yKey4 = yKey3 + cyLarge + 3; + T1_KEYPOS(T1K_L_SHIFT).x = gptRaiseEdge.x + 3; + T1_KEYPOS(T1K_L_SHIFT).y = yKey4; + for (iKey = T1K_Z; iKey < T1K_BACKSPACE; ++iKey) + { + T1_KEYPOS(iKey).x = xKey4; + T1_KEYPOS(iKey).y = yKey4; + xKey4 += pT1->cxDefWidth + 3; + } + T1_KEYPOS(T1K_R_SHIFT).x = xKey4; + T1_KEYPOS(T1K_R_SHIFT).y = yKey4; + + /* 5th row */ + xKey5 = gptRaiseEdge.x + 3 + pT1->cxWidth53or54 + 3; + T1_KEYPOS(T1K_L_CTRL).x = gptRaiseEdge.x + 3; + T1_KEYPOS(T1K_ESCAPE).x = xKey5; + T1_KEYPOS(T1K_L_ALT).x = xKey5 + pT1->cxWidth57 + 3; + + yKey5 = yKey4 + cyLarge + 3; + T1_KEYPOS(T1K_L_CTRL).y = T1_KEYPOS(T1K_ESCAPE).y = T1_KEYPOS(T1K_L_ALT).y = yKey5; + T1_KEYPOS(T1K_R_ALT).y = T1_KEYPOS(T1K_SPACE).y = T1_KEYPOS(T1K_R_CTRL).y = yKey5; + + xKey6 = xKey5 + pT1->cxWidth57 + 3 + pT1->cxWidth55or56 + 3; + T1_KEYPOS(T1K_SPACE).x = xKey6; + + xKey7 = xKey6 + pT1->cxWidth58 + 3; + T1_KEYPOS(T1K_R_ALT).x = xKey7; + T1_KEYPOS(T1K_R_CTRL).x = xKey7 + pT1->cxWidth57 + pT1->cxWidth55or56 + 6; +} + +/* Draw keyboard key edge */ +static void +T1_DrawConvexRect( + _In_ HDC hDC, + _In_ INT x, + _In_ INT y, + _In_ INT width, + _In_ INT height) +{ + HGDIOBJ hBlackPen = GetStockObject(BLACK_PEN); + HGDIOBJ hLtGrayBrush = GetStockObject(LTGRAY_BRUSH); + HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH); + INT dx = width + 4, dy = height + 4; + INT x0 = x - 2, y0 = y + height + 2; + + /* Face */ + SelectObject(hDC, hBlackPen); + SelectObject(hDC, hLtGrayBrush); + Rectangle(hDC, x0, y - 2, x0 + dx, y0); + + /* Rounded corners */ + PatBlt(hDC, x0, y - 2, 1, 1, PATCOPY); + PatBlt(hDC, x0, y0, 1, -1, PATCOPY); + PatBlt(hDC, x0 + dx, y - 2, -1, 1, PATCOPY); + PatBlt(hDC, x0 + dx, y0, -1, -1, PATCOPY); + + /* Light edge */ + PatBlt(hDC, x0 + 1, y + dy - 3, 1, 2 - dy, WHITENESS); + PatBlt(hDC, x0 + 1, y - 1, dx - 2, 1, WHITENESS); + + /* Dark edge */ + SelectObject(hDC, hGrayBrush); + PatBlt(hDC, x0 + 1, y + dy - 3, dx - 2, -1, PATCOPY); + 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, + _In_ const T1WINDOW *pT1, + _In_ LPCWSTR pszBmpName) +{ + HBITMAP hBitmap = LoadBitmapW(ghImm32Inst, pszBmpName); + HDC hdcMem = CreateCompatibleDC(hDC); + HGDIOBJ hbmOld = SelectObject(hdcMem, hBitmap); + INT iKey; + for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey) + { + const POINT *ppt = &T1_KEYPOS(iKey); + BitBlt(hDC, ppt->x, ppt->y, 8, 8, hdcMem, iKey * 8, 0, SRCCOPY); + } + SelectObject(hdcMem, hbmOld); + DeleteDC(hdcMem); + DeleteObject(hBitmap); +} + +static void +T1_InitBitmap( + _In_ HWND hWnd, + _Inout_ PT1WINDOW pT1) +{ + HDC hDC, hMemDC; + HGDIOBJ hNullPen = GetStockObject(NULL_PEN), hbrLtGray = GetStockObject(LTGRAY_BRUSH); + RECT rc; + INT iKey; + + /* Create the bitmap */ + hDC = GetDC(hWnd); + hMemDC = CreateCompatibleDC(hDC); + GetClientRect(hWnd, &rc); + pT1->hbmKeyboard = CreateCompatibleBitmap(hDC, rc.right - rc.left, rc.bottom - rc.top); + ReleaseDC(hWnd, hDC); + + /* Draw keyboard face */ + SelectObject(hMemDC, pT1->hbmKeyboard); + SelectObject(hMemDC, hNullPen); + SelectObject(hMemDC, hbrLtGray); + Rectangle(hMemDC, rc.left, rc.top, rc.right + 1, rc.bottom + 1); + DrawEdge(hMemDC, &rc, EDGE_RAISED, BF_RECT); + + /* 53 --> Left [Ctrl] */ + 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); + + /* 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); + + /* 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); + + /* 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); + + /* 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); + + /* 58 --> [Space] */ + T1_DrawConvexRect(hMemDC, + T1_KEYPOS(T1K_SPACE).x, T1_KEYPOS(T1K_SPACE).y, + pT1->cxWidth58, pT1->cyDefHeight); + + /* 51 --> Left [Shift] */ + 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); + + /* 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); + + /* 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); + + /* 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); + + /* 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); + + /* 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); + + /* Regular keys */ + for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey) + { + LPPOINT ppt = &T1_KEYPOS(iKey); + T1_DrawConvexRect(hMemDC, ppt->x, ppt->y, pT1->cxDefWidth, pT1->cyDefHeight); + } + + T1_DrawLabels(hMemDC, pT1, MAKEINTRESOURCEW(IDB_T1_CHARS)); + DeleteDC(hMemDC); +} + +static INT +T1_OnCreate( + _In_ HWND hWnd) +{ + PT1WINDOW pT1; + HGLOBAL hGlobal = GlobalAlloc(GHND, sizeof(T1WINDOW)); + if (!hGlobal) + return -1; + + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!pT1) + { + GlobalFree(hGlobal); + return -1; + } + + SetWindowLongPtrW(hWnd, 0, (LONG_PTR)hGlobal); + pT1->pt1.x = pT1->pt1.y = -1; + pT1->PressedKey = T1K_NONE; + pT1->CharSet = CHINESEBIG5_CHARSET; + + T1_InitButtonPos(pT1); + T1_InitBitmap(hWnd, pT1); + GlobalUnlock(hGlobal); + return 0; } -/* Software keyboard window procedure (Simplified Chinese) */ -static LRESULT CALLBACK -SKWndProcC1(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +static void +T1_DrawDragBorder( + _In_ HWND hWnd, + _In_ const POINT *ppt1, + _In_ const POINT *ppt2) { - switch (uMsg) - { - case WM_CREATE: - { - FIXME("stub\n"); - return -1; - } + INT cxBorder = GetSystemMetrics(SM_CXBORDER), cyBorder = GetSystemMetrics(SM_CYBORDER); + INT x = ppt1->x - ppt2->x, y = ppt1->y - ppt2->y; + HGDIOBJ hGrayBrush = GetStockObject(GRAY_BRUSH); + RECT rc; + HDC hDisplayDC; - default: + GetWindowRect(hWnd, &rc); + hDisplayDC = CreateDCW(L"DISPLAY", NULL, NULL, NULL); + SelectObject(hDisplayDC, hGrayBrush); + PatBlt(hDisplayDC, x, y, rc.right - rc.left - cxBorder, cyBorder, PATINVERT); + PatBlt(hDisplayDC, x, cyBorder + y, 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 void +T1_OnDestroy( + _In_ HWND hWnd) +{ + HGLOBAL hGlobal; + PT1WINDOW pT1; + HWND hwndOwner; + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) + return; + + if (pT1->pt1.x != -1 && pT1->pt1.y != -1) + T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1); + + DeleteObject(pT1->hbmKeyboard); + GlobalUnlock(hGlobal); + GlobalFree(hGlobal); + + hwndOwner = GetWindow(hWnd, GW_OWNER); + if (hwndOwner) + SendMessageW(hwndOwner, WM_IME_NOTIFY, IMN_SOFTKBDDESTROYED, 0); +} + +static void +T1_InvertButton( + _In_ HWND hWnd, + _In_ HDC hDC, + _In_ const T1WINDOW *pT1, + _In_ UINT iPressed) +{ + INT cxWidth = pT1->cxDefWidth, cyHeight = pT1->cyDefHeight; + HDC hChoiceDC; + + if (iPressed >= T1K_NONE) + return; + + if (hDC) + hChoiceDC = hDC; + else + hChoiceDC = GetDC(hWnd); + + if (iPressed >= T1K_BACKSPACE) + { + switch (iPressed) { - return DefWindowProcW(hwnd, uMsg, wParam, lParam); + case T1K_BACKSPACE: + cxWidth = pT1->cxWidth47; + break; + case T1K_TAB: + cxWidth = pT1->cxWidth48; + break; + case T1K_ENTER: + pT1 = pT1; + cxWidth = pT1->cxWidth50; + cyHeight = pT1->cyHeight50; + break; + case T1K_ESCAPE: + cxWidth = pT1->cxWidth57; + break; + case T1K_SPACE: + cxWidth = pT1->cxWidth58; + break; + default: + cxWidth = 0; + MessageBeep(0xFFFFFFFF); + break; } } - return 0; + + if (cxWidth > 0) + { + PatBlt(hChoiceDC, + T1_KEYPOS(iPressed).x - 1, T1_KEYPOS(iPressed).y - 1, + cxWidth + 2, cyHeight + 2, + DSTINVERT); + } + + if (!hDC) + ReleaseDC(hWnd, hChoiceDC); +} + +static void +T1_OnDraw( + _In_ HDC hDC, + _In_ HWND hWnd) +{ + HGLOBAL hGlobal; + PT1WINDOW pT1; + HDC hMemDC; + RECT rc; + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) + return; + + hMemDC = CreateCompatibleDC(hDC); + SelectObject(hMemDC, pT1->hbmKeyboard); + GetClientRect(hWnd, &rc); + BitBlt(hDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 0, 0, SRCCOPY); + DeleteDC(hMemDC); + + if (pT1->PressedKey < T1K_NONE) + T1_InvertButton(hWnd, hDC, pT1, pT1->PressedKey); + + GlobalUnlock(hGlobal); +} + +static UINT +T1_HitTest( + _In_ const T1WINDOW *pT1, + _In_ const POINT *ppt) +{ + INT iKey; + for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey) + { + const POINT *pptKey = &T1_KEYPOS(iKey); + if (Imm32PtInRect(ppt, pptKey->x, pptKey->y, pT1->cxDefWidth, pT1->cyDefHeight)) + return iKey; + } + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_BACKSPACE).x, T1_KEYPOS(T1K_BACKSPACE).y, pT1->cxWidth47, pT1->cyDefHeight)) + return T1K_BACKSPACE; + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_TAB).x, T1_KEYPOS(T1K_TAB).y, pT1->cxWidth48, pT1->cyDefHeight)) + return T1K_TAB; + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_CAPS).x, T1_KEYPOS(T1K_CAPS).y, pT1->cxWidth49, pT1->cyDefHeight)) + return T1K_CAPS; + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_ENTER).x, T1_KEYPOS(T1K_ENTER).y, pT1->cxWidth50, pT1->cyHeight50)) + return T1K_ENTER; + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_L_SHIFT).x, T1_KEYPOS(T1K_L_SHIFT).y, pT1->cxWidth51or52, pT1->cyDefHeight) || + Imm32PtInRect(ppt, T1_KEYPOS(T1K_R_SHIFT).x, T1_KEYPOS(T1K_R_SHIFT).y, pT1->cxWidth51or52, pT1->cyDefHeight)) + { + return T1K_L_SHIFT; + } + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_L_CTRL).x, T1_KEYPOS(T1K_L_CTRL).y, pT1->cxWidth53or54, pT1->cyDefHeight) || + Imm32PtInRect(ppt, T1_KEYPOS(T1K_R_CTRL).x, T1_KEYPOS(T1K_R_CTRL).y, pT1->cxWidth53or54, pT1->cyDefHeight)) + { + return T1K_L_CTRL; + } + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_L_ALT).x, T1_KEYPOS(T1K_L_ALT).y, pT1->cxWidth55or56, pT1->cyDefHeight) || + Imm32PtInRect(ppt, T1_KEYPOS(T1K_R_ALT).x, T1_KEYPOS(T1K_R_ALT).y, pT1->cxWidth55or56, pT1->cyDefHeight)) + { + return T1K_L_ALT; + } + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_ESCAPE).x, T1_KEYPOS(T1K_ESCAPE).y, pT1->cxWidth57, pT1->cyDefHeight)) + return T1K_ESCAPE; + + if (Imm32PtInRect(ppt, T1_KEYPOS(T1K_SPACE).x, T1_KEYPOS(T1K_SPACE).y, pT1->cxWidth58, pT1->cyDefHeight)) + return T1K_SPACE; + + return T1K_NONE; } static BOOL -Imm32RegisterSoftKeyboard(_In_ UINT uType) +T1_IsValidButton( + _In_ UINT iKey, + _In_ const T1WINDOW *pT1) { - LPCWSTR pszClass; - WNDCLASSEXW wcx; + if (iKey < T1K_BACKSPACE) + return !!pT1->chKeyChar[iKey]; + return iKey <= T1K_TAB || iKey == T1K_ENTER || (T1K_ESCAPE <= iKey && iKey <= T1K_SPACE); +} - if (uType == 1) - pszClass = L"SoftKBDClsT1"; - else if (uType == 2) - pszClass = L"SoftKBDClsC1"; - else +/** + * NOTE: The window that has WS_DISABLED style doesn't receive some mouse messages. + * Use WM_SETCURSOR handling to detect mouse events. + */ +static BOOL +T1_OnSetCursor( + _In_ HWND hWnd, + _In_ LPARAM lParam) +{ + HGLOBAL hGlobal; + PT1WINDOW pT1; + HCURSOR hCursor; + UINT iPressed, iKey; + RECT rc, rcWork; + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) return FALSE; + if (pT1->pt1.x != -1 && pT1->pt1.y != -1) + { + SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL)); + GlobalUnlock(hGlobal); + return TRUE; + } + + GetCursorPos(&pT1->pt0); + ScreenToClient(hWnd, &pT1->pt0); + + iKey = T1_HitTest(pT1, &pT1->pt0); + if (iKey >= T1K_NONE) + hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL); + else + hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_HAND); + SetCursor(hCursor); + + if (HIWORD(lParam) == WM_LBUTTONDOWN) + { + SetCapture(hWnd); + + iPressed = pT1->PressedKey; + if (iPressed < T1K_NONE) + { + UINT iVK = gT1K2VK[iPressed]; + keybd_event(iVK, guScanCode[iVK], KEYEVENTF_KEYUP, 0); + T1_InvertButton(hWnd, NULL, pT1, pT1->PressedKey); + pT1->PressedKey = T1K_NONE; + } + + if (iKey >= T1K_NONE) + { + Imm32GetAllMonitorSize(&rcWork); + GetCursorPos(&pT1->pt0); + GetWindowRect(hWnd, &rc); + pT1->pt1.x = pT1->pt0.x - rc.left; + pT1->pt1.y = pT1->pt0.y - rc.top; + T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1); + } + else if (T1_IsValidButton(iKey, pT1)) + { + UINT iVK = gT1K2VK[iKey]; + keybd_event(iVK, guScanCode[iVK], 0, 0); + pT1->PressedKey = iKey; + T1_InvertButton(hWnd, 0, pT1, iKey); + } + else + { + MessageBeep(0xFFFFFFFF); + } + } + + return TRUE; +} + +static BOOL +T1_OnMouseMove( + _In_ HWND hWnd) +{ + BOOL ret = FALSE; + HGLOBAL hGlobal; + PT1WINDOW pT1; + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) + return FALSE; + + if (pT1->pt1.x != -1 && pT1->pt1.y != -1) + { + T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1); + GetCursorPos(&pT1->pt0); + T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1); + ret = TRUE; + } + + GlobalUnlock(hGlobal); + return ret; +} + +static BOOL +T1_OnButtonUp( + _In_ HWND hWnd) +{ + BOOL ret = FALSE; + HGLOBAL hGlobal; + PT1WINDOW pT1; + INT x, y, iPressed; + HWND hwndOwner, hwndCapture = GetCapture(); + HIMC hIMC; + LPINPUTCONTEXT pIC; + + if (hwndCapture == hWnd) + ReleaseCapture(); + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) + return FALSE; + + iPressed = pT1->PressedKey; + if (iPressed >= T1K_NONE) + { + if (pT1->pt1.x != -1 && pT1->pt1.y != -1 ) + { + T1_DrawDragBorder(hWnd, &pT1->pt0, &pT1->pt1); + x = pT1->pt0.x - pT1->pt1.x; + y = pT1->pt0.y - pT1->pt1.y; + SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + pT1->pt1.x = pT1->pt1.y = -1; + pT1->PressedKey = T1K_NONE; + 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); + } + } + } + } + else + { + UINT iVK = gT1K2VK[iPressed]; + keybd_event(iVK, guScanCode[iVK], KEYEVENTF_KEYUP, 0); + + T1_InvertButton(hWnd, 0, pT1, pT1->PressedKey); + pT1->PressedKey = T1K_NONE; + ret = TRUE; + } + + GlobalUnlock(hGlobal); + return ret; +} + +static LRESULT +T1_SetData( + _In_ HWND hWnd, + _In_ const SOFTKBDDATA *pData) +{ + HGLOBAL hGlobal; + PT1WINDOW pT1; + HDC hDC, hMemDC; + HFONT hFont; + HGDIOBJ hFontOld, hbmOld; + RECT rc; + INT iKey; + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) + return 1; + + hDC = GetDC(hWnd); + hMemDC = CreateCompatibleDC(hDC); + ReleaseDC(hWnd, hDC); + + hbmOld = SelectObject(hMemDC, pT1->hbmKeyboard); +#if 0 /* The default text color is black */ + SetTextColor(hMemDC, RGB(0, 0, 0)); +#endif + SetBkColor(hMemDC, RGB(192, 192, 192)); + + if (pT1->CharSet == DEFAULT_CHARSET) + { + hFont = CreateFontIndirectW(&g_T1LogFont); + } + else + { + LOGFONTW lf = g_T1LogFont; + lf.lfCharSet = (BYTE)pT1->CharSet; + hFont = CreateFontIndirectW(&lf); + } + hFontOld = SelectObject(hMemDC, hFont); + + for (iKey = 0; iKey < T1K_BACKSPACE; ++iKey) + { + INT x0 = T1_KEYPOS(iKey).x, y0 = T1_KEYPOS(iKey).y; + INT x = x0 + 6, y = y0 + 8; + WCHAR wch = pT1->chKeyChar[iKey] = pData->wCode[0][gT1K2VK[iKey]]; + SetRect(&rc, x, y, x0 + pT1->cxDefWidth, y0 + pT1->cyDefHeight); + ExtTextOutW(hMemDC, x, y, ETO_OPAQUE, &rc, &wch, wch != 0, NULL); + } + + DeleteObject(SelectObject(hMemDC, hFontOld)); + SelectObject(hMemDC, hbmOld); + DeleteDC(hMemDC); + GlobalUnlock(hGlobal); + return 0; +} + +static LRESULT +T1_OnImeControl( + _In_ HWND hWnd, + _Inout_ WPARAM wParam, + _Inout_ LPARAM lParam) +{ + LRESULT ret = 1; + PT1WINDOW pT1; + HGLOBAL hGlobal; + + switch (wParam) + { + case IMC_GETSOFTKBDFONT: + { + TRACE("IMC_GETSOFTKBDFONT: %p\n", lParam); + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (hGlobal && pT1) + { + LPLOGFONTW plf = (LPLOGFONTW)lParam; + DWORD CharSet = pT1->CharSet; + GlobalUnlock(hGlobal); + + *plf = g_T1LogFont; + if (CharSet != DEFAULT_CHARSET) + plf->lfCharSet = (BYTE)CharSet; + + ret = 0; + } + break; + } + case IMC_SETSOFTKBDFONT: + { + const LOGFONTW *plf = (LPLOGFONTW)lParam; + TRACE("IMC_SETSOFTKBDFONT: %p\n", lParam); + if (g_T1LogFont.lfCharSet == plf->lfCharSet) + return 0; + + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (hGlobal && pT1) + { + pT1->CharSet = plf->lfCharSet; + GlobalUnlock(hGlobal); + return 0; + } + + break; + } + case IMC_GETSOFTKBDPOS: + { + RECT rc; + TRACE("IMC_GETSOFTKBDPOS\n"); + GetWindowRect(hWnd, &rc); + return MAKELRESULT(rc.left, rc.top); + } + case IMC_SETSOFTKBDPOS: + { + POINT pt; + HWND hwndParent; + + POINTSTOPOINT(pt, lParam); + TRACE("IMC_SETSOFTKBDPOS(%ld, %ld)\n", pt.x, pt.y); + + SetWindowPos(hWnd, NULL, pt.x, pt.y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE); + + hwndParent = GetParent(hWnd); + if (hwndParent) + { + HIMC hIMC = (HIMC)GetWindowLongPtrW(hwndParent, 0); + if (hIMC) + { + LPINPUTCONTEXT pIC = ImmLockIMC(hIMC); + if (pIC) + { + pIC->ptSoftKbdPos.x = pt.x; + pIC->ptSoftKbdPos.y = pt.y; + ImmUnlockIMC(hIMC); + return 0; + } + } + } + break; + } + case IMC_GETSOFTKBDSUBTYPE: + case IMC_SETSOFTKBDSUBTYPE: + { + TRACE("IMC_GETSOFTKBDSUBTYPE/IMC_SETSOFTKBDSUBTYPE\n"); + hGlobal = (HGLOBAL)GetWindowLongPtrW(hWnd, 0); + pT1 = (PT1WINDOW)GlobalLock(hGlobal); + if (!hGlobal || !pT1) + return -1; + + ret = pT1->KeyboardSubType; + + if (wParam == IMC_SETSOFTKBDSUBTYPE) + pT1->KeyboardSubType = lParam; + + GlobalUnlock(hGlobal); + break; + } + case IMC_SETSOFTKBDDATA: + { + TRACE("IMC_SETSOFTKBDDATA: %p\n", lParam); + ret = T1_SetData(hWnd, (SOFTKBDDATA*)lParam); + if (!ret) + { + InvalidateRect(hWnd, NULL, FALSE); + PostMessageW(hWnd, WM_PAINT, 0, 0); + } + break; + } + } + + return ret; +} + +static LRESULT CALLBACK +T1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + { + return T1_OnCreate(hWnd); + } + case WM_DESTROY: + { + T1_OnDestroy(hWnd); + break; + } + case WM_SETCURSOR: + { + if (T1_OnSetCursor(hWnd, lParam)) + break; + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + case WM_MOUSEMOVE: + { + if (T1_OnMouseMove(hWnd)) + break; + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + case WM_PAINT: + { + PAINTSTRUCT ps; + HDC hDC = BeginPaint(hWnd, &ps); + T1_OnDraw(hDC, hWnd); + EndPaint(hWnd, &ps); + break; + } + case WM_SHOWWINDOW: + { + if (!lParam && wParam != SW_SHOWNORMAL) + T1_OnButtonUp(hWnd); + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + case WM_MOUSEACTIVATE: + { + return MA_NOACTIVATE; + } + case WM_LBUTTONUP: + { + if (T1_OnButtonUp(hWnd)) + break; + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + case WM_IME_CONTROL: + { + return T1_OnImeControl(hWnd, wParam, lParam); + } + default: + { + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + } + + return 0; +} + +/***************************************************************************** + * IME Soft Keyboard Type C1 + */ + +#define C1_CLASSNAMEW L"SoftKBDClsC1" + +static LRESULT CALLBACK +C1_WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + { + FIXME("stub\n"); + return -1; + } + + default: + { + return DefWindowProcW(hWnd, uMsg, wParam, lParam); + } + } + return 0; +} + +/*****************************************************************************/ + +static BOOL +Imm32RegisterSoftKeyboard( + _In_ UINT uType) +{ + WNDCLASSEXW wcx; + LPCWSTR pszClass = ((uType == SOFTKEYBOARD_TYPE_T1) ? T1_CLASSNAMEW : C1_CLASSNAMEW); if (GetClassInfoExW(ghImm32Inst, pszClass, &wcx)) return TRUE; ZeroMemory(&wcx, sizeof(wcx)); - wcx.cbSize = sizeof(wcx); - wcx.style = CS_IME; - wcx.cbWndExtra = sizeof(LONG_PTR); - wcx.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); - wcx.hInstance = ghImm32Inst; - wcx.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL); + wcx.cbSize = sizeof(wcx); + wcx.style = CS_IME; + wcx.cbWndExtra = sizeof(PT1WINDOW); + wcx.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); + wcx.hInstance = ghImm32Inst; + wcx.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL); wcx.lpszClassName = pszClass; - if (uType == 1) + if (uType == SOFTKEYBOARD_TYPE_T1) { - wcx.lpfnWndProc = SKWndProcT1; + wcx.lpfnWndProc = T1_WindowProc; wcx.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); } else { - wcx.lpfnWndProc = SKWndProcC1; + wcx.lpfnWndProc = C1_WindowProc; wcx.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); } return !!RegisterClassExW(&wcx); } -static VOID -Imm32GetSKT1TextMetric(_Out_ LPTEXTMETRICW lptm) -{ - HDC hDC; - HFONT hFont; - SIZE size; - HGDIOBJ hFontOld; - WCHAR szText[2] = { 0x894E, 0 }; - - hDC = GetDC(NULL); - - ZeroMemory(&s_lfSKT1Font, sizeof(s_lfSKT1Font)); - s_lfSKT1Font.lfHeight = -12; - s_lfSKT1Font.lfWeight = FW_NORMAL; - s_lfSKT1Font.lfCharSet = CHINESEBIG5_CHARSET; - s_lfSKT1Font.lfOutPrecision = OUT_TT_ONLY_PRECIS; - s_lfSKT1Font.lfClipPrecision = CLIP_DEFAULT_PRECIS; - s_lfSKT1Font.lfQuality = PROOF_QUALITY; - s_lfSKT1Font.lfPitchAndFamily = 49; - hFont = CreateFontIndirectW(&s_lfSKT1Font); - - hFontOld = SelectObject(hDC, hFont); - - GetTextMetricsW(hDC, lptm); - - if (GetTextExtentPoint32W(hDC, szText, 1, &size) && lptm->tmMaxCharWidth < size.cx ) - lptm->tmMaxCharWidth = size.cx; - - DeleteObject(SelectObject(hDC, hFontOld)); - ReleaseDC(NULL, hDC); -} - -static VOID +static void Imm32GetSoftKeyboardDimension( _In_ UINT uType, _Out_ LPINT pcx, _Out_ LPINT pcy) { - INT cxEdge, cyEdge; - TEXTMETRICW tm; - - if (uType == 1) + if (uType == SOFTKEYBOARD_TYPE_T1) { - Imm32GetSKT1TextMetric(&tm); - *pcx = 15 * tm.tmMaxCharWidth + 2 * s_ptRaiseEdge.x + 139; - *pcy = 5 * tm.tmHeight + 2 * s_ptRaiseEdge.y + 58; + TEXTMETRICW tm; + T1_GetTextMetric(&tm); + *pcx = 15 * tm.tmMaxCharWidth + 2 * gptRaiseEdge.x + 139; + *pcy = 5 * tm.tmHeight + 2 * gptRaiseEdge.y + 58; } else { - cxEdge = GetSystemMetrics(SM_CXEDGE); - cyEdge = GetSystemMetrics(SM_CYEDGE); + INT cxEdge = GetSystemMetrics(SM_CXEDGE), cyEdge = GetSystemMetrics(SM_CXEDGE); *pcx = 2 * (GetSystemMetrics(SM_CXBORDER) + cxEdge) + 348; *pcy = 2 * (GetSystemMetrics(SM_CYBORDER) + cyEdge) + 136; } @@ -205,65 +1211,85 @@ ImmCreateSoftKeyboard( { HKL hKL; PIMEDPI pImeDpi; - DWORD dwUICaps, style = (WS_POPUP | WS_DISABLED); - UINT i; - INT xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD; + UINT iVK; + INT xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD, cxEdge, cyEdge; HWND hwndSoftKBD; + DWORD Style, ExStyle, UICaps; + LPCWSTR pszClass; + RECT rcWorkArea; - TRACE("(%u, %p, %d, %d)\n", uType, hwndParent, x, y); - - if (uType != 1 && uType != 2) - return 0; + if ((uType != SOFTKEYBOARD_TYPE_T1) && (uType != SOFTKEYBOARD_TYPE_C1)) + { + ERR("uType: %u\n", uType); + return NULL; /* Invalid keyboard type */ + } + /* Check IME */ hKL = GetKeyboardLayout(0); pImeDpi = ImmLockImeDpi(hKL); - if (!pImeDpi) - return NULL; + if (IS_NULL_UNEXPECTEDLY(pImeDpi)) + return NULL; /* No IME */ - dwUICaps = pImeDpi->ImeInfo.fdwUICaps; + UICaps = pImeDpi->ImeInfo.fdwUICaps; ImmUnlockImeDpi(pImeDpi); - if (!(dwUICaps & UI_CAP_SOFTKBD)) - return NULL; - - if (s_bWannaInitSoftKBD) + /* Check IME capability */ + if (!(UICaps & UI_CAP_SOFTKBD)) { - if (!Imm32GetNearestMonitorSize(hwndParent, &s_rcWorkArea)) - return NULL; - - for (i = 0; i < 0xFF; ++i) - s_uScanCode[i] = MapVirtualKeyW(i, 0); - - s_ptRaiseEdge.x = GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXEDGE); - s_ptRaiseEdge.y = GetSystemMetrics(SM_CYBORDER) + GetSystemMetrics(SM_CYEDGE); - - s_bWannaInitSoftKBD = FALSE; + ERR("UICaps: 0x%X\n", UICaps); + return NULL; /* No capability for soft keyboard */ } - if (!Imm32RegisterSoftKeyboard(uType)) + /* Want metrics? */ + if (g_bWantSoftKBDMetrics) + { + for (iVK = 0; iVK < 0xFF; ++iVK) + { + guScanCode[iVK] = MapVirtualKeyW(iVK, 0); + } + + cxEdge = GetSystemMetrics(SM_CXEDGE); + cyEdge = GetSystemMetrics(SM_CYEDGE); + gptRaiseEdge.x = GetSystemMetrics(SM_CXBORDER) + cxEdge; + gptRaiseEdge.y = GetSystemMetrics(SM_CYBORDER) + cyEdge; + + g_bWantSoftKBDMetrics = FALSE; + } + + if (!Imm32GetNearestWorkArea(hwndParent, &rcWorkArea)) return NULL; + /* Register the window class */ + if (!Imm32RegisterSoftKeyboard(uType)) + { + ERR("\n"); + return NULL; + } + + /* Calculate keyboard size */ Imm32GetSoftKeyboardDimension(uType, &cxSoftKBD, &cySoftKBD); - xSoftKBD = max(s_rcWorkArea.left, min(x, s_rcWorkArea.right - cxSoftKBD)); - ySoftKBD = max(s_rcWorkArea.top, min(y, s_rcWorkArea.bottom - cySoftKBD)); + /* Adjust keyboard position */ + xSoftKBD = Imm32Clamp(x, rcWorkArea.left, rcWorkArea.right - cxSoftKBD); + ySoftKBD = Imm32Clamp(y, rcWorkArea.top , rcWorkArea.bottom - cySoftKBD); - if (uType == 1) /* Traditional Chinese */ + /* Create soft keyboard window */ + if (uType == SOFTKEYBOARD_TYPE_T1) { - hwndSoftKBD = CreateWindowExW(0, - L"SoftKBDClsT1", NULL, style, - xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD, - hwndParent, NULL, ghImm32Inst, NULL); + Style = (WS_POPUP | WS_DISABLED); + ExStyle = 0; + pszClass = T1_CLASSNAMEW; } - else /* Simplified Chinese (uType == 2) */ + else { - style |= WS_BORDER; - hwndSoftKBD = CreateWindowExW(WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME, - L"SoftKBDClsC1", NULL, style, - xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD, - hwndParent, NULL, ghImm32Inst, NULL); + Style = (WS_POPUP | WS_DISABLED | WS_BORDER); + ExStyle = (WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME); + pszClass = C1_CLASSNAMEW; } - + hwndSoftKBD = CreateWindowExW(ExStyle, pszClass, NULL, Style, + xSoftKBD, ySoftKBD, cxSoftKBD, cySoftKBD, + hwndParent, NULL, ghImm32Inst, NULL); + /* Initial is hidden */ ShowWindow(hwndSoftKBD, SW_HIDE); UpdateWindow(hwndSoftKBD); @@ -281,6 +1307,10 @@ ImmShowSoftKeyboard( _In_ INT nCmdShow) { TRACE("(%p, %d)\n", hwndSoftKBD, nCmdShow); + + if (nCmdShow != SW_HIDE && nCmdShow != SW_SHOWNOACTIVATE) + WARN("nCmdShow %d is unexpected\n", nCmdShow); + return hwndSoftKBD && ShowWindow(hwndSoftKBD, nCmdShow); } diff --git a/dll/win32/imm32/t1keys.h b/dll/win32/imm32/t1keys.h new file mode 100644 index 00000000000..22ed5b42469 --- /dev/null +++ b/dll/win32/imm32/t1keys.h @@ -0,0 +1,68 @@ +/* + * PROJECT: ReactOS IMM32 + * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) + * PURPOSE: Defining internal codes (T1K_...) of IME Soft Keyboard Type T1 + * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ + */ + +/* DEFINE_T1K(t1k_code, virtual_key_code, t1k_code_name, virtual_key_name, is_special) */ +DEFINE_T1K( 0, 0xC0, T1K_BACKTICK, VK_OEM_3, FALSE) +DEFINE_T1K( 1, 0x31, T1K_1, VK_1, FALSE) +DEFINE_T1K( 2, 0x32, T1K_2, VK_2, FALSE) +DEFINE_T1K( 3, 0x33, T1K_3, VK_3, FALSE) +DEFINE_T1K( 4, 0x34, T1K_4, VK_4, FALSE) +DEFINE_T1K( 5, 0x35, T1K_5, VK_5, FALSE) +DEFINE_T1K( 6, 0x36, T1K_6, VK_6, FALSE) +DEFINE_T1K( 7, 0x37, T1K_7, VK_7, FALSE) +DEFINE_T1K( 8, 0x38, T1K_8, VK_8, FALSE) +DEFINE_T1K( 9, 0x39, T1K_9, VK_9, FALSE) +DEFINE_T1K(10, 0x30, T1K_0, VK_0, FALSE) +DEFINE_T1K(11, 0xBD, T1K_MINUS, VK_OEM_MINUS, FALSE) +DEFINE_T1K(12, 0xBB, T1K_PLUS, VK_OEM_PLUS, FALSE) +DEFINE_T1K(13, 0xDC, T1K_OEM_5, VK_OEM_5, FALSE) +DEFINE_T1K(14, 0x51, T1K_Q, VK_Q, FALSE) +DEFINE_T1K(15, 0x57, T1K_W, VK_W, FALSE) +DEFINE_T1K(16, 0x45, T1K_E, VK_E, FALSE) +DEFINE_T1K(17, 0x52, T1K_R, VK_R, FALSE) +DEFINE_T1K(18, 0x54, T1K_T, VK_T, FALSE) +DEFINE_T1K(19, 0x59, T1K_Y, VK_Y, FALSE) +DEFINE_T1K(20, 0x55, T1K_U, VK_U, FALSE) +DEFINE_T1K(21, 0x49, T1K_I, VK_I, FALSE) +DEFINE_T1K(22, 0x4F, T1K_O, VK_O, FALSE) +DEFINE_T1K(23, 0x50, T1K_P, VK_P, FALSE) +DEFINE_T1K(24, 0xDB, T1K_OEM_4, VK_OEM_4, FALSE) +DEFINE_T1K(25, 0xDD, T1K_OEM_6, VK_OEM_6, FALSE) +DEFINE_T1K(26, 0x41, T1K_A, VK_A, FALSE) +DEFINE_T1K(27, 0x53, T1K_S, VK_S, FALSE) +DEFINE_T1K(28, 0x44, T1K_D, VK_D, FALSE) +DEFINE_T1K(29, 0x46, T1K_F, VK_F, FALSE) +DEFINE_T1K(30, 0x47, T1K_G, VK_G, FALSE) +DEFINE_T1K(31, 0x48, T1K_H, VK_H, FALSE) +DEFINE_T1K(32, 0x4A, T1K_J, VK_J, FALSE) +DEFINE_T1K(33, 0x4B, T1K_K, VK_K, FALSE) +DEFINE_T1K(34, 0x4C, T1K_L, VK_L, FALSE) +DEFINE_T1K(35, 0xBA, T1K_OEM_1, VK_OEM_1, FALSE) +DEFINE_T1K(36, 0xDE, T1K_OEM_7, VK_OEM_7, FALSE) +DEFINE_T1K(37, 0x5A, T1K_Z, VK_Z, FALSE) +DEFINE_T1K(38, 0x58, T1K_X, VK_X, FALSE) +DEFINE_T1K(39, 0x43, T1K_C, VK_C, FALSE) +DEFINE_T1K(40, 0x56, T1K_V, VK_V, FALSE) +DEFINE_T1K(41, 0x42, T1K_B, VK_B, FALSE) +DEFINE_T1K(42, 0x4E, T1K_N, VK_N, FALSE) +DEFINE_T1K(43, 0x4D, T1K_M, VK_M, FALSE) +DEFINE_T1K(44, 0xBC, T1K_OEM_COMMA, VK_OEM_COMMA, FALSE) +DEFINE_T1K(45, 0xBE, T1K_OEM_PERIOD, VK_OEM_PERIOD, FALSE) +DEFINE_T1K(46, 0xBF, T1K_OEM_2, VK_OEM_2, FALSE) +DEFINE_T1K(47, 0x08, T1K_BACKSPACE, VK_BACK, TRUE) +DEFINE_T1K(48, 0x09, T1K_TAB, VK_TAB, TRUE) +DEFINE_T1K(49, 0x14, T1K_CAPS, VK_CAPITAL, TRUE) +DEFINE_T1K(50, 0x0D, T1K_ENTER, VK_RETURN, TRUE) +DEFINE_T1K(51, 0x10, T1K_L_SHIFT, VK_SHIFT, TRUE) +DEFINE_T1K(52, 0x10, T1K_R_SHIFT, VK_SHIFT, TRUE) +DEFINE_T1K(53, 0x11, T1K_L_CTRL, VK_CONTROL, TRUE) +DEFINE_T1K(54, 0x11, T1K_R_CTRL, VK_CONTROL, TRUE) +DEFINE_T1K(55, 0x12, T1K_L_ALT, VK_MENU, TRUE) +DEFINE_T1K(56, 0x12, T1K_R_ALT, VK_MENU, TRUE) +DEFINE_T1K(57, 0x1B, T1K_ESCAPE, VK_ESCAPE, TRUE) +DEFINE_T1K(58, 0x20, T1K_SPACE, VK_SPACE, TRUE) +DEFINE_T1K(59, 0x00, T1K_NONE, 0, TRUE) diff --git a/sdk/include/ddk/immdev.h b/sdk/include/ddk/immdev.h index 619ac609367..8a8586b774d 100644 --- a/sdk/include/ddk/immdev.h +++ b/sdk/include/ddk/immdev.h @@ -17,12 +17,23 @@ extern "C" { #endif +typedef struct tagSOFTKBDDATA +{ + UINT uCount; + WORD wCode[1][256]; +} SOFTKBDDATA, *PSOFTKBDDATA, *LPSOFTKBDDATA; + /* wParam for WM_IME_CONTROL */ #define IMC_GETCONVERSIONMODE 0x0001 #define IMC_GETSENTENCEMODE 0x0003 #define IMC_GETOPENSTATUS 0x0005 +#define IMC_GETSOFTKBDFONT 0x0011 +#define IMC_SETSOFTKBDFONT 0x0012 #define IMC_GETSOFTKBDPOS 0x0013 #define IMC_SETSOFTKBDPOS 0x0014 +#define IMC_GETSOFTKBDSUBTYPE 0x0015 +#define IMC_SETSOFTKBDSUBTYPE 0x0016 +#define IMC_SETSOFTKBDDATA 0x0018 /* wParam for WM_IME_SYSTEM */ #define IMS_NOTIFYIMESHOW 0x05 @@ -46,6 +57,9 @@ extern "C" { #define IMS_SETLANGBAND 0x23 #define IMS_UNSETLANGBAND 0x24 +/* wParam for WM_IME_NOTIFY */ +#define IMN_SOFTKBDDESTROYED 0x0011 + #define IMMGWL_IMC 0 #define IMMGWL_PRIVATE (sizeof(LONG)) @@ -59,7 +73,7 @@ typedef struct _tagINPUTCONTEXT { POINT ptSoftKbdPos; DWORD fdwConversion; DWORD fdwSentence; - union { + union { LOGFONTA A; LOGFONTW W; } lfFont;