// XTPShortcutManager.cpp : implementation of the CXTPShortcutManager class. // // This file is a part of the XTREME COMMANDBARS MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Resource.h" #include "Common/XTPPropExchange.h" #include "Common/XTPVC80Helpers.h" #include "Common/XTPResourceManager.h" #include "XTPCommandBarsDefines.h" #include "XTPShortcutManager.h" #include "XTPCommandBars.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ////////////////////////////////////////////////////////////////////////// // CXTPShortcutManagerAccel CXTPShortcutManagerAccel::CXTPShortcutManagerAccel() { cmd = 0; key[0].fVirt = 0; key[0].key = 0; key[1].fVirt = 0; key[1].key = 0; m_pManager = 0; } CXTPShortcutManagerAccel::CXTPShortcutManagerAccel(ACCEL* pAccel) { cmd = pAccel->cmd; key[0].fVirt = pAccel->fVirt; key[0].key = pAccel->key; key[1].fVirt = 0; key[1].key = 0; m_pManager = 0; } CXTPShortcutManagerAccel::CXTPShortcutManagerAccel(const XTP_SHORTCUTMANAGER_ACCEL& accel) { cmd = accel.cmd; key[0] = accel.key[0]; key[1] = accel.key[1]; m_pManager = NULL; } CXTPShortcutManagerAccel::CXTPShortcutManagerAccel(const CXTPShortcutManagerAccel& accel) { cmd = accel.cmd; key[0] = accel.key[0]; key[1] = accel.key[1]; m_pManager = NULL; } const CXTPShortcutManagerAccel& CXTPShortcutManagerAccel::operator=(const CXTPShortcutManagerAccel& accel) { cmd = accel.cmd; key[0] = accel.key[0]; key[1] = accel.key[1]; m_pManager = accel.m_pManager; return *this; } ////////////////////////////////////////////////////////////////////////// // CXTPShortcutManagerAccelTable CXTPShortcutManagerAccelTable::CXTPShortcutManagerAccelTable(CXTPShortcutManager* pManager) { m_pManager = pManager; } CXTPShortcutManagerAccelTable::~CXTPShortcutManagerAccelTable() { RemoveAll(); } void CXTPShortcutManagerAccelTable::RemoveAll() { for (int i = 0; i < GetCount(); i++) { m_arrAccels[i]->InternalRelease(); } m_arrAccels.RemoveAll(); } void CXTPShortcutManagerAccelTable::RemoveAt(int nIndex) { if (nIndex >= 0 && nIndex < m_arrAccels.GetSize()) { m_arrAccels[nIndex]->InternalRelease(); m_arrAccels.RemoveAt(nIndex); } } void CXTPShortcutManagerAccelTable::Add(const XTP_SHORTCUTMANAGER_ACCEL& accel) { CXTPShortcutManagerAccel* pAccel = new CXTPShortcutManagerAccel(accel); pAccel->m_pManager = m_pManager; m_arrAccels.Add(pAccel); } void CXTPShortcutManagerAccelTable::CopyAccelTable(LPACCEL lpAccel, int nSize) { RemoveAll(); for (int i = 0; i < nSize; i++) { Add(CXTPShortcutManagerAccel(&lpAccel[i])); } } XTP_SHORTCUTMANAGER_ACCEL* CXTPShortcutManagerAccelTable::CopyAccels() const { XTP_SHORTCUTMANAGER_ACCEL* pAccels = new XTP_SHORTCUTMANAGER_ACCEL[GetCount()]; for (int i = 0; i < GetCount(); i++) { pAccels[i] = *m_arrAccels[i]; } return pAccels; } void CXTPShortcutManagerAccelTable::CopyAccelTable(HACCEL hAccelTable) { RemoveAll(); if (hAccelTable == NULL) return; int nAccelSize = ::CopyAcceleratorTable (hAccelTable, NULL, 0); if (nAccelSize == 0) return; LPACCEL lpAccel = new ACCEL[nAccelSize]; ::CopyAcceleratorTable (hAccelTable, lpAccel, nAccelSize); CopyAccelTable(lpAccel, nAccelSize); delete[] lpAccel; } int CXTPShortcutManagerAccelTable::GetCount() const { return (int)m_arrAccels.GetSize(); } CXTPShortcutManagerAccel* CXTPShortcutManagerAccelTable::GetAt(int nIndex) const { return nIndex >= 0 && nIndex < m_arrAccels.GetSize() ? m_arrAccels.GetAt(nIndex) : NULL; } void CXTPShortcutManagerAccelTable::CopyAccelTable(CXTPShortcutManagerAccelTable* pAccelTable) { RemoveAll(); int nAccelSize = pAccelTable->GetCount(); for (int i = 0; i < nAccelSize; i++) { Add(*pAccelTable->GetAt(i)); } } ////////////////////////////////////////////////////////////////////////// // CXTPShortcutManagerKeyNameText::CXTPShortcutManagerKeyNameText CXTPShortcutManager::CKeyNameText::CKeyNameText() { static const struct { WORD wKey; // Virtual Key Code. LPCTSTR szKeyName; // Display Name (i.e "CTRL"). } virtKeys[] = { { _T('0'), _T("0") }, { _T('1'), _T("1") }, { _T('2'), _T("2") }, { _T('3'), _T("3") }, { _T('4'), _T("4") }, { _T('5'), _T("5") }, { _T('6'), _T("6") }, { _T('7'), _T("7") }, { _T('8'), _T("8") }, { _T('9'), _T("9") }, { _T('A'), _T("A") }, { _T('B'), _T("B") }, { _T('C'), _T("C") }, { _T('D'), _T("D") }, { _T('E'), _T("E") }, { _T('F'), _T("F") }, { _T('G'), _T("G") }, { _T('H'), _T("H") }, { _T('I'), _T("I") }, { _T('J'), _T("J") }, { _T('K'), _T("K") }, { _T('L'), _T("L") }, { _T('M'), _T("M") }, { _T('N'), _T("N") }, { _T('O'), _T("O") }, { _T('P'), _T("P") }, { _T('Q'), _T("Q") }, { _T('R'), _T("R") }, { _T('S'), _T("S") }, { _T('T'), _T("T") }, { _T('U'), _T("U") }, { _T('V'), _T("V") }, { _T('W'), _T("W") }, { _T('X'), _T("X") }, { _T('Y'), _T("Y") }, { _T('Z'), _T("Z") }, { VK_LBUTTON, _T("Left Button") }, { VK_RBUTTON, _T("Right Button") }, { VK_CANCEL, _T("Ctrl+Break") }, { VK_MBUTTON, _T("Middle Button") }, { VK_BACK, _T("Backspace") }, { VK_TAB, _T("Tab") }, { VK_CLEAR, _T("Clear") }, { VK_RETURN, _T("Enter") }, { VK_SHIFT, _T("Shift") }, { VK_CONTROL, _T("Ctrl") }, { VK_MENU, _T("Alt") }, { VK_PAUSE, _T("Pause") }, { VK_CAPITAL, _T("Caps Lock") }, { VK_ESCAPE, _T("Esc") }, { VK_SPACE, _T("Space") }, { VK_PRIOR, _T("Page Up") }, { VK_NEXT, _T("Page Down") }, { VK_END, _T("End") }, { VK_HOME, _T("Home") }, { VK_LEFT, _T("Left Arrow") }, { VK_UP, _T("Up Arrow") }, { VK_RIGHT, _T("Right Arrow") }, { VK_DOWN, _T("Down Arrow") }, { VK_SELECT, _T("Select") }, { VK_PRINT, _T("Print") }, { VK_EXECUTE, _T("Execute") }, { VK_SNAPSHOT, _T("Snapshot") }, { VK_INSERT, _T("Ins") }, { VK_DELETE, _T("Del") }, { VK_HELP, _T("Help") }, { VK_LWIN , _T("Win") }, { VK_RWIN, _T("Win") }, { VK_APPS, _T("Application") }, { VK_MULTIPLY, _T("Num *") }, { VK_ADD, _T("Num +") }, { VK_SEPARATOR, _T("Separator") }, { VK_SUBTRACT, _T("Num -") }, { VK_DECIMAL, _T("Num .") }, { VK_DIVIDE, _T("Num /") }, { VK_F1, _T("F1") }, { VK_F2, _T("F2") }, { VK_F3, _T("F3") }, { VK_F4, _T("F4") }, { VK_F5, _T("F5") }, { VK_F6, _T("F6") }, { VK_F7, _T("F7") }, { VK_F8, _T("F8") }, { VK_F9, _T("F9") }, { VK_F10, _T("F10") }, { VK_F11, _T("F11") }, { VK_F12, _T("F12") }, { VK_NUMPAD0, _T("Num 0") }, { VK_NUMPAD1, _T("Num 1") }, { VK_NUMPAD2, _T("Num 2") }, { VK_NUMPAD3, _T("Num 3") }, { VK_NUMPAD4, _T("Num 4") }, { VK_NUMPAD5, _T("Num 5") }, { VK_NUMPAD6, _T("Num 6") }, { VK_NUMPAD7, _T("Num 7") }, { VK_NUMPAD8, _T("Num 8") }, { VK_NUMPAD9, _T("Num 9") }, { VK_NUMLOCK, _T("Num Lock") }, { VK_SCROLL, _T("Scrl Lock") }, { VK_ATTN, _T("Attn") }, { VK_CRSEL, _T("Crsel") }, { VK_EXSEL, _T("Exsel") }, { VK_EREOF, _T("Ereof") }, { VK_PLAY, _T("Play") }, { VK_ZOOM, _T("Zoom") }, { VK_NONAME, _T("No Name") }, { VK_PA1, _T("Pa1") }, { VK_OEM_CLEAR, _T("Oem Clear") }, }; for (int i = 0; i < _countof(virtKeys); i++) { SetAt(virtKeys[i].wKey, virtKeys[i].szKeyName); } } WORD CXTPShortcutManager::CKeyNameText::Parse(LPCTSTR lpszKey) { POSITION pos = m_mapVirtualKeys.GetStartPosition(); while (pos) { WORD rKey; CString strKey; m_mapVirtualKeys.GetNextAssoc(pos, rKey, strKey); if (strKey.CompareNoCase(lpszKey) == 0) return rKey; } return 0; } CString CXTPShortcutManager::CKeyNameText::Translate(UINT nKey) { CString strKeyNameText; if (m_mapVirtualKeys.Lookup((WORD)nKey, strKeyNameText)) { return strKeyNameText; } return _T(""); } void CXTPShortcutManager::CKeyNameText::SetAt(UINT uiVirtKey, LPCTSTR strKeyNameText) { m_mapVirtualKeys.SetAt((WORD)uiVirtKey, strKeyNameText); } #define SAFE_DESTROY_ACCELTABLE(hAccelTable) if (hAccelTable) {::DestroyAcceleratorTable (hAccelTable); hAccelTable = NULL;} CXTPShortcutManager::CXTPShortcutManager(CXTPCommandBars* pCommandBars) { m_pCommandBars = pCommandBars; m_pAccelTable = new CXTPShortcutManagerAccelTable(this); m_pOriginalAccelTable = NULL; m_bAllowEscapeShortcut = FALSE; m_bUseSystemKeyNameText = FALSE; m_bAllowDoubleKeyShortcuts = TRUE; m_pKeyNameText = new CKeyNameText(); m_nDisableShortcuts = 0; m_bDisableOnCapture = TRUE; } CXTPShortcutManager::~CXTPShortcutManager() { SAFE_DELETE(m_pAccelTable); SAFE_DELETE(m_pOriginalAccelTable); SAFE_DELETE(m_pKeyNameText); } void CXTPShortcutManager::SetAccelerators(UINT nIDResource) { m_pAccelTable->RemoveAll(); LPCTSTR lpszResourceName = MAKEINTRESOURCE(nIDResource); HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_ACCELERATOR); if (hInst) { HACCEL hAccel = ::LoadAccelerators(hInst, lpszResourceName); m_pAccelTable->CopyAccelTable(hAccel); CreateOriginalAccelTable(); } } void CXTPShortcutManager::SetDefaultAccelerator(HACCEL hAccelTable) { m_pAccelTable->CopyAccelTable(hAccelTable); CreateOriginalAccelTable(); } void CXTPShortcutManager::CreateOriginalAccelTable() { if (m_pOriginalAccelTable == NULL) m_pOriginalAccelTable = new CXTPShortcutManagerAccelTable(this); m_pOriginalAccelTable->CopyAccelTable(m_pAccelTable); } void CXTPShortcutManager::Reset() { ASSERT(m_pOriginalAccelTable); if (m_pOriginalAccelTable) { m_pAccelTable->CopyAccelTable(m_pOriginalAccelTable); } } CString CXTPShortcutManager::Format(CXTPShortcutManagerAccel* lpAccel, int* pPriority) { CString str; CKeyHelper helper (lpAccel, this); helper.Format (str); if (pPriority) { *pPriority = helper.Priority(); } return str; } BOOL CXTPShortcutManager::OnPreviewEditKey(CXTPShortcutManagerAccel* pAccel) { if ((pAccel->key[0].fVirt & FCONTROL) == 0 && (pAccel->key[0].fVirt & FSHIFT) == 0 && (pAccel->key[0].fVirt & FALT) == 0 && (pAccel->key[0].fVirt & FVIRTKEY) && (pAccel->key[0].key == VK_ESCAPE) && !m_bAllowEscapeShortcut) return FALSE; return TRUE; } void CXTPShortcutManager::DisableShortcuts(BOOL bDisable) { m_nDisableShortcuts += bDisable ? +1 : -1; } BOOL CXTPShortcutManager::IsAccelMessage(CXTPShortcutManagerAccel::SHORTCUTACCEL& accel, int nKeyState, LPMSG lpMsg) const { BOOL fVirt = lpMsg->message == WM_KEYDOWN || lpMsg->message == WM_SYSKEYDOWN; WORD flags = accel.fVirt; if ( (DWORD)accel.key != lpMsg->wParam || ((fVirt != 0) != ((flags & FVIRTKEY) != 0))) { return FALSE; } if (fVirt && ((nKeyState & (FSHIFT | FCONTROL)) != (flags & (FSHIFT | FCONTROL)))) { return FALSE; } if ((nKeyState & FALT) != (flags & FALT)) { return FALSE; } return TRUE; } int CXTPShortcutManager::GetAccelKeyState() const { int vkCtrl = VK_CONTROL; int vkAlt = VK_MENU; if ((GetKeyState(VK_RMENU) & 0x8000) && (GetKeyState(VK_LCONTROL) & 0x8000)) { vkCtrl = VK_RCONTROL; vkAlt = VK_LMENU; } int nKeyState = 0; if (GetKeyState(vkCtrl) & 0x8000) nKeyState |= FCONTROL; if (GetKeyState(vkAlt) & 0x8000) nKeyState |= FALT; if (GetKeyState(VK_SHIFT) & 0x8000) nKeyState |= FSHIFT; return nKeyState; } BOOL CXTPShortcutManager::TranslateAccelerator(LPMSG lpMsg) { if (!m_pCommandBars || m_pCommandBars->IsCustomizeMode()) return FALSE; HWND hWnd = m_pCommandBars->GetSite()->GetSafeHwnd(); if (m_nDisableShortcuts > 0) return FALSE; CXTPShortcutManagerAccelTable* pAccelTable = GetDefaultAccelerator(); if (pAccelTable == NULL || pAccelTable->GetCount() == 0) return FALSE; if (lpMsg->message != WM_KEYDOWN && lpMsg->message != WM_SYSKEYDOWN && lpMsg->message != WM_CHAR && lpMsg->message != WM_SYSCHAR) return FALSE; int nKeyState = GetAccelKeyState(); BOOL bFound = FALSE; int nAccelSize = pAccelTable->GetCount(); for (int i = 0; i < nAccelSize; i++) { CXTPShortcutManagerAccel* accel = pAccelTable->GetAt(i); if (!IsAccelMessage(accel->key[0], nKeyState, lpMsg)) continue; bFound = TRUE; if (IsWindowEnabled(hWnd) && (!m_bDisableOnCapture || ::GetCapture() == NULL) && !IsIconic(hWnd) && accel->cmd != 0) { if (accel->key[1].key != 0) { if (m_pCommandBars->GetSite()->IsFrameWnd()) { CKeyHelper key(accel, this); CString strMessage, strFormat; CXTPResourceManager::AssertValid(XTPResourceManager()->LoadString(&strFormat, XTP_IDS_SHORTCUT_SECONDKEY)); strMessage.Format(strFormat, (LPCTSTR)key.Format(&accel->key[0])); ((CFrameWnd*)m_pCommandBars->GetSite())->SetMessageText(strMessage); } BOOL bAccept = FALSE; m_nDisableShortcuts++; ::SetCapture(hWnd); while (::GetCapture() == hWnd) { MSG msg; VERIFY(::GetMessage(&msg, NULL, 0, 0)); if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) { if (msg.wParam == VK_SHIFT || msg.wParam == VK_CONTROL || msg.wParam == VK_MENU) continue; nKeyState = GetAccelKeyState(); for (int j = 0; j < nAccelSize; j++) { CXTPShortcutManagerAccel* secondAccel = pAccelTable->GetAt(j); if (secondAccel->key[0].fVirt == accel->key[0].fVirt && secondAccel->key[0].key == accel->key[0].key) { if (!IsAccelMessage(secondAccel->key[1], nKeyState, &msg)) continue; bAccept = TRUE; accel = secondAccel; break; } } if (!bAccept) { MessageBeep(MB_ICONEXCLAMATION); } break; } DispatchMessage (&msg); if (msg.message == WM_COMMAND || msg.message == WM_ACTIVATE || msg.message == WM_LBUTTONDOWN || msg.message == WM_NCACTIVATE || msg.message == WM_CLOSE || msg.message == WM_SYSCOMMAND) break; } ::ReleaseCapture(); m_nDisableShortcuts--; if (IsWindow(hWnd) && m_pCommandBars->GetSite()->IsFrameWnd()) { ((CFrameWnd*)m_pCommandBars->GetSite())->SetMessageText((UINT)0); } if (!bAccept) return TRUE; } SendMessage(hWnd, WM_COMMAND, accel->cmd, 0); } break; } return bFound; } BOOL CXTPShortcutManager::FindDefaultFrameAccelerator(int nCmd, CString& strShortcut) { CFrameWnd* pFrame = DYNAMIC_DOWNCAST(CFrameWnd, m_pCommandBars->GetSite()); HACCEL hAccelTable = pFrame ? pFrame->m_hAccelTable : NULL; if (!hAccelTable) return FALSE; ASSERT(hAccelTable); int nAccelSize = ::CopyAcceleratorTable (hAccelTable, NULL, 0); LPACCEL lpAccel = new ACCEL[nAccelSize]; ::CopyAcceleratorTable (hAccelTable, lpAccel, nAccelSize); BOOL bFound = FALSE; BOOL bEqual = FALSE; CString strFirst = _T(""); int nFirstPriorety = 0; for (int i = 0; i < nAccelSize; i++) { if (lpAccel[i].cmd == nCmd) { int nPriority = 0; CXTPShortcutManagerAccel accel(&lpAccel[i]); CString str = Format(&accel, &nPriority); if (str == strShortcut) bEqual = TRUE; if (strFirst.IsEmpty() || (nFirstPriorety < nPriority)) { strFirst = str; nFirstPriorety = nPriority; } bFound = TRUE; } } delete[] lpAccel; if (!bFound) strShortcut = ""; else if (!bEqual) strShortcut = strFirst; return bFound; } BOOL CXTPShortcutManager::FindDefaultAccelerator(int nCmd, CString& strShortcut) { CXTPShortcutManagerAccelTable* pAccelTable = GetDefaultAccelerator(); int nAccelSize = pAccelTable ? pAccelTable->GetCount() : 0; if (m_pOriginalAccelTable == NULL && nAccelSize == 0) return FindDefaultFrameAccelerator(nCmd, strShortcut); if (nAccelSize == 0) return FALSE; BOOL bFound = FALSE; BOOL bEqual = FALSE; CString strFirst = _T(""); int nFirstPriorety = 0; for (int i = 0; i < nAccelSize; i++) { CXTPShortcutManagerAccel* accel = pAccelTable->GetAt(i); if (accel->cmd == (int)nCmd) { int nPriority = 0; CString str = Format(accel, &nPriority); if (str == strShortcut) bEqual = TRUE; if (strFirst.IsEmpty() || (nFirstPriorety < nPriority)) { strFirst = str; nFirstPriorety = nPriority; } bFound = TRUE; } } if (!bFound) strShortcut = ""; else if (!bEqual) strShortcut = strFirst; return bFound; } CXTPShortcutManager::CKeyHelper::CKeyHelper(const CXTPShortcutManagerAccel* lpAccel, CXTPShortcutManager* pManager/*= NULL*/) : m_pManager(pManager), m_lpAccel (lpAccel) { m_bAllowLocaleKey = TRUE; } CXTPShortcutManager::CKeyHelper::~CKeyHelper() { } int CXTPShortcutManager::CKeyHelper::Priority() { if (m_lpAccel == NULL) return 0; if (m_lpAccel->key[0].fVirt & FCONTROL) return 3; if (m_lpAccel->key[0].fVirt & FALT) return 2; if (m_lpAccel->key[0].fVirt & FSHIFT) return 1; return 4; } void CXTPShortcutManager::CKeyHelper::Format(CString& str) const { str.Empty (); if (m_lpAccel == NULL) { ASSERT (FALSE); return; } str = Format(&m_lpAccel->key[0]); if (m_lpAccel->key[1].key != 0) { CString str2 = Format(&m_lpAccel->key[1]); if (!str2.IsEmpty()) { str += _T(", ") + str2; } } } CString CXTPShortcutManager::CKeyHelper::Format(const CXTPShortcutManagerAccel::SHORTCUTACCEL* pAccel) const { CString str; if (pAccel->key != VK_CANCEL) { if (pAccel->fVirt & FCONTROL) { AddVirtKeyStr(str, VK_CONTROL); } if (pAccel->fVirt & FSHIFT) { AddVirtKeyStr(str, VK_SHIFT); } if (pAccel->fVirt & FALT) { AddVirtKeyStr(str, VK_MENU); } if (pAccel->fVirt & 0x20) { AddVirtKeyStr (str, VK_LWIN); } } if (pAccel->key) { if (pAccel->fVirt & FVIRTKEY) { AddVirtKeyStr(str, pAccel->key, TRUE); } else if ((pAccel->key >= 1 && pAccel->key <= 26) && (pAccel->fVirt == FNOINVERT)) { AddVirtKeyStr(str, VK_CONTROL); str += (char) ('A' + pAccel->key - 1); } else if (pAccel->key != VK_ESCAPE && pAccel->key != VK_TAB) { str += (char) pAccel->key; } } else if (str.GetLength() > 0) { str = str.Left(str.GetLength() - 1); } return str; } void CXTPShortcutManager::CKeyHelper::AddVirtKeyStr(CString& str, UINT uiVirtKey, BOOL bLast) const { ASSERT(m_pManager); if (!m_pManager) return; CString strKey; if (m_bAllowLocaleKey) { strKey = m_pManager->GetKeyNameText(uiVirtKey); } else { strKey = m_pManager->m_pKeyNameText->Translate(uiVirtKey); if (strKey.IsEmpty()) { strKey.Format(_T("0x%x"), uiVirtKey); } } if (!strKey.IsEmpty()) { str += strKey; if (!bLast) { str += '+'; } } } CString CXTPShortcutManager::CKeyHelper::GetLocalKeyNameText(UINT uiVirtKey) { #define BUFFER_LEN 50 TCHAR szBuffer[BUFFER_LEN + 1]; ZeroMemory(szBuffer, BUFFER_LEN); if (uiVirtKey == VK_CANCEL) return _T(""); UINT nScanCode = ::MapVirtualKeyEx (uiVirtKey, 0, ::GetKeyboardLayout (0)) << 16 | 0x1; if (uiVirtKey >= VK_PRIOR && uiVirtKey <= VK_HELP) { nScanCode |= 0x01000000; } ::GetKeyNameText(nScanCode, szBuffer, BUFFER_LEN); CString strKey = szBuffer; if (!strKey.IsEmpty()) { strKey.MakeLower(); for (int i = 0; i < strKey.GetLength(); i++) { TCHAR c = strKey[i]; if (IsCharLower(c)) { strKey.SetAt (i, CXTPShortcutManager::ToUpper(c)); break; } } } return strKey; } int CXTPShortcutManager::FindAccelPos(LPCTSTR lpszAccel) { LPCTSTR lpsz = _tcschr(lpszAccel, _T('&')); while (lpsz && *(lpsz + 1) == _T('&')) { lpsz = _tcschr(lpsz + 2, _T('&')); } return (lpsz == NULL) ? -1 : (int)(lpsz - lpszAccel); } BOOL CXTPShortcutManager::CompareAccelKey(TCHAR chAccel, UINT wParam) { if (wParam >= VK_NUMPAD0 && wParam <= VK_NUMPAD9) return (UINT)chAccel == (wParam + '0' - VK_NUMPAD0); TCHAR tchVirtualKey = (TCHAR)MapVirtualKey(wParam, 2); if (tchVirtualKey == NULL) return FALSE; TCHAR chAccelUpper = ToUpper(chAccel); if ((chAccel == (TCHAR)wParam) || (chAccelUpper == (TCHAR)wParam)) return TRUE; int nLayoutCount = GetKeyboardLayoutList(0, 0); if (nLayoutCount >= 1) { CArray arrLayoutList; arrLayoutList.SetSize(nLayoutCount); GetKeyboardLayoutList(nLayoutCount, arrLayoutList.GetData()); BYTE keyState[256]; if (!GetKeyboardState (keyState)) return FALSE; for (int i = 0; i < nLayoutCount; i++) { WORD chKey = 0; #ifdef _UNICODE if (ToUnicodeEx((UINT)wParam, 0, keyState, (LPWSTR)&chKey, 1, 0, arrLayoutList[i]) == 1) #else if (ToAsciiEx((UINT)wParam, 0, keyState, &chKey, 0, arrLayoutList[i]) == 1) #endif { if ((chAccel == (TCHAR)chKey) || (chAccelUpper == ToUpper((TCHAR)chKey))) return TRUE; } BYTE ksShift = keyState[VK_SHIFT]; keyState[VK_SHIFT]= 0x81; #ifdef _UNICODE if (ToUnicodeEx((UINT)wParam, 0, keyState, (LPWSTR)&chKey, 1, 0, arrLayoutList[i]) == 1) #else if (ToAsciiEx((UINT)wParam, 0, keyState, &chKey, 0, arrLayoutList[i]) == 1) #endif { if ((chAccel == (TCHAR)chKey) || (chAccelUpper == ToUpper((TCHAR)chKey))) return TRUE; } keyState[VK_SHIFT] = ksShift; } } return FALSE; } void CXTPShortcutManager::SetKeyNameText(UINT uiVirtKey, LPCTSTR strKeyNameText) { m_pKeyNameText->SetAt(uiVirtKey, strKeyNameText); } CString CXTPShortcutManager::GetKeyNameText(UINT uiVirtKey) { CString strKey; if (m_bUseSystemKeyNameText) { strKey = CKeyHelper::GetLocalKeyNameText(uiVirtKey); } if (strKey.IsEmpty()) { strKey = m_pKeyNameText->Translate(uiVirtKey); } if (strKey.IsEmpty() && !m_bUseSystemKeyNameText) { strKey = CKeyHelper::GetLocalKeyNameText(uiVirtKey); } return strKey; } TCHAR CXTPShortcutManager::ToUpper(TCHAR vkTCHAR) { TCHAR szChar[2] = {vkTCHAR, _T('\0') }; CharUpper(szChar); return szChar[0]; } ///////////////////////////////////////////////////////////////////////////// // CKeyAssign CXTPShortcutManager::CKeyAssign::CKeyAssign(CXTPShortcutManager* pManager/*= NULL*/) : m_keyHelper(&m_accel, pManager) { m_nKeyDefined = 0; m_bExtendedOnly = FALSE; m_bAllowDoubleKeyShortcuts = pManager ? pManager->m_bAllowDoubleKeyShortcuts : FALSE; ResetKey(); } CXTPShortcutManager::CKeyAssign::~CKeyAssign() { } BOOL CXTPShortcutManager::CKeyAssign::PreTranslateMessage(MSG* pMsg) { if (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_MBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN) { SetFocus (); return TRUE; } if (pMsg->message != WM_KEYDOWN && pMsg->message != WM_SYSKEYDOWN && pMsg->message != WM_KEYUP && pMsg->message != WM_SYSKEYUP) return CEdit::PreTranslateMessage(pMsg); if (m_bAllowDoubleKeyShortcuts) return TranslateDoubleKeyShortcutsMessage(pMsg); return TranslateSingleKeyShortcutsMessage(pMsg); } BOOL CXTPShortcutManager::CKeyAssign::TranslateDoubleKeyShortcutsMessage(MSG* pMsg) { BOOL bPressed = pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN; if (!bPressed) return FALSE; BOOL bControlPressed = ::GetKeyState(VK_CONTROL) & 0x8000; BOOL bAltPressed = ::GetKeyState(VK_MENU) & 0x8000; if (!bControlPressed && !bAltPressed && (pMsg->wParam == VK_TAB)) { return FALSE; } if (pMsg->wParam == VK_SHIFT || pMsg->wParam == VK_CONTROL || pMsg->wParam == VK_MENU) return FALSE; if (pMsg->wParam == VK_BACK) { if (m_nKeyDefined == 2) { m_accel.key[1].fVirt = 0; m_accel.key[1].key = 0; m_nKeyDefined = 1; } else { ResetKey(); } } else { if (m_nKeyDefined > 1) ResetKey(); if (m_nKeyDefined > 1) { ASSERT(FALSE); return FALSE; } // read in the actual state because we were not tracking releases if there was a // definition SetAccelFlag(m_nKeyDefined, FSHIFT, ::GetKeyState(VK_SHIFT) & 0x8000); SetAccelFlag(m_nKeyDefined, FCONTROL, bControlPressed); SetAccelFlag(m_nKeyDefined, FALT, bAltPressed); m_accel.key[m_nKeyDefined].key = (WORD)pMsg->wParam; SetAccelFlag(m_nKeyDefined, FVIRTKEY, TRUE); m_nKeyDefined++; } if (m_keyHelper.GetShortcutManager() && !m_keyHelper.GetShortcutManager()->OnPreviewEditKey(&m_accel)) { ResetKey(); return TRUE; } CString str; m_keyHelper.Format(str); SetWindowText(str); SetSel(str.GetLength(), str.GetLength()); return TRUE; } BOOL CXTPShortcutManager::CKeyAssign::TranslateSingleKeyShortcutsMessage(MSG* pMsg) { BOOL bPressed = pMsg->message == WM_KEYDOWN || pMsg->message == WM_SYSKEYDOWN; BOOL bControlPressed = ::GetKeyState(VK_CONTROL) & 0x8000; BOOL bAltPressed = ::GetKeyState(VK_MENU) & 0x8000; BOOL bWinPressed = (::GetKeyState(VK_LWIN) & 0x8000) || (::GetKeyState(VK_RWIN) & 0x8000); if (!bControlPressed && !bAltPressed && (pMsg->wParam == VK_TAB)) { if (m_nKeyDefined == 0) ResetKey(); return FALSE; } if (bPressed && !((1 << 30) & pMsg->lParam)) { ResetKey(); } if (m_bExtendedOnly) { if (bPressed) { SetAccelFlag(0, FSHIFT, GetKeyState(VK_SHIFT) < 0); SetAccelFlag(0, FCONTROL, GetKeyState(VK_CONTROL) < 0); SetAccelFlag(0, FALT, GetKeyState(VK_MENU) < 0); SetAccelFlag(0, 0x20, bWinPressed); } } else if (m_nKeyDefined == 0) { // read in the actual state because we were not tracking releases if there was a // definition SetAccelFlag(0, FSHIFT, ::GetKeyState(VK_SHIFT) & 0x8000); SetAccelFlag(0, FCONTROL, bControlPressed); SetAccelFlag(0, FALT, bAltPressed); SetAccelFlag(0, 0x20, bWinPressed); if (pMsg->wParam == VK_SHIFT || pMsg->wParam == VK_CONTROL || pMsg->wParam == VK_MENU || pMsg->wParam == VK_LWIN || pMsg->wParam == VK_RWIN ) { // all work is already done } else if (bPressed) { m_accel.key[0].key = (WORD)pMsg->wParam; SetAccelFlag(0, FVIRTKEY, TRUE); m_nKeyDefined = 1; } } if (m_keyHelper.GetShortcutManager() && !m_keyHelper.GetShortcutManager()->OnPreviewEditKey(&m_accel)) { ResetKey(); return TRUE; } CString str; m_keyHelper.Format (str); SetWindowText(str); return TRUE; } void CXTPShortcutManager::CKeyAssign::ResetKey() { m_accel.cmd = 0; m_accel.key[0].fVirt = m_accel.key[1].fVirt = 0; m_accel.key[0].key = m_accel.key[1].key = 0; m_nKeyDefined = 0; if (m_hWnd != NULL) { SetWindowText (_T("")); } } void CXTPShortcutManager::CKeyAssign::SetAccelFlag(int nKey, BYTE bFlag, BOOL bSet) { ASSERT(nKey == 0 || nKey == 1); if (nKey > 1) return; if (bSet) m_accel.key[nKey].fVirt |= bFlag; else m_accel.key[nKey].fVirt &= ~bFlag; } BOOL CXTPShortcutManager::CKeyAssign::IsKeyDefined () const { return m_nKeyDefined != 0; } CXTPShortcutManagerAccel* CXTPShortcutManager::CKeyAssign::GetAccel() { return &m_accel; } void CXTPShortcutManager::CKeyAssign::SetAccel(CXTPShortcutManagerAccel* pAccel) { m_accel = *pAccel; m_nKeyDefined = (m_accel.key[0].key != 0 ? 1 : 0) + (m_accel.key[1].key != 0 ? 1 : 0); if (m_hWnd != NULL) { CString str; m_keyHelper.Format (str); SetWindowText (str); } } void CXTPShortcutManager::UpdateAcellTable(LPACCEL lpAccel, int nSize) { m_pAccelTable->CopyAccelTable(lpAccel, nSize); } void CXTPShortcutManager::UpdateAcellTable(XTP_SHORTCUTMANAGER_ACCEL* lpAccel, int nSize) { m_pAccelTable->RemoveAll(); for (int i = 0; i < nSize; i++) { m_pAccelTable->Add(lpAccel[i]); } } BOOL CXTPShortcutManager::GetShortcut(int ID, CXTPShortcutManagerAccel* pAccel) { CXTPShortcutManagerAccelTable* pAccelTable = GetDefaultAccelerator(); if (!pAccelTable) return FALSE; for (int i = 0; i < pAccelTable->GetCount(); i++) { CXTPShortcutManagerAccel* accel = pAccelTable->GetAt(i); if (accel->cmd == ID) { *pAccel = *accel; return TRUE; } } return FALSE; } void CXTPShortcutManager::AddShortcut(long cmd, LPCTSTR strKey) { CXTPShortcutManagerAccel accel; if (!ParseShortcut(strKey, &accel)) return; accel.cmd = cmd; m_pAccelTable->Add(accel); } void CXTPShortcutManager::AddShortcut(long fVirt, long key, long cmd) { CXTPShortcutManagerAccel accel; accel.key[0].fVirt = (BYTE)(fVirt | FVIRTKEY); accel.key[0].key = (WORD)key; accel.cmd = cmd; int nAccelSize = m_pAccelTable->GetCount(); for (int i = 0; i < nAccelSize; i++) { CXTPShortcutManagerAccel* accelOld = m_pAccelTable->GetAt(i); if (CKeyHelper::EqualAccels(&accel, accelOld)) { accelOld->cmd = cmd; return; } } m_pAccelTable->Add(accel); } void CXTPShortcutManager::SerializeShortcuts(CArchive& ar) { CXTPPropExchangeArchive px(ar); DoPropExchange(&px); } void CXTPShortcutManager::SaveShortcuts(LPCTSTR lpszProfileName) { if (m_pOriginalAccelTable == NULL) return; XTP_SHORTCUTMANAGER_ACCEL* lpAccel = m_pAccelTable->CopyAccels(); AfxGetApp()->WriteProfileBinary(lpszProfileName, _T("Accelerators"), (LPBYTE)lpAccel, m_pAccelTable->GetCount() * sizeof(XTP_SHORTCUTMANAGER_ACCEL)); AfxGetApp()->WriteProfileInt(lpszProfileName, _T("AcceleratorsVersion"), 1); delete[] lpAccel; } void CXTPShortcutManager::LoadShortcuts(LPCTSTR lpszProfileName) { if (m_pOriginalAccelTable == NULL) return; int nVersion = AfxGetApp()->GetProfileInt(lpszProfileName, _T("AcceleratorsVersion"), 0); if (nVersion == 0) { UINT uiSize; LPACCEL lpAccel = 0; if (AfxGetApp()->GetProfileBinary(lpszProfileName, _T("Accelerators"), (LPBYTE*) &lpAccel, &uiSize)) { int nAccelSize = uiSize / sizeof(ACCEL); ASSERT (lpAccel != NULL); UpdateAcellTable(lpAccel, nAccelSize); delete[] lpAccel; } } else if (nVersion == 1) { UINT uiSize; XTP_SHORTCUTMANAGER_ACCEL* lpAccel = 0; if (AfxGetApp()->GetProfileBinary(lpszProfileName, _T("Accelerators"), (LPBYTE*) &lpAccel, &uiSize)) { int nAccelSize = uiSize / sizeof(XTP_SHORTCUTMANAGER_ACCEL); ASSERT (lpAccel != NULL); UpdateAcellTable(lpAccel, nAccelSize); delete[] lpAccel; } } } BOOL CXTPShortcutManager::ParseShortcutVirtKey(CString& strShortcutKey, int nAccel) const { CString str = m_pKeyNameText->Translate(nAccel) + _T('+'); int nIndex = strShortcutKey.Find(str); if (nIndex != -1) { strShortcutKey = strShortcutKey.Left(nIndex) + strShortcutKey.Mid(nIndex + str.GetLength()); return TRUE; } return FALSE; } BOOL CXTPShortcutManager::ParseShortcut(CString strShortcutKey, BYTE& fVirt, WORD& key) const { fVirt = FVIRTKEY; key = 0; if (ParseShortcutVirtKey(strShortcutKey, VK_CONTROL)) { fVirt |= FCONTROL; } if (ParseShortcutVirtKey(strShortcutKey, VK_MENU)) { fVirt |= FALT; } if (ParseShortcutVirtKey(strShortcutKey, VK_SHIFT)) { fVirt |= FSHIFT; } key = m_pKeyNameText->Parse(strShortcutKey); if (key != 0) return TRUE; if (strShortcutKey.GetLength() > 3 && strShortcutKey[0] == _T('0') && strShortcutKey[1] == _T('x')) { SCANF_S(strShortcutKey, _T("0x%hx"), &key); } return key != 0; } BOOL CXTPShortcutManager::ParseShortcut(CString strShortcut, CXTPShortcutManagerAccel* accel) { int nIndex = strShortcut.Find(_T(", ")); if (nIndex == -1) { if (!ParseShortcut(strShortcut, accel->key[0].fVirt, accel->key[0].key)) return FALSE; accel->key[1].fVirt = 0; accel->key[1].key = 0; } else { if (!ParseShortcut(strShortcut.Left(nIndex), accel->key[0].fVirt, accel->key[0].key)) return FALSE; if (!ParseShortcut(strShortcut.Mid(nIndex + 2), accel->key[1].fVirt, accel->key[1].key)) return FALSE; } return TRUE; } void CXTPShortcutManager::DoPropExchange(CXTPPropExchange* pPX) { pPX->ExchangeSchemaSafe(); if (pPX->IsStoring()) { int nAccelSize = m_pAccelTable->GetCount(); if (pPX->IsAllowBlobValues()) { XTP_SHORTCUTMANAGER_ACCEL* lpAccel = m_pAccelTable->CopyAccels(); pPX->WriteCount(nAccelSize); pPX->Write(_T("Data"), lpAccel, nAccelSize * sizeof(XTP_SHORTCUTMANAGER_ACCEL)); delete[] lpAccel; } else { CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Shortcut"))); POSITION posEnum = pEnumerator->GetPosition(nAccelSize); for (int i = 0; i < nAccelSize; i++) { CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum)); CXTPShortcutManagerAccel* pAccel = m_pAccelTable->GetAt(i); CString strShortcut; CKeyHelper keyHelper(pAccel, this); keyHelper.m_bAllowLocaleKey = FALSE; keyHelper.Format(strShortcut); PX_Int(&secItem, _T("Id"), pAccel->cmd, 0); PX_String(&secItem, _T("Key"), strShortcut); } } } else { m_pAccelTable->RemoveAll(); if (pPX->GetSchema() < _XTP_SCHEMA_1200) { if (pPX->IsAllowBlobValues()) { int nAccelSize = (int)pPX->ReadCount(); LPACCEL lpAccel = new ACCEL[nAccelSize]; pPX->Read(_T("Data"), lpAccel, nAccelSize* sizeof(ACCEL)); UpdateAcellTable(lpAccel, nAccelSize); delete[] lpAccel; } else { CArray accels; CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Accel"))); POSITION posEnum = pEnumerator->GetPosition(0); while (posEnum) { ACCEL accel; CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum)); PX_UShort(&secItem, _T("Id"), (USHORT&)(accel.cmd), 0); PX_Byte(&secItem, _T("virt"), (accel.fVirt), 0); PX_UShort(&secItem, _T("key"), (USHORT&)(accel.key), 0); accels.Add(accel); } UpdateAcellTable(accels.GetData(), (int)accels.GetSize()); } } else { if (pPX->IsAllowBlobValues()) { int nAccelSize = (int)pPX->ReadCount(); XTP_SHORTCUTMANAGER_ACCEL* lpAccel = new XTP_SHORTCUTMANAGER_ACCEL[nAccelSize]; pPX->Read(_T("Data"), lpAccel, nAccelSize * sizeof(XTP_SHORTCUTMANAGER_ACCEL)); UpdateAcellTable(lpAccel, nAccelSize); delete[] lpAccel; } else { CXTPPropExchangeEnumeratorPtr pEnumerator(pPX->GetEnumerator(_T("Shortcut"))); POSITION posEnum = pEnumerator->GetPosition(0); while (posEnum) { CXTPShortcutManagerAccel accel; CXTPPropExchangeSection secItem(pEnumerator->GetNext(posEnum)); PX_Int(&secItem, _T("Id"), accel.cmd, 0); CString strShortcut; // TODO: Add Parse Here PX_String(&secItem, _T("Key"), strShortcut, _T("")); if (ParseShortcut(strShortcut, &accel)) { m_pAccelTable->Add(accel); } } } } } } BOOL CXTPShortcutManager::OnBeforeAdd(CXTPShortcutManagerAccel* accel) { UNREFERENCED_PARAMETER(accel); return FALSE; } BOOL CXTPShortcutManager::OnBeforeRemove(CXTPShortcutManagerAccel* accel) { UNREFERENCED_PARAMETER(accel); return FALSE; }