credui: Display a warning balloon if the user has Caps Lock on.

This commit is contained in:
Rob Shearman 2007-11-19 18:31:44 +00:00 committed by Alexandre Julliard
parent 110f6e99e7
commit e35665fc47
3 changed files with 173 additions and 24 deletions

View File

@ -45,4 +45,6 @@ STRINGTABLE DISCARDABLE
IDS_MESSAGEFORMAT "Connecting to %s"
IDS_INCORRECTPASSWORDTITLE "Logon unsuccessful"
IDS_INCORRECTPASSWORD "Make sure that your user name\nand password are correct."
IDS_CAPSLOCKONTITLE "Caps Lock is On"
IDS_CAPSLOCKON "Having Caps Lock on may cause you to enter your password incorrectly.\n\nPress the Caps Lock key on your keyboard to turn off Caps Lock before\nentering your password."
}

View File

@ -35,6 +35,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(credui);
#define TOOLID_INCORRECTPASSWORD 1
#define TOOLID_CAPSLOCKON 2
#define ID_CAPSLOCKPOP 1
struct pending_credentials
{
struct list entry;
@ -130,6 +135,7 @@ struct cred_dialog_params
BOOL fSave;
DWORD dwFlags;
HWND hwndBalloonTip;
BOOL fBalloonTipActive;
};
static void CredDialogFillUsernameCombo(HWND hwndUsername, struct cred_dialog_params *params)
@ -178,32 +184,14 @@ static void CredDialogFillUsernameCombo(HWND hwndUsername, struct cred_dialog_pa
CredFree(credentials);
}
static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dialog_params *params)
static void CredDialogCreateBalloonTip(HWND hwndDlg, struct cred_dialog_params *params)
{
TTTOOLINFOW toolinfo;
RECT rcPassword;
INT x;
INT y;
WCHAR wszTitle[256];
WCHAR wszText[256];
/* user name likely wrong so balloon would be confusing. focus is also
* not set to the password edit box, so more notification would need to be
* handled */
if (!params->pszUsername[0])
if (params->hwndBalloonTip)
return;
if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORDTITLE, wszTitle, sizeof(wszTitle)/sizeof(wszTitle[0])))
{
ERR("failed to load IDS_INCORRECTPASSWORDTITLE\n");
return;
}
if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORD, wszText, sizeof(wszText)/sizeof(wszText[0])))
{
ERR("failed to load IDS_INCORRECTPASSWORD\n");
return;
}
params->hwndBalloonTip = CreateWindowExW(WS_EX_TOOLWINDOW, TOOLTIPS_CLASSW,
NULL, WS_POPUP | TTS_NOPREFIX | TTS_BALLOON, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, NULL,
@ -211,10 +199,16 @@ static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dia
SetWindowPos(params->hwndBalloonTip, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORD, wszText, sizeof(wszText)/sizeof(wszText[0])))
{
ERR("failed to load IDS_INCORRECTPASSWORD\n");
return;
}
toolinfo.cbSize = sizeof(toolinfo);
toolinfo.uFlags = TTF_TRACK;
toolinfo.hwnd = hwndDlg;
toolinfo.uId = 0;
toolinfo.uId = TOOLID_INCORRECTPASSWORD;
memset(&toolinfo.rect, 0, sizeof(toolinfo.rect));
toolinfo.hinst = NULL;
toolinfo.lpszText = wszText;
@ -222,6 +216,47 @@ static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dia
toolinfo.lpReserved = NULL;
SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo);
if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKON, wszText, sizeof(wszText)/sizeof(wszText[0])))
{
ERR("failed to load IDS_CAPSLOCKON\n");
return;
}
toolinfo.uId = TOOLID_CAPSLOCKON;
SendMessageW(params->hwndBalloonTip, TTM_ADDTOOLW, 0, (LPARAM)&toolinfo);
}
static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dialog_params *params)
{
TTTOOLINFOW toolinfo;
RECT rcPassword;
INT x;
INT y;
WCHAR wszTitle[256];
/* user name likely wrong so balloon would be confusing. focus is also
* not set to the password edit box, so more notification would need to be
* handled */
if (!params->pszUsername[0])
return;
/* don't show two balloon tips at once */
if (params->fBalloonTipActive)
return;
if (!LoadStringW(hinstCredUI, IDS_INCORRECTPASSWORDTITLE, wszTitle, sizeof(wszTitle)/sizeof(wszTitle[0])))
{
ERR("failed to load IDS_INCORRECTPASSWORDTITLE\n");
return;
}
CredDialogCreateBalloonTip(hwndDlg, params);
memset(&toolinfo, 0, sizeof(toolinfo));
toolinfo.cbSize = sizeof(toolinfo);
toolinfo.hwnd = hwndDlg;
toolinfo.uId = TOOLID_INCORRECTPASSWORD;
SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_ERROR, (LPARAM)wszTitle);
GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword);
@ -231,13 +266,97 @@ static void CredDialogShowIncorrectPasswordBalloon(HWND hwndDlg, struct cred_dia
SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo);
params->fBalloonTipActive = TRUE;
}
static void CredDialogShowCapsLockBalloon(HWND hwndDlg, struct cred_dialog_params *params)
{
TTTOOLINFOW toolinfo;
RECT rcPassword;
INT x;
INT y;
WCHAR wszTitle[256];
/* don't show two balloon tips at once */
if (params->fBalloonTipActive)
return;
if (!LoadStringW(hinstCredUI, IDS_CAPSLOCKONTITLE, wszTitle, sizeof(wszTitle)/sizeof(wszTitle[0])))
{
ERR("failed to load IDS_IDSCAPSLOCKONTITLE\n");
return;
}
CredDialogCreateBalloonTip(hwndDlg, params);
memset(&toolinfo, 0, sizeof(toolinfo));
toolinfo.cbSize = sizeof(toolinfo);
toolinfo.hwnd = hwndDlg;
toolinfo.uId = TOOLID_CAPSLOCKON;
SendMessageW(params->hwndBalloonTip, TTM_SETTITLEW, TTI_WARNING, (LPARAM)wszTitle);
GetWindowRect(GetDlgItem(hwndDlg, IDC_PASSWORD), &rcPassword);
/* just inside the left side of the password edit control */
x = rcPassword.left + 12;
y = rcPassword.bottom - 3;
SendMessageW(params->hwndBalloonTip, TTM_TRACKPOSITION, 0, MAKELONG(x, y));
SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&toolinfo);
SetTimer(hwndDlg, ID_CAPSLOCKPOP,
SendMessageW(params->hwndBalloonTip, TTM_GETDELAYTIME, TTDT_AUTOPOP, 0),
NULL);
params->fBalloonTipActive = TRUE;
}
static void CredDialogHideBalloonTip(HWND hwndDlg, struct cred_dialog_params *params)
{
/* we don't need the balloon tip again, so destroy it */
DestroyWindow(params->hwndBalloonTip);
params->hwndBalloonTip = NULL;
TTTOOLINFOW toolinfo;
if (!params->hwndBalloonTip)
return;
memset(&toolinfo, 0, sizeof(toolinfo));
toolinfo.cbSize = sizeof(toolinfo);
toolinfo.hwnd = hwndDlg;
toolinfo.uId = 0;
SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo);
toolinfo.uId = 1;
SendMessageW(params->hwndBalloonTip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&toolinfo);
params->fBalloonTipActive = FALSE;
}
static inline BOOL CredDialogCapsLockOn(void)
{
return GetKeyState(VK_CAPITAL) & 0x1 ? TRUE : FALSE;
}
static LRESULT CALLBACK CredDialogPasswordSubclassProc(HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
struct cred_dialog_params *params = (struct cred_dialog_params *)dwRefData;
switch (uMsg)
{
case WM_KEYDOWN:
if (wParam == VK_CAPITAL)
{
HWND hwndDlg = GetParent(hwnd);
if (CredDialogCapsLockOn())
CredDialogShowCapsLockBalloon(hwndDlg, params);
else
CredDialogHideBalloonTip(hwndDlg, params);
}
break;
case WM_DESTROY:
RemoveWindowSubclass(hwnd, CredDialogPasswordSubclassProc, uIdSubclass);
break;
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
static BOOL CredDialogInit(HWND hwndDlg, struct cred_dialog_params *params)
@ -267,7 +386,12 @@ static BOOL CredDialogInit(HWND hwndDlg, struct cred_dialog_params *params)
CredDialogFillUsernameCombo(hwndUsername, params);
if (params->pszUsername[0])
{
/* prevent showing a balloon tip here */
params->fBalloonTipActive = TRUE;
SetFocus(hwndPassword);
params->fBalloonTipActive = FALSE;
}
else
SetFocus(hwndUsername);
@ -287,8 +411,13 @@ static BOOL CredDialogInit(HWND hwndDlg, struct cred_dialog_params *params)
else if (params->fSave)
CheckDlgButton(hwndDlg, IDC_SAVE, BST_CHECKED);
/* setup subclassing for Caps Lock detection */
SetWindowSubclass(hwndPassword, CredDialogPasswordSubclassProc, 1, (DWORD_PTR)params);
if (params->dwFlags & CREDUI_FLAGS_INCORRECT_PASSWORD)
CredDialogShowIncorrectPasswordBalloon(hwndDlg, params);
else if ((GetFocus() == hwndPassword) && CredDialogCapsLockOn())
CredDialogShowCapsLockBalloon(hwndDlg, params);
return FALSE;
}
@ -361,6 +490,12 @@ static INT_PTR CALLBACK CredDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
EndDialog(hwndDlg, IDCANCEL);
return TRUE;
case MAKELONG(IDC_PASSWORD, EN_SETFOCUS):
if (CredDialogCapsLockOn())
{
struct cred_dialog_params *params =
(struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
CredDialogShowCapsLockBalloon(hwndDlg, params);
}
/* don't allow another window to steal focus while the
* user is typing their password */
LockSetForegroundWindow(LSFW_LOCK);
@ -384,6 +519,15 @@ static INT_PTR CALLBACK CredDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
}
}
return FALSE;
case WM_TIMER:
if (wParam == ID_CAPSLOCKPOP)
{
struct cred_dialog_params *params =
(struct cred_dialog_params *)GetWindowLongPtrW(hwndDlg, DWLP_USER);
CredDialogHideBalloonTip(hwndDlg, params);
return TRUE;
}
return FALSE;
case WM_DESTROY:
{
struct cred_dialog_params *params =
@ -446,6 +590,7 @@ DWORD WINAPI CredUIPromptForCredentialsW(PCREDUI_INFOW pUIInfo,
params.fSave = pfSave ? *pfSave : FALSE;
params.dwFlags = dwFlags;
params.hwndBalloonTip = NULL;
params.fBalloonTipActive = FALSE;
ret = DialogBoxParamW(hinstCredUI, MAKEINTRESOURCEW(IDD_CREDDIALOG),
pUIInfo ? pUIInfo->hwndParent : NULL,

View File

@ -29,3 +29,5 @@
#define IDS_MESSAGEFORMAT 301
#define IDS_INCORRECTPASSWORDTITLE 302
#define IDS_INCORRECTPASSWORD 303
#define IDS_CAPSLOCKON 304
#define IDS_CAPSLOCKONTITLE 305