825 lines
27 KiB
C
825 lines
27 KiB
C
// **************************************************************************
|
|
// Filterkeys dialogs
|
|
// Process the filterkeys dialogs
|
|
// **************************************************************************
|
|
|
|
|
|
#include "Access.h"
|
|
|
|
extern DWORD g_dwOrigFKFlags;
|
|
extern BOOL g_bFKOn;
|
|
|
|
#define SWAP(A, B) ( A ^= B, B ^= A, A ^= B )
|
|
|
|
// Prototypes
|
|
INT_PTR WINAPI BKDlg (HWND, UINT, WPARAM, LPARAM);
|
|
INT_PTR WINAPI RKDlg (HWND, UINT, WPARAM, LPARAM);
|
|
BOOL WINAPI NotificationDlg (HWND, UINT, WPARAM, LPARAM);
|
|
BOOL SubclassFilterKeysTestBox (UINT uIdTestBox,HWND hDlg);
|
|
BOOL SubclassRepeatKeysTestBox (UINT uIdTestBox,HWND hDlg);
|
|
|
|
// All these are for subclassing, so that pressing TAB stops at the next
|
|
// control after test areas. a-anilk
|
|
LRESULT CALLBACK SubclassWndProcFKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
|
LRESULT CALLBACK SubclassWndProcFKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
|
LRESULT CALLBACK SubclassWndProcRKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
|
LRESULT CALLBACK SubclassWndProcRKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
|
|
|
|
// Times are in milliseconds
|
|
#define DELAYSIZE 5
|
|
UINT uDelayTable[] = { 300, 700, 1000, 1500, 2000 };
|
|
|
|
// Times are in milliseconds
|
|
#define RATESIZE 6
|
|
UINT uRateTable[] = { 300, 500, 700, 1000, 1500, 2000 };
|
|
|
|
// Times are in milliseconds
|
|
#define BOUNCESIZE 5
|
|
UINT uBounceTable[] = { 500, 700, 1000, 1500, 2000 };
|
|
|
|
// Times are in milliseconds
|
|
// TODO 5, 10, and 20 sec needs change to kernel code (SystemParametersInfo)
|
|
#define ACCEPTSIZE 10
|
|
UINT uAcceptTable[] = { 0, 300, 500, 700, 1000, 1400, 2000, 5000, 10000, 20000 };
|
|
|
|
// these are wndprocs for subclassed windows to ignore repeated tab keys in
|
|
// some situations.
|
|
WNDPROC g_WndProcFKPrev = NULL;
|
|
WNDPROC g_WndProcFKNext = NULL;
|
|
WNDPROC g_WndProcRKPrev = NULL;
|
|
WNDPROC g_WndProcRKNext = NULL;
|
|
|
|
// other definitions for the keyboard
|
|
// UP means key was up before this message, DOWN means key was down
|
|
// PRESS means the key is being pressed, RELEASE means key being released
|
|
|
|
#define KEY_UP 0
|
|
#define KEY_DOWN 1
|
|
|
|
#define KEY_PRESS 0
|
|
#define KEY_RELEASE 1
|
|
|
|
// Macros to look at the lParam of keyboard messages
|
|
//
|
|
#define SCAN_CODE(theParam) (LOBYTE (HIWORD(theParam)))
|
|
#define EXTENDED(theParam) ( (HIWORD (theParam) & 0x0100) > 0)
|
|
#define SYSKEY(theParam) ( (HIWORD (theParam) & 0x2000) > 0)
|
|
#define MENUMODE(theParam) ( (HIWORD (theParam) & 0x1000) > 0)
|
|
#define PREV_STATE(theParam) ( (HIWORD (theParam) & 0x4000) > 0)
|
|
#define TRAN_STATE(theParam) ( (HIWORD (theParam) & 0x8000) > 0)
|
|
|
|
#define MAKE(theParam) (TRAN_STATE(theParam) == KEY_PRESS)
|
|
#define BREAK(theParam) (TRAN_STATE(theParam) == KEY_RELEASE)
|
|
#define WASUP(theParam) (PREV_STATE(theParam) == KEY_UP)
|
|
#define WASDOWN(theParam) (PREV_STATE(theParam) == KEY_DOWN)
|
|
|
|
#define FIRSTHIT(theParam) (WASUP(theParam) && MAKE(theParam))
|
|
|
|
// *************************************************************************
|
|
// Process the scrolling messages from our trackbars.
|
|
// GENERIC CODE - called for any TrackBar handler.
|
|
// Passed in the hwnd, wParam, hwndScroll
|
|
// we can do all handling and return the new trackbar value without
|
|
// knowing what control it is.
|
|
// Returns -1 to mean don't do anything
|
|
// *************************************************************************
|
|
|
|
int HandleScroll (HWND hwnd, WPARAM wParam, HWND hwndScroll) {
|
|
int nCurSliderPos = (int) SendMessage(
|
|
hwndScroll, TBM_GETPOS, 0, 0);
|
|
int nMaxVal = (int) SendMessage(
|
|
hwndScroll, TBM_GETRANGEMAX, 0, 0);
|
|
int nMinVal = (int) SendMessage(
|
|
hwndScroll, TBM_GETRANGEMIN, 0, 0);
|
|
|
|
switch (LOWORD(wParam)) {
|
|
case TB_LINEUP:
|
|
case TB_LINEDOWN:
|
|
case TB_THUMBTRACK:
|
|
case TB_THUMBPOSITION:
|
|
case SB_ENDSCROLL:
|
|
break;
|
|
|
|
case TB_BOTTOM:
|
|
nCurSliderPos = nMaxVal;
|
|
break;
|
|
|
|
case TB_TOP:
|
|
nCurSliderPos = nMinVal;
|
|
break;
|
|
}
|
|
|
|
if (nCurSliderPos < nMinVal)
|
|
{
|
|
nCurSliderPos = nMinVal;
|
|
}
|
|
|
|
if (nCurSliderPos > nMaxVal)
|
|
{
|
|
nCurSliderPos = nMaxVal;
|
|
}
|
|
|
|
SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM) hwnd, 0);
|
|
return(nCurSliderPos);
|
|
}
|
|
|
|
// Helper functions
|
|
|
|
__inline WriteFloat(LPTSTR pszBuf, UINT uVal, LPCTSTR pszUnits)
|
|
{
|
|
wsprintf(pszBuf, TEXT("%d.%d %s"), uVal/1000, (uVal % 1000)/100, pszUnits);
|
|
}
|
|
|
|
__inline void HandleSelection(HWND hwnd, UINT *puTable, DWORD *pdwNewValue)
|
|
{
|
|
LRESULT i = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
|
|
*pdwNewValue = (i != CB_ERR)?puTable[i]:0;
|
|
}
|
|
|
|
int GetIndex(DWORD dwValue, UINT *puTable, int cSize)
|
|
{
|
|
int i;
|
|
for (i = 0; i < cSize; i++)
|
|
{
|
|
if (puTable[i] >= dwValue)
|
|
break;
|
|
}
|
|
|
|
if (i >= cSize)
|
|
i = cSize - 1;
|
|
|
|
return i;
|
|
}
|
|
|
|
void FillAndSetCombo(HWND hwnd, UINT *puTable, int cItems, int iCurPos, LPCTSTR pszUnits)
|
|
{
|
|
int i;
|
|
TCHAR pszItem[100];
|
|
|
|
SendMessage(hwnd, CB_RESETCONTENT, 0, 0);
|
|
for (i=0;i<cItems;i++)
|
|
{
|
|
WriteFloat(pszItem, puTable[i], pszUnits);
|
|
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)pszItem);
|
|
}
|
|
SendMessage(hwnd, CB_SETCURSEL, iCurPos, 0);
|
|
}
|
|
|
|
void TestFilterKeys (BOOL fTurnTestOn)
|
|
{
|
|
if (fTurnTestOn)
|
|
{
|
|
g_fk.dwFlags &= ~FKF_INDICATOR;
|
|
g_fk.dwFlags |= FKF_FILTERKEYSON;
|
|
}
|
|
else
|
|
{
|
|
if (g_dwOrigFKFlags & FKF_FILTERKEYSON)
|
|
{
|
|
g_fk.dwFlags |= FKF_FILTERKEYSON;
|
|
}
|
|
else
|
|
{
|
|
g_fk.dwFlags &= ~FKF_FILTERKEYSON;
|
|
}
|
|
|
|
if (g_dwOrigFKFlags & FKF_INDICATOR)
|
|
{
|
|
g_fk.dwFlags |= FKF_INDICATOR;
|
|
}
|
|
else
|
|
{
|
|
g_fk.dwFlags &= ~FKF_INDICATOR;
|
|
}
|
|
}
|
|
|
|
AccessSystemParametersInfo(SPI_SETFILTERKEYS, sizeof(g_fk), &g_fk, 0);
|
|
}
|
|
|
|
|
|
// ****************************************************************************
|
|
// Main filter keys dialog handler
|
|
// ****************************************************************************
|
|
|
|
INT_PTR WINAPI FilterKeyDlg (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
FILTERKEYS fk;
|
|
BOOL fProcessed = TRUE;
|
|
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
// Setup hotkey
|
|
CheckDlgButton(hwnd, IDC_FK_HOTKEY, (g_fk.dwFlags & FKF_HOTKEYACTIVE) ? TRUE : FALSE);
|
|
|
|
// Setup the radio buttons for SLOW vs BOUNCE keys
|
|
if (0 != g_fk.iBounceMSec) {
|
|
// Bounce keys enabeled
|
|
CheckRadioButton(hwnd, IDC_FK_BOUNCE, IDC_FK_REPEAT, IDC_FK_BOUNCE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), FALSE);
|
|
}
|
|
else
|
|
{
|
|
// Slow key enabled
|
|
CheckRadioButton(hwnd, IDC_FK_BOUNCE, IDC_FK_REPEAT, IDC_FK_REPEAT);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), TRUE);
|
|
}
|
|
|
|
CheckDlgButton(hwnd, IDC_FK_SOUND, (g_fk.dwFlags & FKF_CLICKON) ? TRUE : FALSE);
|
|
CheckDlgButton(hwnd, IDC_FK_STATUS, (g_fk.dwFlags & FKF_INDICATOR) ? TRUE : FALSE);
|
|
//
|
|
// SteveDon 5/15/98
|
|
// If the focus is in the TestBox and "Ignore Quick Keystrokes" is on,
|
|
// you have to hold down tab to get out. But as soon as focus leaves,
|
|
// Ignore Quick Keystrokes gets turned off and the tab keys ends up
|
|
// autorepeating very quickly, which (usually) lands you back in the
|
|
// TestBox.
|
|
// Solution: ignore repeated tabs in this dialog.
|
|
// Problem: keys don't go to the dialog, they go to the focused
|
|
// control. So: we can try to ignore repeated tab keys for the controls
|
|
// just after the test box and just before the test box, which means
|
|
// that we need to subclass those window procs.
|
|
if (!SubclassFilterKeysTestBox (IDC_FK_TESTBOX,hwnd))
|
|
return (FALSE);
|
|
|
|
break;
|
|
|
|
case WM_HELP:
|
|
WinHelp(((LPHELPINFO) lParam)->hItemHandle, __TEXT("access.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_aIds);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU:
|
|
WinHelp((HWND) wParam, __TEXT("access.hlp"), HELP_CONTEXTMENU, (DWORD_PTR) (LPSTR) g_aIds);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
case IDC_FK_HOTKEY:
|
|
g_fk.dwFlags ^= FKF_HOTKEYACTIVE;
|
|
break;
|
|
|
|
case IDC_FK_REPEAT:
|
|
g_fk.iBounceMSec = 0;
|
|
|
|
if (g_fk.iDelayMSec == 0)
|
|
{
|
|
g_fk.iDelayMSec = g_nLastRepeatDelay;
|
|
g_fk.iRepeatMSec = g_nLastRepeatRate;
|
|
g_fk.iWaitMSec = g_nLastWait;
|
|
}
|
|
|
|
CheckRadioButton(hwnd, IDC_FK_REPEAT, IDC_FK_BOUNCE, IDC_FK_REPEAT);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), TRUE);
|
|
break;
|
|
|
|
case IDC_FK_BOUNCE:
|
|
g_fk.iDelayMSec = 0;
|
|
g_fk.iRepeatMSec = 0;
|
|
g_fk.iWaitMSec = 0;
|
|
|
|
if (g_fk.iBounceMSec == 0)
|
|
{
|
|
g_fk.iBounceMSec = g_dwLastBounceKeySetting;
|
|
}
|
|
|
|
CheckRadioButton(hwnd, IDC_FK_REPEAT, IDC_FK_BOUNCE, IDC_FK_BOUNCE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_BK_SETTINGS), TRUE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_RK_SETTINGS), FALSE);
|
|
break;
|
|
|
|
// Settings dialogs
|
|
case IDC_RK_SETTINGS: // This is RepeatKeys
|
|
fk = g_fk;
|
|
if (DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ADVCHARREPEAT), hwnd, RKDlg) == IDCANCEL) {
|
|
g_fk = fk;
|
|
}
|
|
break;
|
|
|
|
case IDC_BK_SETTINGS: // This is BounceKeys
|
|
fk = g_fk;
|
|
if (DialogBox(g_hinst, MAKEINTRESOURCE(IDD_ADVKEYBOUNCE), hwnd, BKDlg) == IDCANCEL) {
|
|
g_fk = fk;
|
|
}
|
|
break;
|
|
|
|
case IDC_FK_SOUND:
|
|
g_fk.dwFlags ^= FKF_CLICKON;
|
|
break;
|
|
|
|
case IDC_FK_STATUS:
|
|
g_fk.dwFlags ^= FKF_INDICATOR;
|
|
break;
|
|
|
|
// The test edit box is a special control for us. When we get the
|
|
// focus we turn on the current filterkeys settings, when we
|
|
// leave the text box, we turn them back to what they were.
|
|
case IDC_FK_TESTBOX:
|
|
switch (HIWORD(wParam)) {
|
|
case EN_SETFOCUS: TestFilterKeys(TRUE); break;
|
|
case EN_KILLFOCUS: TestFilterKeys(FALSE); break;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
if (g_dwLastBounceKeySetting == 0)
|
|
g_dwLastBounceKeySetting = uBounceTable[0];
|
|
EndDialog(hwnd, IDOK);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hwnd, IDCANCEL);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fProcessed = FALSE; break;
|
|
}
|
|
return(fProcessed);
|
|
}
|
|
|
|
|
|
void PutNumInEdit (HWND hwndEdit, int nNum)
|
|
{
|
|
TCHAR szBuf[10], szBuf2[20];
|
|
wsprintf(szBuf, __TEXT("%d.%d"), nNum / 1000, (nNum % 1000) / 100);
|
|
GetNumberFormat(LOCALE_USER_DEFAULT, 0, szBuf, NULL, szBuf2, 20);
|
|
SetWindowText(hwndEdit, szBuf2);
|
|
}
|
|
|
|
|
|
// **************************************************************************
|
|
// BKDlg
|
|
// Process the BounceKeys dialog.
|
|
// **************************************************************************
|
|
INT_PTR WINAPI BKDlg (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
int i;
|
|
BOOL fProcessed = TRUE;
|
|
TCHAR pszSeconds[50];
|
|
int ctch;
|
|
|
|
switch (uMsg) {
|
|
case WM_INITDIALOG:
|
|
ctch = LoadString(g_hinst, IDS_SECONDS, pszSeconds, ARRAY_SIZE(pszSeconds));
|
|
Assert(ctch);
|
|
// Determine the bounce. Make sure its a valide value.
|
|
if (g_dwLastBounceKeySetting == 0)
|
|
g_dwLastBounceKeySetting = 500;
|
|
|
|
if (g_fk.iBounceMSec == 0)
|
|
g_fk.iBounceMSec = g_dwLastBounceKeySetting;
|
|
|
|
i = GetIndex(g_fk.iBounceMSec, uBounceTable, BOUNCESIZE);
|
|
FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_BK_BOUNCERATE), uBounceTable, BOUNCESIZE, i, pszSeconds);
|
|
break;
|
|
|
|
case WM_HELP: // F1
|
|
WinHelp(((LPHELPINFO) lParam)->hItemHandle, __TEXT("access.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_aIds);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU: // right mouse click
|
|
WinHelp((HWND) wParam, __TEXT("access.hlp"), HELP_CONTEXTMENU, (DWORD_PTR) (LPSTR) g_aIds);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
// The test edit box is a special control for us. When we get the
|
|
// focus we turn on the current filterkeys settings, when we
|
|
// leave the text box, we turn them back to what they were.
|
|
case IDC_BK_TESTBOX:
|
|
switch (HIWORD(wParam)) {
|
|
case EN_SETFOCUS: TestFilterKeys(TRUE); break;
|
|
case EN_KILLFOCUS: TestFilterKeys(FALSE); break;
|
|
}
|
|
break;
|
|
|
|
case IDC_CMB_BK_BOUNCERATE:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case CBN_SELCHANGE:
|
|
HandleSelection(GetDlgItem(hwnd, IDC_CMB_BK_BOUNCERATE), uBounceTable, &g_fk.iBounceMSec);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
// Save the last known valid setting.
|
|
g_dwLastBounceKeySetting = g_fk.iBounceMSec;
|
|
EndDialog(hwnd, IDOK);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hwnd, IDCANCEL);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default: fProcessed = FALSE; break;
|
|
}
|
|
return(fProcessed);
|
|
}
|
|
|
|
// **************************************************************************
|
|
// RKDlg
|
|
// Process the RepeatKeys dialog.
|
|
// **************************************************************************
|
|
|
|
INT_PTR WINAPI RKDlg (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
|
int i;
|
|
BOOL fProcessed = TRUE;
|
|
static s_fRepeating = TRUE;
|
|
static DWORD s_nLastRepeatDelayOld;
|
|
static DWORD s_nLastRepeatRateOld;
|
|
static DWORD s_nLastWaitOld;
|
|
TCHAR pszItem[100];
|
|
TCHAR pszSeconds[50];
|
|
int ctch;
|
|
LPARAM lParamT;
|
|
|
|
switch(uMsg) {
|
|
case WM_INITDIALOG:
|
|
ctch = LoadString(g_hinst, IDS_SECONDS, pszSeconds, ARRAY_SIZE(pszSeconds));
|
|
Assert(ctch);
|
|
|
|
s_nLastRepeatDelayOld = g_nLastRepeatDelay;
|
|
s_nLastRepeatRateOld = g_nLastRepeatRate;
|
|
s_nLastWaitOld = g_nLastWait;
|
|
|
|
s_fRepeating = (0 != g_fk.iDelayMSec);
|
|
CheckRadioButton(hwnd, IDC_RK_NOREPEAT, IDC_RK_REPEAT,
|
|
s_fRepeating ? IDC_RK_REPEAT : IDC_RK_NOREPEAT);
|
|
|
|
if (!s_fRepeating) {
|
|
// Set FilterKey values to LastRepeat values
|
|
// so the sliders will still get initialized correctly
|
|
g_fk.iDelayMSec = g_nLastRepeatDelay;
|
|
g_fk.iRepeatMSec = g_nLastRepeatRate;
|
|
}
|
|
|
|
// Initialize the Acceptance combo box to last valid state
|
|
i = GetIndex(g_fk.iWaitMSec, uAcceptTable, ACCEPTSIZE);
|
|
FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_RK_ACCEPTRATE), uAcceptTable, ACCEPTSIZE, i, pszSeconds);
|
|
g_fk.iWaitMSec = uAcceptTable[i];
|
|
|
|
// Initialize the Delay combo box
|
|
i = GetIndex(g_fk.iDelayMSec, uDelayTable, DELAYSIZE);
|
|
FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), uDelayTable, DELAYSIZE, i, pszSeconds);
|
|
g_fk.iDelayMSec = uDelayTable[i];
|
|
|
|
// Initialize the Repeat Rate Slider Note -1 is set via the checkbox.
|
|
i = GetIndex(g_fk.iRepeatMSec, uRateTable, RATESIZE);
|
|
FillAndSetCombo(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), uRateTable, RATESIZE, i, pszSeconds);
|
|
g_fk.iRepeatMSec = uRateTable[i];
|
|
|
|
// Now cleanup from initialization. Disable controls
|
|
// that usable... Swap back any params needed
|
|
if (!s_fRepeating)
|
|
{
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), FALSE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), FALSE);
|
|
|
|
// If we're not repeating, now set the value to 0
|
|
// which indicates max repeat rate.
|
|
g_fk.iDelayMSec = 0;
|
|
g_fk.iRepeatMSec = 0;
|
|
}
|
|
//
|
|
// SteveDon 5/15/98
|
|
// If the focus is in the TestBox and "Ignore Quick Keystrokes" is on,
|
|
// you have to hold down tab to get out. But as soon as focus leaves,
|
|
// Ignore Quick Keystrokes gets turned off and the tab keys ends up
|
|
// autorepeating very quickly, which (usually) lands you back in the
|
|
// TestBox.
|
|
// Solution: ignore repeated tabs in this dialog.
|
|
// Problem: keys don't go to the dialog, they go to the focused
|
|
// control. So: we can try to ignore repeated tab keys for the controls
|
|
// just after the test box and just before the test box, which means
|
|
// that we need to subclass those window procs.
|
|
if (!SubclassRepeatKeysTestBox (IDC_RK_TESTBOX,hwnd))
|
|
return (FALSE);
|
|
break;
|
|
|
|
case WM_HELP: // F1
|
|
WinHelp(((LPHELPINFO) lParam)->hItemHandle, __TEXT("access.hlp"), HELP_WM_HELP, (DWORD_PTR) (LPSTR) g_aIds);
|
|
break;
|
|
|
|
case WM_CONTEXTMENU: // right mouse click
|
|
WinHelp((HWND) wParam, __TEXT("access.hlp"), HELP_CONTEXTMENU, (DWORD_PTR) (LPSTR) g_aIds);
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
|
|
// Turn on repeat keys - We're disabling via CPL rather than any flags in the call
|
|
case IDC_RK_REPEAT:
|
|
if (!s_fRepeating) {
|
|
g_fk.iDelayMSec = g_nLastRepeatDelay;
|
|
g_fk.iRepeatMSec = g_nLastRepeatRate;
|
|
}
|
|
|
|
// Now that we have valid parameters, continue with setting the sliders.
|
|
s_fRepeating = TRUE;
|
|
CheckRadioButton(hwnd, IDC_RK_NOREPEAT, IDC_RK_REPEAT, IDC_RK_REPEAT);
|
|
if (g_fk.iRepeatMSec == 0)
|
|
g_fk.iRepeatMSec = uRateTable[0];
|
|
if (g_fk.iDelayMSec == 0)
|
|
g_fk.iDelayMSec = uDelayTable[0];
|
|
|
|
i = GetIndex(g_fk.iRepeatMSec, uRateTable, RATESIZE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), TRUE);
|
|
SendDlgItemMessage(hwnd, IDC_CMB_RK_REPEATRATE, CB_SETCURSEL, i, 0);
|
|
i = GetIndex(g_fk.iDelayMSec, uDelayTable, DELAYSIZE);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), TRUE);
|
|
SendDlgItemMessage(hwnd, IDC_CMB_RK_DELAYRATE, CB_SETCURSEL, i, 0);
|
|
break;
|
|
|
|
// Turn OFF repeat keys
|
|
case IDC_RK_NOREPEAT:
|
|
s_fRepeating = FALSE;
|
|
CheckRadioButton(hwnd, IDC_RK_NOREPEAT, IDC_RK_REPEAT, IDC_RK_NOREPEAT);
|
|
g_fk.iDelayMSec = 0;
|
|
g_fk.iRepeatMSec = 0;
|
|
SendDlgItemMessage(hwnd, IDC_CMB_RK_DELAYRATE, CB_SETCURSEL, -1, 0);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), FALSE);
|
|
SendDlgItemMessage(hwnd, IDC_CMB_RK_REPEATRATE, CB_SETCURSEL, -1, 0);
|
|
EnableWindow(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), FALSE);
|
|
break;
|
|
|
|
// Process the test box - turnon filterkeys while inside it.
|
|
case IDC_RK_TESTBOX:
|
|
switch (HIWORD(wParam)) {
|
|
case EN_SETFOCUS: TestFilterKeys(TRUE); break;
|
|
case EN_KILLFOCUS: TestFilterKeys(FALSE); break;
|
|
}
|
|
break;
|
|
|
|
case IDC_CMB_RK_DELAYRATE:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case CBN_SELCHANGE:
|
|
HandleSelection(GetDlgItem(hwnd, IDC_CMB_RK_DELAYRATE), uDelayTable, &g_fk.iDelayMSec);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_CMB_RK_REPEATRATE:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case CBN_SELCHANGE:
|
|
HandleSelection(GetDlgItem(hwnd, IDC_CMB_RK_REPEATRATE), uRateTable, &g_fk.iRepeatMSec);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_CMB_RK_ACCEPTRATE:
|
|
switch (HIWORD(wParam))
|
|
{
|
|
case CBN_SELCHANGE:
|
|
HandleSelection(GetDlgItem(hwnd, IDC_CMB_RK_ACCEPTRATE), uAcceptTable, &g_fk.iWaitMSec);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDOK:
|
|
// Save off repeating values to registry
|
|
EndDialog(hwnd, IDOK);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
g_nLastRepeatDelay = s_nLastRepeatDelayOld;
|
|
g_nLastRepeatRate = s_nLastRepeatRateOld;
|
|
g_nLastWait = s_nLastWaitOld;
|
|
|
|
EndDialog(hwnd, IDCANCEL);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
fProcessed = FALSE;
|
|
break;
|
|
}
|
|
return(fProcessed);
|
|
}
|
|
|
|
// **************************************************************************
|
|
// SubclassFilterKeysTestBox
|
|
//
|
|
// This takes the dialog ID of an edit field, and then finds the controls
|
|
// near the edit field (the controls 2 windows before and 2 windows after the
|
|
// edit control in the z-order). These are the nearest controls that get
|
|
// keyboard messages. It subclasses both of these controls
|
|
// so that they ignore any WM_KEYDOWN messages when the key being pressed is
|
|
// the tab key and the key is already down (i.e. this is a repeated message)
|
|
//
|
|
// **************************************************************************
|
|
BOOL SubclassFilterKeysTestBox (UINT uIdTestBox,HWND hDlg)
|
|
{
|
|
HWND hwndPrev,
|
|
hwndNext,
|
|
hwndTestBox;
|
|
|
|
hwndTestBox = GetDlgItem (hDlg,uIdTestBox);
|
|
// BE CAREFUL IF DIALOG CHANGES! Right now the
|
|
// Previous Previous window is the "S&ettings" push button,
|
|
// and the Next Next is the "&Beep when keys pressed..."
|
|
// checkbox. If the order changes, this code might have to change too.
|
|
// Could make it more general where it searches for controls before
|
|
// and after that can get keyboard focus.
|
|
hwndPrev = GetNextDlgTabItem (hDlg,hwndTestBox,TRUE);
|
|
if (!hwndPrev)
|
|
return FALSE;
|
|
|
|
g_WndProcFKPrev = (WNDPROC) GetWindowLongPtr (hwndPrev, GWLP_WNDPROC);
|
|
SetWindowLongPtr (hwndPrev,GWLP_WNDPROC,(LPARAM)SubclassWndProcFKPrev);
|
|
|
|
hwndNext = GetNextDlgTabItem (hDlg,hwndTestBox,FALSE);
|
|
if (!hwndNext)
|
|
return FALSE;
|
|
|
|
g_WndProcFKNext = (WNDPROC) GetWindowLongPtr (hwndNext, GWLP_WNDPROC);
|
|
SetWindowLongPtr (hwndNext,GWLP_WNDPROC,(LPARAM)SubclassWndProcFKNext);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// **************************************************************************
|
|
// SubclassWndProcFKPrev
|
|
//
|
|
// This is the WndProc used to ignore repeated presses of the tab key for
|
|
// the first focusable control that precedes the test box.
|
|
//
|
|
// **************************************************************************
|
|
LRESULT CALLBACK SubclassWndProcFKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_KEYDOWN:
|
|
if ((int)wParam == VK_TAB)
|
|
{
|
|
if (WASDOWN (lParam))
|
|
{
|
|
return (0);
|
|
}
|
|
// if not a repeat, need to move the focus. For some reason,
|
|
// just calling CallWindowProc won't do it for us.
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
|
|
}
|
|
else
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return (DLGC_WANTTAB | CallWindowProc (g_WndProcFKPrev,hwnd,uMsg,wParam,lParam));
|
|
break;
|
|
}
|
|
return (CallWindowProc(g_WndProcFKPrev,hwnd,uMsg,wParam,lParam));
|
|
}
|
|
|
|
// **************************************************************************
|
|
// SubclassWndProcFKNext
|
|
//
|
|
// This is the WndProc used to ignore repeated presses of the tab key for
|
|
// the first focusable control that follows the test box.
|
|
//
|
|
// **************************************************************************
|
|
LRESULT CALLBACK SubclassWndProcFKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_KEYDOWN:
|
|
if ((int)wParam == VK_TAB)
|
|
{
|
|
if (WASDOWN(lParam))
|
|
{
|
|
return (0);
|
|
}
|
|
// if not a repeat, need to move the focus. For some reason,
|
|
// just calling CallWindowProc won't do it for us.
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
|
|
}
|
|
else
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return (DLGC_WANTTAB | CallWindowProc (g_WndProcFKNext,hwnd,uMsg,wParam,lParam));
|
|
break;
|
|
}
|
|
return (CallWindowProc(g_WndProcFKNext,hwnd,uMsg,wParam,lParam));
|
|
}
|
|
|
|
// **************************************************************************
|
|
// SubclassRepeatKeysTestBox
|
|
//
|
|
// Same as SubclassFilterKeysTestBox, but keeps it's info in different
|
|
// globals so that one doesn't overwrite the other.
|
|
//
|
|
// **************************************************************************
|
|
BOOL SubclassRepeatKeysTestBox (UINT uIdTestBox,HWND hDlg)
|
|
{
|
|
HWND hwndPrev,
|
|
hwndNext,
|
|
hwndTestBox;
|
|
|
|
hwndTestBox = GetDlgItem (hDlg,uIdTestBox);
|
|
// BE CAREFUL IF DIALOG CHANGES! Right now the
|
|
// Previous Previous window is the "S&ettings" push button,
|
|
// and the Next Next is the "&Beep when keys pressed..."
|
|
// checkbox. If the order changes, this code might have to change too.
|
|
// Could make it more general where it searches for controls before
|
|
// and after that can get keyboard focus.
|
|
hwndPrev = GetNextDlgTabItem (hDlg,hwndTestBox,TRUE);
|
|
g_WndProcRKPrev = (WNDPROC) GetWindowLongPtr (hwndPrev,GWLP_WNDPROC);
|
|
SetWindowLongPtr (hwndPrev,GWLP_WNDPROC,(LPARAM)SubclassWndProcRKPrev);
|
|
|
|
hwndNext = GetNextDlgTabItem (hDlg,hwndTestBox,FALSE);
|
|
g_WndProcRKNext = (WNDPROC) GetWindowLongPtr (hwndNext,GWLP_WNDPROC);
|
|
SetWindowLongPtr (hwndNext,GWLP_WNDPROC,(LPARAM)SubclassWndProcRKNext);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
// **************************************************************************
|
|
// SubclassWndProcRKPrev
|
|
//
|
|
// **************************************************************************
|
|
LRESULT CALLBACK SubclassWndProcRKPrev(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_KEYDOWN:
|
|
if ((int)wParam == VK_TAB)
|
|
{
|
|
if (WASDOWN (lParam))
|
|
{
|
|
return (0);
|
|
}
|
|
// if not a repeat, need to move the focus. For some reason,
|
|
// just calling CallWindowProc won't do it for us.
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
|
|
}
|
|
else
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return (DLGC_WANTTAB | CallWindowProc (g_WndProcRKPrev,hwnd,uMsg,wParam,lParam));
|
|
break;
|
|
}
|
|
return (CallWindowProc(g_WndProcRKPrev,hwnd,uMsg,wParam,lParam));
|
|
}
|
|
|
|
// **************************************************************************
|
|
// SubclassWndProcRKNext
|
|
//
|
|
// **************************************************************************
|
|
LRESULT CALLBACK SubclassWndProcRKNext(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_KEYDOWN:
|
|
if ((int)wParam == VK_TAB)
|
|
{
|
|
if (WASDOWN(lParam))
|
|
{
|
|
return (0);
|
|
}
|
|
// if not a repeat, need to move the focus. For some reason,
|
|
// just calling CallWindowProc won't do it for us.
|
|
if (GetKeyState(VK_SHIFT) < 0)
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,1,0);
|
|
}
|
|
else
|
|
{
|
|
SendMessage (GetParent(hwnd),WM_NEXTDLGCTL,0,0);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_GETDLGCODE:
|
|
return (DLGC_WANTTAB | CallWindowProc (g_WndProcRKNext,hwnd,uMsg,wParam,lParam));
|
|
break;
|
|
}
|
|
return (CallWindowProc(g_WndProcRKNext,hwnd,uMsg,wParam,lParam));
|
|
}
|
|
|
|
///////////////////////////////// End of File /////////////////////////////////
|