You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

485 lines
11 KiB

/*
* Copyright (C) 2000 Brian Harris
* Copyright (C) 2006 Dorian Boissonnade
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "StdAfx.h"
#include "MfcEmbed.h"
#include "AccelParser.h"
#include "Utils.h"
#include "resource.h"
#include "Plugins.h"
#define BEGIN_VK_TEST if (0){}
#define VK_TEST(KEY) else if (stricmp(p, #KEY) == 0){ key = VK_##KEY; }
// a few that winuser.h doesn't have for some reason (snagged from msdn)
#define VK_OEM_PLUS 0xBB
#define VK_OEM_COMMA 0xBC
#define VK_OEM_MINUS 0xBD
#define VK_OEM_PERIOD 0xBE
// and some more friendly definitions...
#define VK_PLUS VK_OEM_PLUS
#define VK_EQUALS VK_OEM_PLUS
#define VK_MINUS VK_OEM_MINUS
#define VK_COMMA VK_OEM_COMMA
#define VK_PERIOD VK_OEM_PERIOD
#define VK_PERIOD VK_OEM_PERIOD
#define VK_PAGE_UP VK_PRIOR
#define VK_PAGE_DOWN VK_NEXT
//Standard accel to show in menu
static const ACCEL stdAccels[] = {
{FCONTROL, 'C', ID_EDIT_COPY},
{FCONTROL, 'V', ID_EDIT_PASTE},
{FCONTROL, 'X', ID_EDIT_CUT},
{FVIRTKEY|FALT, VK_F4, ID_FILE_CLOSE}
};
extern BOOL ParsePluginCommand(char *pszCommand, char** plugin, char **parameter);
CAccelParser::CAccelParser()
{
accelTable = NULL;
numAccelerators = 0;
memset(accelerators, 0, sizeof(ACCEL) * MAX_ACCEL);
numMKeys = 0;
memset(mouse, 0, sizeof(ACCEL) * MAX_MOUSE);
}
CAccelParser::CAccelParser(LPCTSTR filename)
{
accelTable = NULL;
numAccelerators = 0;
memset(accelerators, 0, sizeof(ACCEL) * MAX_ACCEL);
Load(filename);
}
CAccelParser::~CAccelParser()
{
if (accelTable){
DestroyAcceleratorTable(accelTable);
}
}
int CAccelParser::Load(LPCTSTR filename)
{
SETUP_LOG("Accel");
if (accelTable){
DestroyAcceleratorTable(accelTable);
accelTable = NULL;
numAccelerators = 0;
}
int retVal = CParser::Load(filename);
END_LOG();
return retVal;
}
int CAccelParser::Parse(char *p)
{
// <modifiers> <key> = <command>
char *e = strchr(p, '=');
if (e){
*e = 0;
e++;
e = SkipWhiteSpace(e);
TrimWhiteSpace(e);
TrimWhiteSpace(p);
return SetAccel(p, e);
}
return 0;
}
int CAccelParser::SetAccel(const char* pKey, const char* pCommand)
{
int command = 0;
const char *alt, *ctrl, *shift;
const char* p;
BYTE virt;
int key;
command = theApp.commands.GetId(pCommand);
if (!command) {
LOG_ERROR_1( "Command %s is unknow", pCommand);
//return 0;
}
virt = 0;
p = pKey;
alt = strstr(pKey, "ALT");
if (alt){
virt |= FALT;
p = alt + 3;
}
ctrl = strstr(pKey, "CTRL");
if (ctrl){
virt |= FCONTROL;
if (ctrl > alt){
p = ctrl + 4;
}
}
shift = strstr(pKey, "SHIFT");
if (shift){
virt |= FSHIFT;
if ((shift > alt) && (shift > ctrl)){
p = shift + 5;
}
}
// by now, p should be past the modifiers and point to " <key>"
p = SkipWhiteSpace((char*)p);
if (strncmp(p, "VK_", 3) == 0){
p+=3;
key = 0;
// these should be in order of frequency of use to speed up parsing
BEGIN_VK_TEST
VK_TEST(ESCAPE)
VK_TEST(LEFT)
VK_TEST(RIGHT)
VK_TEST(F1)
VK_TEST(F2)
VK_TEST(F3)
VK_TEST(F4)
VK_TEST(F5)
VK_TEST(F6)
VK_TEST(F7)
VK_TEST(F8)
VK_TEST(F9)
VK_TEST(F10)
VK_TEST(F11)
VK_TEST(F12)
VK_TEST(HOME)
VK_TEST(END)
VK_TEST(PRIOR) // page up
VK_TEST(NEXT) // page down
VK_TEST(PAGE_UP)
VK_TEST(PAGE_DOWN)
VK_TEST(UP)
VK_TEST(DOWN)
VK_TEST(INSERT)
VK_TEST(DELETE)
VK_TEST(SPACE)
VK_TEST(HELP)
VK_TEST(EXECUTE)
VK_TEST(SELECT)
VK_TEST(PRINT)
VK_TEST(SNAPSHOT) // print screen?
VK_TEST(PLUS)
VK_TEST(MINUS)
VK_TEST(COMMA)
VK_TEST(PERIOD)
VK_TEST(EQUALS)
VK_TEST(BACK)
VK_TEST(TAB)
VK_TEST(CLEAR)
VK_TEST(RETURN)
VK_TEST(MULTIPLY)
VK_TEST(ADD)
VK_TEST(SUBTRACT)
VK_TEST(DECIMAL)
VK_TEST(DIVIDE)
VK_TEST(SEPARATOR)
VK_TEST(PAUSE)
VK_TEST(CAPITAL)
VK_TEST(MENU)
VK_TEST(BROWSER_BACK)
VK_TEST(BROWSER_FORWARD)
VK_TEST(BROWSER_REFRESH)
VK_TEST(BROWSER_STOP)
VK_TEST(BROWSER_SEARCH)
VK_TEST(BROWSER_FAVORITES)
VK_TEST(BROWSER_HOME)
/*
VK_TEST(KANA)
VK_TEST(JUNJA)
VK_TEST(FINAL)
VK_TEST(HANJA)
VK_TEST(KANJI)
VK_TEST(CONVERT)
VK_TEST(NONCONVERT)
VK_TEST(ACCEPT)
VK_TEST(MODECHANGE)
*/
VK_TEST(LWIN)
VK_TEST(RWIN)
VK_TEST(APPS)
VK_TEST(NUMPAD0)
VK_TEST(NUMPAD1)
VK_TEST(NUMPAD2)
VK_TEST(NUMPAD3)
VK_TEST(NUMPAD4)
VK_TEST(NUMPAD5)
VK_TEST(NUMPAD6)
VK_TEST(NUMPAD7)
VK_TEST(NUMPAD8)
VK_TEST(NUMPAD9)
/*
VK_TEST(F13)
VK_TEST(F14)
VK_TEST(F15)
VK_TEST(F16)
VK_TEST(F17)
VK_TEST(F18)
VK_TEST(F19)
VK_TEST(F20)
VK_TEST(F21)
VK_TEST(F22)
VK_TEST(F23)
VK_TEST(F24)
*/
VK_TEST(NUMLOCK)
VK_TEST(SCROLL)
}
else if (stricmp(p, "LButton") == 0){
SetMAccel(command, virt, WM_LBUTTONDOWN);
return true;
}
else if (stricmp(p, "MButton") == 0){
SetMAccel(command, virt, WM_MBUTTONDOWN);
return true;
}
else if (stricmp(p, "RButton") == 0){
SetMAccel(command, virt, WM_RBUTTONDOWN);
return true;
}
else {
// regular key, convert it to virtual-key code to
// get the associated key on the keyboard.
key = VkKeyScanA(*p) & 0xff;
}
virt |= FVIRTKEY;
SetAccel(command, virt, key);
LOG_2("Added accelerator %s with command %s", pKey, pCommand);
return true;
}
void CAccelParser::SetAccel(WORD command, BYTE virt, WORD key)
{
int oldAccel = FindAccel(virt, key);
if (command != 0 && oldAccel == -1) {
if (numAccelerators == MAX_ACCEL) return;
accelerators[numAccelerators].cmd = command;
accelerators[numAccelerators].fVirt = virt;
accelerators[numAccelerators].key = key;
numAccelerators++;
}
else {
if (command != 0)
accelerators[oldAccel].cmd = command;
else if (oldAccel>=0)
DeleteAccel(oldAccel);
}
if (accelTable) {
DestroyAcceleratorTable(accelTable);
accelTable = NULL;
}
}
void CAccelParser::SetMAccel(WORD command, BYTE virt, WORD button)
{
int oldAccel = FindMAccel(virt, button);
if (command == 0) {
if(oldAccel != -1)
DeleteMAccel(oldAccel);
return;
}
if (oldAccel != -1) {
mouse[oldAccel].cmd = command;
return;
}
if (numMKeys == MAX_MOUSE) return;
mouse[numMKeys].cmd = command;
mouse[numMKeys].fVirt = virt;
mouse[numMKeys].key = button;
numMKeys++;
}
void CAccelParser::DeleteMAccel(int idx)
{
ASSERT(idx>=0&&idx<=MAX_MOUSE);
int i;
--numMKeys;
for (i=idx;i<numMKeys;i++)
mouse[i] = mouse[i+1];
}
void CAccelParser::DeleteAccel(int idx)
{
ASSERT(idx>=0&&idx<=MAX_ACCEL);
int i;
--numAccelerators;
for (i=idx;i<numAccelerators;i++)
accelerators[i] = accelerators[i+1];
}
int CAccelParser::FindMAccel(WORD virt, DWORD key)
{
const ACCEL* accel = NULL;
for (int i=0;i<numAccelerators;i++)
if (mouse[i].key == key && mouse[i].fVirt == virt)
return i;
return -1;
}
int CAccelParser::FindAccel(WORD virt, DWORD key)
{
const ACCEL* accel = NULL;
for (int i=0;i<numAccelerators;i++)
if (accelerators[i].key == key && accelerators[i].fVirt == virt)
return i;
return -1;
}
HACCEL CAccelParser::GetTable(){
if (!accelTable){
accelTable = CreateAcceleratorTable(accelerators, numAccelerators);
}
return accelTable;
}
CString CAccelParser::GetStrAccel(UINT id)
{
const ACCEL* accel = NULL;
for (int i=0;i<numAccelerators;i++) {
if (accelerators[i].cmd == id) {
accel = &accelerators[i];
break;
}
}
if (!accel) {
for (int i=0;i<sizeof(stdAccels)/sizeof(ACCEL);i++) {
if (stdAccels[i].cmd == id) {
accel = &stdAccels[i];
break;
}
}
}
if (accel) {
CString str;
TCHAR buf[25];
if(accel->fVirt & FCONTROL) {
GetKeyNameText(MapVirtualKey(VK_CONTROL, 0)<<16, buf, sizeof(buf) / sizeof(TCHAR));
if (*buf) {
CharLowerBuff(buf+1, _tcslen(buf)-1);
str = str + buf + _T("+");
}
}
if(accel->fVirt & FSHIFT) {
GetKeyNameText(MapVirtualKey(VK_SHIFT, 0)<<16, buf, sizeof(buf) / sizeof(TCHAR));
if (*buf) {
CharLowerBuff(buf+1, _tcslen(buf)-1);
str = str + buf + _T("+");
}
}
if(accel->fVirt & FALT) {
GetKeyNameText(MapVirtualKey(VK_MENU, 0)<<16, buf, sizeof(buf) / sizeof(TCHAR));
if (*buf) {
CharLowerBuff(buf+1, _tcslen(buf)-1);
str = str + buf + _T("+");
}
}
if(accel->fVirt & FVIRTKEY) {
WORD key = accel->key;
UINT scan = MapVirtualKey(key, 0);
if ((key >= VK_PRIOR) && (key<=VK_DELETE))
scan |= 0x100; // should remove the numpad text
if (GetKeyNameText(scan<<16 , buf, sizeof(buf) / sizeof(TCHAR)) == 0)
return _T("");
// Since I can't find a way to remove the numpad indication
// for /,* or . I'm removing it the hard way.
TCHAR* parenthesis = _tcschr(buf, '(');
if (parenthesis && parenthesis>buf)
*parenthesis = 0;
if (*buf) {
CharLowerBuff(buf+1, _tcslen(buf)-1);
str += buf;
}
}
else {
char c[2] = { accel->key & 0xff, '\0' };
USES_CONVERSION;
str += A2CT(c);
}
return str;
}
return _T("");
}
int CAccelParser::CheckMouse(UINT message){
int i, virt = 0;
virt = message >> 8;
switch (message & 0xff) {
case MK_LBUTTON: message = WM_LBUTTONDOWN; break;
case MK_RBUTTON: message = WM_RBUTTONDOWN; break;
case MK_MBUTTON: message = WM_MBUTTONDOWN; break;
default : ;
}
for (i=0; i<numMKeys; i++) {
if (mouse[i].key == message) {
if (mouse[i].fVirt == virt)
return mouse[i].cmd;
}
}
return 0;
}