// 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<HKL, HKL&> 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<ACCEL, ACCEL&> 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;
}