/////////////////////////////////////////////////////////////////////////////// // // mousebut.c // Mouse Buttons Property sheet page. // // // History: // 29 Jan 94 FelixA // Taken from mouse.c - functions only pertaining to General // Property sheet. // Double Click Speed // Left/Right handed use // // 11 May 95 SteveCat // Ported to Windows NT and Unicode, cleaned up // // // NOTE/BUGS // // Copyright (C) 1994-1995 Microsoft Corporation // /////////////////////////////////////////////////////////////////////////////// //========================================================================== // Include files //========================================================================== // // Mouse Buttons Property sheet page. // #include "main.h" #include "util.h" #include "rc.h" #include "mousectl.h" #include #include // Needed for ERROR_SUCCESS value. const TCHAR szYes[] = TEXT("yes"); const TCHAR szNo[] = TEXT("no"); const TCHAR szDblClkSpeed[] = TEXT("DoubleClickSpeed"); const TCHAR szRegStr_Mouse[]= REGSTR_PATH_MOUSE; // SwapMouseButtons takes // TRUE to make it a right mouse // FALSE to make it a left mouse #define CLICKMIN 100 /* milliseconds */ #define CLICKMAX 900 #define CLICKSUM (CLICKMIN+CLICKMAX) #define CLICKRANGE (CLICKMAX-CLICKMIN) #define RIGHT TRUE #define LEFT FALSE typedef struct tag_MouseGenStr { BOOL bSwap; BOOL bOrigSwap; short ClickSpeed; short OrigDblClkSpeed; HWND hWndDblClkScroll; HWND hDlg; // HWND hMouseButDlg; RECT OrigRect; RECT DblClkRect; POINT ObjectPoint; POINT SelectPoint; int jackstate, jackhits; // for jack-in-the-box control int jackignore; // for jack-in-the-box control } MOUSEBUTSTR, *PMOUSEBUTSTR, FAR * LPMOUSEBUTSTR; // #include "..\..\..\inc\mousehlp.h" #include "mousehlp.h" const DWORD aMouseButHelpIds[] = { IDC_GROUPBOX_1, IDH_COMM_GROUPBOX, IDC_GROUPBOX_2, IDH_DLGMOUSE_HANDED_PIC, IDC_GROUPBOX_3, IDH_DLGMOUSE_HANDED_PIC, IDC_GROUPBOX_4, IDH_COMM_GROUPBOX, IDC_SELECTDRAG, IDH_DLGMOUSE_HANDED_PIC, IDC_OBJECTMENU, IDH_DLGMOUSE_HANDED_PIC, MOUSE_LEFTHAND, IDH_DLGMOUSE_LEFT, MOUSE_RIGHTHAND, IDH_DLGMOUSE_RIGHT, MOUSE_SELECTBMP, IDH_DLGMOUSE_HANDED_PIC, MOUSE_MOUSEBMP, IDH_DLGMOUSE_HANDED_PIC, MOUSE_MENUBMP, IDH_DLGMOUSE_HANDED_PIC, MOUSE_CLICKSCROLL, IDH_DLGMOUSE_DOUBCLICK, IDC_GROUPBOX_5, IDH_DLGMOUSE_DCLICK_PIC, MOUSE_DBLCLKBMP, IDH_DLGMOUSE_DCLICK_PIC, 0, 0 }; #ifdef DEBUG #define REG_INTEGER 1000 int fTraceRegAccess = 0; void NEAR PASCAL RegDetails( int iWrite, HKEY hk, LPCTSTR lpszSubKey, LPCTSTR lpszValueName, DWORD dwType, LPTSTR lpszString, int iValue ) { TCHAR Buff[256]; TCHAR far *lpszReadWrite[] = { TEXT("DESK.CPL:Read"), TEXT("DESK.CPL:Write") }; if( !fTraceRegAccess ) return; switch( dwType ) { case REG_SZ: wsprintf( Buff, TEXT("%s String:hk=%#08lx, %s:%s=%s\n\r"), lpszReadWrite[iWrite], hk, lpszSubKey, lpszValueName, lpszString ); break; case REG_INTEGER: wsprintf( Buff, TEXT("%s int:hk=%#08lx, %s:%s=%d\n\r"), lpszReadWrite[iWrite], hk, lpszSubKey, lpszValueName, iValue ); break; case REG_BINARY: wsprintf( Buff, TEXT("%s Binary:hk=%#08lx, %s:%s=%#0lx;DataSize:%d\r\n"), lpszReadWrite[iWrite], hk, lpszSubKey, lpszValueName, lpszString, iValue ); break; } OutputDebugString( Buff ); } #endif // DEBUG /////////////////////////////////////////////////////////////////////////////// // // GetIntFromSubKey // hKey is the handle to the subkey // (already pointing to the proper location). // /////////////////////////////////////////////////////////////////////////////// int NEAR PASCAL GetIntFromSubkey( HKEY hKey, LPCTSTR lpszValueName, int iDefault ) { TCHAR szValue[20]; DWORD dwSizeofValueBuff = sizeof( szValue ); DWORD dwType; int iRetValue = iDefault; if( (RegQueryValueEx( hKey, (LPTSTR)lpszValueName, NULL, &dwType, (LPBYTE) szValue, &dwSizeofValueBuff ) == ERROR_SUCCESS ) && dwSizeofValueBuff ) { // // BOGUS: This handles only the string type entries now! // if( dwType == REG_SZ ) iRetValue = (int) StrToLong( szValue ); #ifdef DEBUG else OutputDebugString( TEXT("String type expected from Registry\n\r")); #endif } #ifdef DEBUG RegDetails( 0, hKey, TEXT(""), lpszValueName, REG_INTEGER, NULL, iRetValue ); #endif return( iRetValue ); } /////////////////////////////////////////////////////////////////////////////// // // GetIntFromReg() // Opens the given subkey and gets the int value. // /////////////////////////////////////////////////////////////////////////////// int NEAR PASCAL GetIntFromReg( HKEY hKey, LPCTSTR lpszSubkey, LPCTSTR lpszNameValue, int iDefault ) { HKEY hk; int iRetValue = iDefault; // // See if the key is present. // if( RegOpenKey( hKey, lpszSubkey, &hk ) == ERROR_SUCCESS ) { iRetValue = GetIntFromSubkey( hk, lpszNameValue, iDefault ); RegCloseKey( hk ); } return( iRetValue ); } BOOL NEAR PASCAL GetStringFromReg( HKEY hKey, LPCTSTR lpszSubkey, LPCTSTR lpszValueName, LPCTSTR lpszDefault, LPTSTR lpszValue, DWORD dwSizeofValueBuff ) { HKEY hk; DWORD dwType; BOOL fSuccess = FALSE; // // See if the key is present. // if( RegOpenKey( hKey, lpszSubkey, &hk ) == ERROR_SUCCESS ) { if( (RegQueryValueEx( hk, (LPTSTR) lpszValueName, NULL, &dwType, (LPBYTE) lpszValue, &dwSizeofValueBuff ) == ERROR_SUCCESS ) && dwSizeofValueBuff ) { // // BOGUS: This handles only the string type entries now! // #ifdef DEBUG if( dwType != REG_SZ ) { OutputDebugString( TEXT("String type expected from Registry\n\r")); } else #endif fSuccess = TRUE; } RegCloseKey( hk ); } // // If failure, use the default string. // if( !fSuccess ) lstrcpy( lpszValue, lpszDefault ); #ifdef DEBUG RegDetails( 0, hKey, lpszSubkey, lpszValueName, REG_SZ, lpszValue, 0 ); #endif return( fSuccess ); } /////////////////////////////////////////////////////////////////////////////// // // UpdateRegistry: // This updates a given value of any data type at a given // location in the registry. // // The value name is passed in as an Id to a string in USER's String table. // /////////////////////////////////////////////////////////////////////////////// BOOL FAR PASCAL UpdateRegistry( HKEY hKey, LPCTSTR lpszSubkey, LPCTSTR lpszValueName, DWORD dwDataType, LPVOID lpvData, DWORD dwDataSize ) { HKEY hk; if( RegCreateKey( hKey, lpszSubkey, &hk ) == ERROR_SUCCESS ) { RegSetValueEx( hk, (LPTSTR)lpszValueName, 0, dwDataType, (LPBYTE)lpvData, dwDataSize ); #ifdef DEBUG RegDetails( 1, hKey, lpszSubkey, lpszValueName, dwDataType, lpvData, (int)dwDataSize ); #endif RegCloseKey( hk ); return( TRUE ); } return( FALSE ); } // // Swaps the menu and selection bitmaps. // void NEAR PASCAL ShowButtonState( PMOUSEBUTSTR pMstr ) { HWND hDlg; Assert( pMstr ); hDlg = pMstr->hDlg; MouseControlSetSwap( GetDlgItem( hDlg, MOUSE_MOUSEBMP ), pMstr->bSwap ); SetWindowPos( GetDlgItem( hDlg, pMstr->bSwap? IDC_SELECTDRAG : IDC_OBJECTMENU ), NULL, pMstr->ObjectPoint.x, pMstr->ObjectPoint.y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER ); SetWindowPos( GetDlgItem( hDlg, !pMstr->bSwap ? IDC_SELECTDRAG : IDC_OBJECTMENU ), NULL, pMstr->SelectPoint.x, pMstr->SelectPoint.y, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER ); CheckDlgButton( hDlg, MOUSE_RIGHTHAND, !pMstr->bSwap ); CheckDlgButton( hDlg, MOUSE_LEFTHAND, pMstr->bSwap ); } void NEAR PASCAL DestroyMouseButDlg( PMOUSEBUTSTR pMstr ) { if( pMstr ) { SetWindowLong( pMstr->hDlg, DWL_USER, (LONG)NULL ); LocalFree( (HGLOBAL)pMstr ); } } /////////////////////////////////////////////////////////////////////////////// // // Jack stuff -- code to manage the jack-in-the-box double-click testbox // /////////////////////////////////////////////////////////////////////////////// typedef struct { int first; // first frame of state int last; // last frame of state int repeat; // state's repeat count } JACKSTATE; #define JACK_OPPOSITE_STATE (-2) #define JACK_NEXT_STATE (-1) #define JACK_CRANKING ( 0) #define JACK_OPENING ( 1) #define JACK_BOUNCING ( 2) #define JACK_CLOSING ( 3) // // NOTE every state starts with a key frame in the AVI file // JACKSTATE JackFSA[] = { { 0, 7, -1 }, // cranking { 8, 12, 1 }, // opening { 16, 23, -1 }, // bouncing { 24, 27, 1 }, // closing }; #define JACK_NUM_STATES ( sizeof( JackFSA ) / sizeof( JACKSTATE ) ) void JackSetState( HWND dlg, PMOUSEBUTSTR mstr, int index ) { JACKSTATE *state; switch( index ) { case JACK_OPPOSITE_STATE: mstr->jackstate++; // // fall thru // case JACK_NEXT_STATE: index = mstr->jackstate + 1; } index %= JACK_NUM_STATES; state = JackFSA + index; mstr->jackstate = index; mstr->jackignore++; Animate_Play( GetDlgItem( dlg, MOUSE_DBLCLKBMP ), state->first, state->last, state->repeat ); } void JackClicked( HWND dlg, PMOUSEBUTSTR mstr ) { JACKSTATE *state = JackFSA + mstr->jackstate; if( state->repeat < 0 ) JackSetState( dlg, mstr, JACK_NEXT_STATE ); else mstr->jackhits++; } void JackStopped( HWND dlg, PMOUSEBUTSTR mstr ) { if( --mstr->jackignore < 0 ) { JACKSTATE *state = JackFSA + mstr->jackstate; if( state->repeat > 0 ) { int index; if( mstr->jackhits ) { mstr->jackhits--; index = JACK_OPPOSITE_STATE; } else index = JACK_NEXT_STATE; JackSetState( dlg, mstr, index ); } } } void JackStart( HWND dlg, PMOUSEBUTSTR mstr ) { mstr->jackhits = 0; mstr->jackstate = 0; mstr->jackignore = -1; Animate_Open( GetDlgItem( dlg, MOUSE_DBLCLKBMP ), MAKEINTRESOURCE( IDA_JACKNBOX ) ); JackSetState( dlg, mstr, JACK_CRANKING ); } BOOL NEAR PASCAL InitMouseButDlg( HWND hDlg ) { POINT Origin; PMOUSEBUTSTR pMstr; RECT TmpRect; // // BUGBUG must do the alloc when you are adding these pages // you cannot just return false and hope things work. // pMstr = (PMOUSEBUTSTR) LocalAlloc( LPTR , sizeof( MOUSEBUTSTR ) ); if( pMstr == NULL ) return TRUE; SetWindowLong( hDlg, DWL_USER, (LONG)pMstr ); pMstr->hDlg = hDlg; Origin.x = Origin.y = 0; ClientToScreen( hDlg, (LPPOINT) &Origin ); GetWindowRect( hDlg, &pMstr->OrigRect ); pMstr->OrigRect.left -= Origin.x; pMstr->OrigRect.right -= Origin.x; GetWindowRect( GetDlgItem( hDlg, MOUSE_DBLCLKBMP ), &pMstr->DblClkRect ); pMstr->DblClkRect.top -= Origin.y; pMstr->DblClkRect.bottom -= Origin.y; pMstr->DblClkRect.left -= Origin.x; pMstr->DblClkRect.right -= Origin.x; // // Find position of Select and Object windows // GetWindowRect( GetDlgItem( hDlg, IDC_SELECTDRAG ), &TmpRect ); ScreenToClient( hDlg, (POINT FAR*)&TmpRect ); pMstr->SelectPoint.x = TmpRect.left; pMstr->SelectPoint.y = TmpRect.top; GetWindowRect( GetDlgItem( hDlg, IDC_OBJECTMENU ), &TmpRect ); ScreenToClient( hDlg, (POINT FAR*)&TmpRect ); pMstr->ObjectPoint.x = TmpRect.left; pMstr->ObjectPoint.y = TmpRect.top; // // Set(and get), then restore the state of the mouse buttons. // (pMstr->bOrigSwap) = (pMstr->bSwap) = SwapMouseButton( TRUE ); SwapMouseButton( pMstr->bOrigSwap ); ShowButtonState( pMstr ); pMstr->OrigDblClkSpeed = pMstr->ClickSpeed = GetIntFromReg( HKEY_CURRENT_USER, szRegStr_Mouse, szDblClkSpeed, CLICKMIN + (CLICKRANGE/2) ); pMstr->hWndDblClkScroll = GetDlgItem( hDlg, MOUSE_CLICKSCROLL ); SendMessage( pMstr->hWndDblClkScroll, TBM_SETRANGE, 0, MAKELONG( CLICKMIN, CLICKMAX )); SendMessage( pMstr->hWndDblClkScroll, TBM_SETPOS, TRUE, (LONG)(CLICKMIN + CLICKMAX - pMstr->ClickSpeed )); SetDoubleClickTime( pMstr->ClickSpeed ); JackStart( hDlg, pMstr ); return TRUE; } BOOL CALLBACK MouseButDlg( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { PMOUSEBUTSTR pMstr = (PMOUSEBUTSTR) GetWindowLong( hDlg, DWL_USER ); switch( message ) { case WM_INITDIALOG: return InitMouseButDlg( hDlg ); case WM_DESTROY: DestroyMouseButDlg( pMstr ); break; case WM_HSCROLL: if( (HWND)lParam == pMstr->hWndDblClkScroll ) { short temp = CLICKMIN + CLICKMAX - (short) SendMessage( (HWND)lParam, TBM_GETPOS, 0, 0L ); if( temp != pMstr->ClickSpeed ) { pMstr->ClickSpeed = temp; SetDoubleClickTime( pMstr->ClickSpeed ); SendMessage( GetParent( hDlg ), PSM_CHANGED, (WPARAM)hDlg, 0L ); } } break; case WM_RBUTTONDBLCLK: case WM_LBUTTONDBLCLK: { POINT point = { (int)MAKEPOINTS( lParam ).x, (int)MAKEPOINTS( lParam ).y }; if( PtInRect( &pMstr->DblClkRect, point ) ) JackClicked( hDlg, pMstr ); break; } case WM_COMMAND: switch( LOWORD( wParam ) ) { case MOUSE_LEFTHAND: if( pMstr->bSwap != RIGHT ) { SendMessage( GetParent( hDlg ), PSM_CHANGED, (WPARAM)hDlg, 0L ); pMstr->bSwap = RIGHT; ShowButtonState( pMstr ); } break; case MOUSE_RIGHTHAND: if( pMstr->bSwap != LEFT ) { SendMessage( GetParent( hDlg ), PSM_CHANGED, (WPARAM)hDlg, 0L ); pMstr->bSwap = LEFT; ShowButtonState( pMstr ); } break; case MOUSE_DBLCLKBMP: if( HIWORD( wParam ) == ACN_STOP ) JackStopped( hDlg, pMstr ); break; } break; case WM_NOTIFY: switch( ((NMHDR FAR *)lParam)->code ) { case PSN_APPLY: HourGlass( TRUE ); if( pMstr->bSwap != pMstr->bOrigSwap ) { SystemParametersInfo( SPI_SETMOUSEBUTTONSWAP, pMstr->bSwap, NULL, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE ); pMstr->bOrigSwap = pMstr->bSwap; } if( pMstr->ClickSpeed != pMstr->OrigDblClkSpeed ) { SystemParametersInfo( SPI_SETDOUBLECLICKTIME, pMstr->ClickSpeed, NULL, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE ); pMstr->OrigDblClkSpeed = pMstr->ClickSpeed; } HourGlass( FALSE ); break; case PSN_RESET: SetDoubleClickTime( pMstr->OrigDblClkSpeed ); break; default: return FALSE; } break; case WM_HELP: // F1 WinHelp( ((LPHELPINFO) lParam)->hItemHandle, HELP_FILE, HELP_WM_HELP, (DWORD) (LPTSTR) aMouseButHelpIds ); break; case WM_CONTEXTMENU: // right mouse click WinHelp( (HWND) wParam, HELP_FILE, HELP_CONTEXTMENU, (DWORD) (LPTSTR) aMouseButHelpIds ); break; default: return FALSE; } return TRUE; }