/* * PROJECT: ReactOS IMM32 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Implementing IME Soft Keyboard * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ */ #include "precomp.h" #include "resource.h" WINE_DEFAULT_DEBUG_CHANNEL(imm); /* * 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 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, _In_ INT xMin, _In_ INT xMax) { if (x < xMin) return xMin; if (x > xMax) return xMax; return x; } static VOID Imm32GetAllMonitorSize( _Out_ LPRECT prcWork) { if (GetSystemMetrics(SM_CMONITORS) == 1) { SystemParametersInfoW(SPI_GETWORKAREA, 0, prcWork, 0); return; } prcWork->left = GetSystemMetrics(SM_XVIRTUALSCREEN); prcWork->top = GetSystemMetrics(SM_YVIRTUALSCREEN); prcWork->right = prcWork->left + GetSystemMetrics(SM_CXVIRTUALSCREEN); prcWork->bottom = prcWork->top + GetSystemMetrics(SM_CYVIRTUALSCREEN); } static BOOL Imm32GetNearestWorkArea( _In_opt_ HWND hwnd, _Out_ LPRECT prcWork) { HMONITOR hMonitor; MONITORINFO mi; if (GetSystemMetrics(SM_CMONITORS) == 1) { Imm32GetAllMonitorSize(prcWork); return TRUE; } 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; } /***************************************************************************** * IME Soft Keyboard Type T1 */ #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_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); 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); 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); 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); 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); 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, 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); 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); 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); 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); 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); 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); 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) { 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; } static void T1_DrawDragBorder( _In_ HWND hWnd, _In_ const POINT *ppt1, _In_ const POINT *ppt2) { 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; 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) { 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; } } 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 T1_IsValidButton( _In_ UINT iKey, _In_ const T1WINDOW *pT1) { if (iKey < T1K_BACKSPACE) return !!pT1->chKeyChar[iKey]; return iKey <= T1K_TAB || iKey == T1K_ENTER || (T1K_ESCAPE <= iKey && iKey <= T1K_SPACE); } /** * 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" #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) { switch (uMsg) { case WM_CREATE: { 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); } } 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(PT1WINDOW); wcx.hIcon = LoadIconW(NULL, (LPCWSTR)IDI_APPLICATION); wcx.hInstance = ghImm32Inst; wcx.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_SIZEALL); wcx.lpszClassName = pszClass; if (uType == SOFTKEYBOARD_TYPE_T1) { wcx.lpfnWndProc = T1_WindowProc; wcx.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); } else { wcx.lpfnWndProc = C1_WindowProc; wcx.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH); } return !!RegisterClassExW(&wcx); } static void Imm32GetSoftKeyboardDimension( _In_ UINT uType, _Out_ LPINT pcx, _Out_ LPINT pcy) { if (uType == SOFTKEYBOARD_TYPE_T1) { TEXTMETRICW tm; T1_GetTextMetric(&tm); *pcx = 15 * tm.tmMaxCharWidth + 2 * gptRaiseEdge.x + 139; *pcy = 5 * tm.tmHeight + 2 * gptRaiseEdge.y + 58; } else { INT cxEdge = GetSystemMetrics(SM_CXEDGE), cyEdge = GetSystemMetrics(SM_CXEDGE); *pcx = 2 * (GetSystemMetrics(SM_CXBORDER) + cxEdge) + 348; *pcy = 2 * (GetSystemMetrics(SM_CYBORDER) + cyEdge) + 136; } } /*********************************************************************** * ImmCreateSoftKeyboard (IMM32.@) * * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImmCreateSoftKeyboard.html */ HWND WINAPI ImmCreateSoftKeyboard( _In_ UINT uType, _In_ HWND hwndParent, _In_ INT x, _In_ INT y) { HKL hKL; PIMEDPI pImeDpi; 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 != 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 (IS_NULL_UNEXPECTEDLY(pImeDpi)) return NULL; /* No IME */ UICaps = pImeDpi->ImeInfo.fdwUICaps; ImmUnlockImeDpi(pImeDpi); /* Check IME capability */ if (!(UICaps & UI_CAP_SOFTKBD)) { ERR("UICaps: 0x%X\n", UICaps); return NULL; /* No capability for soft keyboard */ } /* 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); /* Adjust keyboard position */ xSoftKBD = Imm32Clamp(x, rcWorkArea.left, rcWorkArea.right - cxSoftKBD); ySoftKBD = Imm32Clamp(y, rcWorkArea.top , rcWorkArea.bottom - cySoftKBD); /* Create soft keyboard window */ if (uType == SOFTKEYBOARD_TYPE_T1) { Style = (WS_POPUP | WS_DISABLED); ExStyle = 0; pszClass = T1_CLASSNAMEW; } else { 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); return hwndSoftKBD; } /*********************************************************************** * ImmShowSoftKeyboard (IMM32.@) * * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImmShowSoftKeyboard.html */ BOOL WINAPI ImmShowSoftKeyboard( _In_ HWND hwndSoftKBD, _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); } /*********************************************************************** * ImmDestroySoftKeyboard (IMM32.@) * * @see https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/ImmDestroySoftKeyboard.html */ BOOL WINAPI ImmDestroySoftKeyboard( _In_ HWND hwndSoftKBD) { TRACE("(%p)\n", hwndSoftKBD); return DestroyWindow(hwndSoftKBD); }