WindowsXP-SP1/shell/comctl32/v6/hotkey.c

399 lines
10 KiB
C

/*-----------------------------------------------------------------------
**
** 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;
}