mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
398 lines
9.9 KiB
398 lines
9.9 KiB
/*-----------------------------------------------------------------------
|
|
**
|
|
** Hotkey.c
|
|
**
|
|
** Hotkey edit control.
|
|
**
|
|
**-----------------------------------------------------------------------*/
|
|
//
|
|
// Win32 REVIEW:
|
|
// See all the Get/SetWindowInt().
|
|
//
|
|
#include "ctlspriv.h"
|
|
|
|
#define F_EXT 0x01000000L
|
|
|
|
#define GWU_VIRTKEY 0
|
|
#define GWU_MODS 1*sizeof(ULONG_PTR)
|
|
#define GWU_INVALID 2*sizeof(ULONG_PTR)
|
|
#define GWU_DEFAULT 3*sizeof(ULONG_PTR)
|
|
#define GWU_HFONT 4*sizeof(ULONG_PTR)
|
|
#define GWU_YFONT 5*sizeof(ULONG_PTR)
|
|
#define GWU_HTHEME 6*sizeof(ULONG_PTR)
|
|
#define NUM_WND_EXTRA (GWU_HTHEME+sizeof(ULONG_PTR))
|
|
|
|
LRESULT CALLBACK HotKeyWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
BOOL InitHotKeyClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.lpfnWndProc = HotKeyWndProc;
|
|
wc.lpszClassName = s_szHOTKEY_CLASS;
|
|
wc.style = CS_GLOBALCLASS;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = NUM_WND_EXTRA;
|
|
|
|
if (!RegisterClass(&wc) && !GetClassInfo(hInstance, s_szHOTKEY_CLASS, &wc))
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
const UINT s_Combos[8] = {
|
|
HKCOMB_NONE,
|
|
HKCOMB_S,
|
|
HKCOMB_C,
|
|
HKCOMB_SC,
|
|
HKCOMB_A,
|
|
HKCOMB_SA,
|
|
HKCOMB_CA,
|
|
HKCOMB_SCA};
|
|
|
|
void SetHotKey(HWND hwnd, WORD wVirtKey, WORD wMods, BOOL fSendNotify)
|
|
{
|
|
/* don't invalidate if it's the same
|
|
*/
|
|
if (wVirtKey == GetWindowInt(hwnd, GWU_VIRTKEY) &&
|
|
wMods == GetWindowInt(hwnd, GWU_MODS))
|
|
return;
|
|
|
|
SetWindowInt(hwnd, GWU_VIRTKEY ,wVirtKey);
|
|
SetWindowInt(hwnd, GWU_MODS ,wMods);
|
|
InvalidateRect(hwnd,NULL,TRUE);
|
|
|
|
if (fSendNotify) {
|
|
FORWARD_WM_COMMAND(GetParent(hwnd), GetDlgCtrlID(hwnd), hwnd, EN_CHANGE, SendMessage);
|
|
}
|
|
|
|
NotifyWinEvent(EVENT_OBJECT_VALUECHANGE, hwnd, OBJID_CLIENT, 0);
|
|
}
|
|
|
|
void GetKeyName(UINT vk, LPTSTR lpsz, BOOL fExt)
|
|
{
|
|
LONG scan;
|
|
|
|
scan = (LONG)MapVirtualKey(vk,0) << 16;
|
|
if (fExt)
|
|
scan |= F_EXT;
|
|
|
|
GetKeyNameText(scan,lpsz,50);
|
|
}
|
|
|
|
void PaintHotKey(register HWND hwnd)
|
|
{
|
|
TCHAR sz[128];
|
|
TCHAR szPlus[10];
|
|
int cch;
|
|
register HDC hdc;
|
|
UINT wMods;
|
|
UINT wVirtKey;
|
|
PAINTSTRUCT ps;
|
|
int x, y;
|
|
HANDLE hFont;
|
|
// DWORD dwColor;
|
|
// DWORD dwBkColor;
|
|
|
|
LocalizedLoadString(IDS_PLUS, szPlus, ARRAYSIZE(szPlus));
|
|
|
|
wVirtKey = (UINT) GetWindowInt(hwnd, GWU_VIRTKEY);
|
|
wMods = (UINT) GetWindowInt(hwnd, GWU_MODS);
|
|
if (wVirtKey || wMods)
|
|
{
|
|
sz[0] = 0;
|
|
cch = 0;
|
|
if (wMods & HOTKEYF_CONTROL)
|
|
{
|
|
GetKeyName(VK_CONTROL, sz, FALSE);
|
|
lstrcat(sz,(LPTSTR)szPlus);
|
|
}
|
|
if (wMods & HOTKEYF_SHIFT)
|
|
{
|
|
GetKeyName(VK_SHIFT, sz+lstrlen(sz), FALSE);
|
|
lstrcat(sz,szPlus);
|
|
}
|
|
if (wMods & HOTKEYF_ALT)
|
|
{
|
|
GetKeyName(VK_MENU, sz+lstrlen(sz), FALSE);
|
|
lstrcat(sz,szPlus);
|
|
}
|
|
|
|
GetKeyName(wVirtKey, sz+lstrlen(sz), wMods & HOTKEYF_EXT);
|
|
}
|
|
else
|
|
LocalizedLoadString(IDS_NONE,sz,100);
|
|
|
|
cch = lstrlen(sz);
|
|
|
|
HideCaret(hwnd);
|
|
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
hdc = BeginPaint(hwnd,&ps);
|
|
|
|
|
|
hFont = SelectObject(hdc, (HFONT)GetWindowInt(hwnd,GWU_HFONT));
|
|
|
|
x = g_cxBorder;
|
|
y = g_cyBorder;
|
|
|
|
if (IsWindowEnabled(hwnd))
|
|
{
|
|
SetBkColor(hdc, g_clrWindow);
|
|
SetTextColor(hdc, g_clrWindowText);
|
|
TextOut(hdc,x,y,sz,cch);
|
|
}
|
|
else
|
|
{
|
|
// set the background color to Grayed like edit controls
|
|
SetBkColor(hdc, g_clrBtnFace);
|
|
if (g_clrGrayText)
|
|
{
|
|
SetTextColor(hdc,g_clrGrayText);
|
|
TextOut(hdc,x,y,sz,cch);
|
|
}
|
|
else
|
|
{
|
|
GrayString(hdc,NULL,NULL,(ULONG_PTR)(LPTSTR)sz,cch,x,y,0,0);
|
|
}
|
|
}
|
|
|
|
MGetTextExtent(hdc, sz, cch, &x, NULL);
|
|
if (GetFocus() == hwnd)
|
|
SetCaretPos(x+g_cxBorder,
|
|
g_cyBorder);
|
|
ShowCaret(hwnd);
|
|
|
|
EndPaint(hwnd,&ps);
|
|
}
|
|
|
|
void HKMSetRules(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
SetWindowInt(hwnd, GWU_INVALID, wParam);
|
|
SetWindowInt(hwnd, GWU_DEFAULT, lParam);
|
|
}
|
|
|
|
HFONT HKMSetFont(HWND hwnd, HFONT wParam)
|
|
{
|
|
HFONT lParam;
|
|
HDC hdc;
|
|
INT cy;
|
|
|
|
lParam = (HFONT)GetWindowInt(hwnd,GWU_HFONT);
|
|
SetWindowInt(hwnd,GWU_HFONT,(LONG_PTR)wParam);
|
|
hdc = GetDC(hwnd);
|
|
if (wParam)
|
|
wParam = SelectObject(hdc, wParam);
|
|
MGetTextExtent(hdc, TEXT("C"), 1, NULL, &cy);
|
|
SetWindowInt(hwnd,GWU_YFONT,cy);
|
|
if (wParam)
|
|
SelectObject(hdc, wParam);
|
|
ReleaseDC(hwnd,hdc);
|
|
InvalidateRect(hwnd,NULL,TRUE);
|
|
return lParam;
|
|
}
|
|
|
|
LRESULT CALLBACK HotKeyWndProc(HWND hwnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
WORD wVirtKey;
|
|
WORD wMods;
|
|
RECT rc;
|
|
HDC hdc;
|
|
|
|
switch (wMsg)
|
|
{
|
|
case WM_NCCREATE:
|
|
SetWindowBits(hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);
|
|
InitGlobalColors();
|
|
return TRUE;
|
|
|
|
case WM_CREATE:
|
|
{
|
|
HTHEME hTheme;
|
|
SetHotKey(hwnd, 0, 0, FALSE);
|
|
HKMSetRules(hwnd, 0, 0);
|
|
HKMSetFont(hwnd, g_hfontSystem);
|
|
hTheme = OpenThemeData(hwnd, L"Combobox");
|
|
if (hTheme)
|
|
SetWindowLongPtr(hwnd, GWU_HTHEME, (ULONG_PTR)hTheme);
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
HTHEME hTheme = (HTHEME)GetWindowLongPtr(hwnd, GWU_HTHEME);
|
|
if (hTheme)
|
|
CloseThemeData(hTheme);
|
|
}
|
|
break;
|
|
|
|
case WM_NCPAINT:
|
|
{
|
|
HTHEME hTheme = (HTHEME)GetWindowLongPtr(hwnd, GWU_HTHEME);
|
|
if (hTheme)
|
|
{
|
|
HRGN hrgn = (wParam != 1) ? (HRGN)wParam : NULL;
|
|
HBRUSH hbr = (HBRUSH)GetClassLongPtr(hwnd, GCLP_HBRBACKGROUND);
|
|
|
|
if (CCDrawNonClientTheme(hTheme, hwnd, hrgn, hbr, 0, CBXS_NORMAL))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
goto DoDefault;
|
|
|
|
case WM_THEMECHANGED:
|
|
{
|
|
HTHEME hTheme = (HTHEME)GetWindowLongPtr(hwnd, GWU_HTHEME);
|
|
if (hTheme)
|
|
CloseThemeData(hTheme);
|
|
|
|
hTheme = OpenThemeData(hwnd, L"Combobox");
|
|
|
|
SetWindowLongPtr(hwnd, GWU_HTHEME, (ULONG_PTR)hTheme); // Set a NULL if OpenThemeData fails
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
case WM_SETFOCUS:
|
|
InvalidateRect(hwnd,NULL,TRUE);
|
|
CreateCaret(hwnd,NULL,0,(int)GetWindowInt(hwnd,GWU_YFONT));
|
|
ShowCaret(hwnd);
|
|
break;
|
|
|
|
case WM_KILLFOCUS:
|
|
if (!GetWindowInt(hwnd, GWU_VIRTKEY))
|
|
SetHotKey(hwnd, 0, 0, TRUE);
|
|
DestroyCaret();
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return DLGC_WANTCHARS | DLGC_WANTARROWS; // | DLGC_WANTALLKEYS;
|
|
|
|
case HKM_SETHOTKEY:
|
|
SetHotKey(hwnd, LOBYTE(wParam), HIBYTE(wParam), FALSE);
|
|
break;
|
|
|
|
case HKM_GETHOTKEY:
|
|
return (256*(BYTE)GetWindowInt(hwnd, GWU_MODS)) +
|
|
((BYTE)GetWindowInt(hwnd, GWU_VIRTKEY));
|
|
break;
|
|
|
|
case HKM_SETRULES:
|
|
HKMSetRules(hwnd, wParam, LOWORD(lParam));
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
SetFocus(hwnd);
|
|
break;
|
|
|
|
case WM_SYSKEYDOWN:
|
|
case WM_KEYDOWN:
|
|
switch (wParam)
|
|
{
|
|
case VK_RETURN:
|
|
case VK_TAB:
|
|
case VK_SPACE:
|
|
case VK_DELETE:
|
|
case VK_ESCAPE:
|
|
case VK_BACK:
|
|
case VK_LWIN:
|
|
case VK_RWIN:
|
|
case VK_APPS:
|
|
SetHotKey(hwnd, 0, 0, TRUE);
|
|
return DefWindowProc(hwnd,wMsg,wParam,lParam);
|
|
|
|
case VK_MENU:
|
|
case VK_SHIFT:
|
|
case VK_CONTROL:
|
|
wVirtKey = 0;
|
|
goto SetNewHotKey;
|
|
|
|
default:
|
|
wVirtKey = (WORD) wParam;
|
|
SetNewHotKey:
|
|
wMods = 0;
|
|
if (GetKeyState(VK_CONTROL) < 0)
|
|
wMods |= HOTKEYF_CONTROL;
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
wMods |= HOTKEYF_SHIFT;
|
|
if (GetKeyState(VK_MENU) < 0)
|
|
wMods |= HOTKEYF_ALT;
|
|
|
|
#define IsFUNKEY(vk) ((vk) >= VK_F1 && (vk) <= VK_F24)
|
|
#define IsNUMKEY(vk) ((vk) >= VK_NUMPAD0 && (vk) <= VK_DIVIDE)
|
|
|
|
//
|
|
// dont enforce any rules on the Function keys or
|
|
// on the number pad keys.
|
|
//
|
|
// if this combination is invalid, use the default
|
|
if (!IsFUNKEY(wVirtKey) &&
|
|
!IsNUMKEY(wVirtKey) &&
|
|
(s_Combos[wMods] & GetWindowInt(hwnd, GWU_INVALID)))
|
|
{
|
|
wMods = (WORD)GetWindowInt(hwnd, GWU_DEFAULT);
|
|
}
|
|
|
|
if (lParam & F_EXT)
|
|
wMods |= HOTKEYF_EXT;
|
|
|
|
SetHotKey(hwnd, wVirtKey, wMods, TRUE);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_SYSKEYUP:
|
|
case WM_CHAR:
|
|
case WM_SYSCHAR:
|
|
case WM_KEYUP:
|
|
if (!GetWindowInt(hwnd, GWU_VIRTKEY))
|
|
SetHotKey(hwnd, 0, 0, TRUE);
|
|
break;
|
|
|
|
case WM_GETFONT:
|
|
return GetWindowInt(hwnd,GWU_HFONT);
|
|
|
|
case WM_SETFONT:
|
|
return (LRESULT)(UINT_PTR)HKMSetFont(hwnd, (HFONT)wParam);
|
|
|
|
case WM_PAINT:
|
|
PaintHotKey(hwnd);
|
|
break;
|
|
|
|
case WM_ERASEBKGND:
|
|
HideCaret(hwnd);
|
|
hdc = GetDC(hwnd);
|
|
GetClientRect(hwnd, &rc);
|
|
if (IsWindowEnabled(hwnd)) {
|
|
FillRect(hdc, &rc, g_hbrWindow);
|
|
} else {
|
|
FillRect(hdc, &rc, g_hbrBtnFace);
|
|
}
|
|
ReleaseDC(hwnd, hdc);
|
|
// lParam = DefWindowProc(hwnd,wMsg,wParam,lParam);
|
|
ShowCaret(hwnd);
|
|
return TRUE;
|
|
|
|
case WM_GETOBJECT:
|
|
if( lParam == OBJID_QUERYCLASSNAMEIDX )
|
|
return MSAA_CLASSNAMEIDX_HOTKEY;
|
|
goto DoDefault;
|
|
|
|
case WM_ENABLE:
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
goto DoDefault;
|
|
|
|
default:
|
|
DoDefault:
|
|
return DefWindowProc(hwnd,wMsg,wParam,lParam);
|
|
}
|
|
return 0L;
|
|
}
|