aseprite/src/ui/accelerator.cpp

431 lines
10 KiB
C++
Raw Normal View History

// Aseprite UI Library
2013-01-27 23:13:13 +08:00
// Copyright (C) 2001-2013 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
2007-09-19 07:57:02 +08:00
#ifdef HAVE_CONFIG_H
2009-07-13 04:29:16 +08:00
#include "config.h"
#endif
2009-07-13 04:29:16 +08:00
#include "ui/accelerator.h"
#include "base/unique_ptr.h"
#include "base/split_string.h"
#include "base/string.h"
2007-09-19 07:57:02 +08:00
#include <allegro/keyboard.h>
#include <ctype.h>
#include <string>
#include <vector>
2007-09-19 07:57:02 +08:00
// #define REPORT_KEYS
#define PREPROCESS_KEYS
namespace ui {
void Accelerator::addKey(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
2007-09-19 07:57:02 +08:00
{
KeyCombo key;
2007-09-19 07:57:02 +08:00
key.modifiers = modifiers;
key.scancode = scancode;
key.unicodeChar = unicodeChar;
2007-09-19 07:57:02 +08:00
m_combos.push_back(key);
2007-09-19 07:57:02 +08:00
}
void Accelerator::addKeysFromString(const std::string& str)
2007-09-19 07:57:02 +08:00
{
KeyModifiers modifiers = kKeyNoneModifier;
KeyScancode scancode = kKeyNil;
int unicodeChar = 0;
// Special case: plus sign
if (str == "+") {
addKey(kKeyNoneModifier, kKeyNil, '+');
return;
}
2007-09-19 07:57:02 +08:00
std::vector<std::string> tokens;
base::split_string(str, tokens, "+");
for (std::string tok : tokens) {
tok = base::string_to_lower(tok);
if (scancode == kKeySpace) {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeySpaceModifier);
scancode = kKeyNil;
}
2007-09-19 07:57:02 +08:00
// Modifiers
if (tok == "shift") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyShiftModifier);
}
else if (tok == "alt") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
}
else if (tok == "ctrl") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCtrlModifier);
}
else if (tok == "cmd") {
modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
}
2007-09-19 07:57:02 +08:00
// Scancode
2007-09-19 07:57:02 +08:00
// word with one character
else if (tok.size() == 1) {
if ((tok[0] >= 'a') && (tok[0] <= 'z')) {
unicodeChar = tok[0];
2007-09-19 07:57:02 +08:00
}
else {
unicodeChar = tok[0];
2007-09-19 07:57:02 +08:00
}
if ((tok[0] >= 'a') && (tok[0] <= 'z'))
scancode = (KeyScancode)((int)kKeyA + tolower(tok[0]) - 'a');
else if ((tok[0] >= '0') && (tok[0] <= '9'))
scancode = (KeyScancode)((int)kKey0 + tok[0] - '0');
2007-09-19 07:57:02 +08:00
else {
switch (tok[0]) {
case '~': scancode = kKeyTilde; break;
case '-': scancode = kKeyMinus; break;
case '=': scancode = kKeyEquals; break;
case '[': scancode = kKeyOpenbrace; break;
case ']': scancode = kKeyClosebrace; break;
case ';': scancode = kKeyColon; break;
case '\'': scancode = kKeyQuote; break;
case '\\': scancode = kKeyBackslash; break;
case ',': scancode = kKeyComma; break;
case '.': scancode = kKeyStop; break;
case '/': scancode = kKeySlash; break;
case '*': scancode = kKeyAsterisk; break;
}
2007-09-19 07:57:02 +08:00
}
}
/* other ones */
else {
/* F1, F2, ..., F11, F12 */
if (tok[0] == 'f' && (tok.size() <= 3)) {
int num = strtol(tok.c_str()+1, NULL, 10);
if ((num >= 1) && (num <= 12))
scancode = (KeyScancode)((int)kKeyF1 + num - 1);
2007-09-19 07:57:02 +08:00
}
else if ((tok == "escape") || (tok == "esc"))
scancode = kKeyEsc;
else if (tok == "backspace")
scancode = kKeyBackspace;
else if (tok == "tab")
scancode = kKeyTab;
else if (tok == "enter")
scancode = kKeyEnter;
else if (tok == "space")
scancode = kKeySpace;
else if ((tok == "insert") || (tok == "ins"))
scancode = kKeyInsert;
else if ((tok == "delete") || (tok == "del"))
scancode = kKeyDel;
else if (tok == "home")
scancode = kKeyHome;
else if (tok == "end")
scancode = kKeyEnd;
else if ((tok == "page up") || (tok == "pgup"))
scancode = kKeyPageUp;
else if ((tok == "page down") || (tok == "pgdn"))
scancode = kKeyPageDown;
else if (tok == "left")
scancode = kKeyLeft;
else if (tok == "right")
scancode = kKeyRight;
else if (tok == "up")
scancode = kKeyUp;
else if (tok == "down")
scancode = kKeyDown;
else if (tok == "0 pad")
scancode = kKey0Pad;
else if (tok == "1 pad")
scancode = kKey1Pad;
else if (tok == "2 pad")
scancode = kKey2Pad;
else if (tok == "3 pad")
scancode = kKey3Pad;
else if (tok == "4 pad")
scancode = kKey4Pad;
else if (tok == "5 pad")
scancode = kKey5Pad;
else if (tok == "6 pad")
scancode = kKey6Pad;
else if (tok == "7 pad")
scancode = kKey7Pad;
else if (tok == "8 pad")
scancode = kKey8Pad;
else if (tok == "9 pad")
scancode = kKey9Pad;
else if (tok == "slash pad")
scancode = kKeySlashPad;
else if (tok == "asterisk")
scancode = kKeyAsterisk;
else if (tok == "minus pad")
scancode = kKeyMinusPad;
else if (tok == "plus pad")
scancode = kKeyPlusPad;
else if (tok == "del pad")
scancode = kKeyDelPad;
else if (tok == "enter pad")
scancode = kKeyEnterPad;
2007-09-19 07:57:02 +08:00
}
}
addKey(modifiers, scancode, unicodeChar);
2007-09-19 07:57:02 +08:00
}
std::string Accelerator::KeyCombo::toString()
2007-09-19 07:57:02 +08:00
{
// Same order that Allegro scancodes
2007-09-19 07:57:02 +08:00
static const char *table[] = {
NULL,
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"0 Pad",
"1 Pad",
"2 Pad",
"3 Pad",
"4 Pad",
"5 Pad",
"6 Pad",
"7 Pad",
"8 Pad",
"9 Pad",
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"F8",
"F9",
"F10",
"F11",
"F12",
"Esc",
"~",
"-",
"=",
"Backspace",
"Tab",
"[",
"]",
"Enter",
";",
"\'",
"\\",
"KEY_BACKSLASH2",
",",
".",
"/",
"Space",
"Ins",
"Del",
"Home",
"End",
"PgUp",
"PgDn",
"Left",
"Right",
"Up",
"Down",
"/ Pad",
"* Pad",
"- Pad",
"+ Pad",
"Delete Pad",
"Enter Pad",
"PrtScr",
"Pause",
"KEY_ABNT_C1",
"Yen",
"Kana",
"KEY_CONVERT",
"KEY_NOCONVERT",
"KEY_AT",
"KEY_CIRCUMFLEX",
"KEY_COLON2",
"Kanji",
};
std::string buf;
2007-09-19 07:57:02 +08:00
// Shifts
if (this->modifiers & kKeyCtrlModifier) buf += "Ctrl+";
if (this->modifiers & kKeyCmdModifier) buf += "Cmd+";
if (this->modifiers & kKeyAltModifier) buf += "Alt+";
if (this->modifiers & kKeyShiftModifier) buf += "Shift+";
if (this->modifiers & kKeySpaceModifier) buf += "Space+";
2007-09-19 07:57:02 +08:00
// Key
if (this->unicodeChar)
buf += (wchar_t)toupper(this->unicodeChar);
else if (this->scancode)
buf += table[this->scancode];
else if (!buf.empty() && buf[buf.size()-1] == '+')
buf.erase(buf.size()-1);
return buf;
2007-09-19 07:57:02 +08:00
}
std::string Accelerator::toString()
2007-09-19 07:57:02 +08:00
{
ASSERT(!m_combos.empty());
return m_combos.front().toString();
2007-09-19 07:57:02 +08:00
}
bool Accelerator::check(KeyModifiers modifiers, KeyScancode scancode, int unicodeChar)
2007-09-19 07:57:02 +08:00
{
#ifdef REPORT_KEYS
char buf[256];
std::string buf2;
2007-09-19 07:57:02 +08:00
#endif
// Preprocess the character to be compared with the accelerator
2007-09-19 07:57:02 +08:00
#ifdef PREPROCESS_KEYS
// Directly scancode
if ((scancode >= kKeyF1 && scancode <= kKeyF12) ||
(scancode == kKeyEsc) ||
(scancode == kKeyBackspace) ||
(scancode == kKeyTab) ||
(scancode == kKeyEnter) ||
(scancode == kKeyBackslash) ||
(scancode == kKeyBackslash2) ||
(scancode >= kKeySpace && scancode <= kKeyDown) ||
(scancode >= kKeyEnterPad && scancode <= kKeyNoconvert) ||
(scancode == kKeyKanji)) {
unicodeChar = 0;
2007-09-19 07:57:02 +08:00
}
// For Ctrl+number
/* scancode unicodeChar
2007-09-19 07:57:02 +08:00
Ctrl+0 27 0
Ctrl+1 28 2
Ctrl+2 29 0
Ctrl+3 30 27
Ctrl+4 31 28
Ctrl+5 32 29
Ctrl+6 33 30
Ctrl+7 34 31
Ctrl+8 35 127
Ctrl+9 36 2
*/
else if ((scancode >= kKey0 && scancode <= kKey9) &&
(unicodeChar < 32 || unicodeChar == 127)) {
unicodeChar = '0' + scancode - kKey0;
scancode = kKeyNil;
2007-09-19 07:57:02 +08:00
}
// For Ctrl+letter
else if (unicodeChar >= 1 && unicodeChar <= 'z'-'a'+1) {
unicodeChar = 'a'+unicodeChar-1;
scancode = kKeyNil;
2007-09-19 07:57:02 +08:00
}
// For any other legal Unicode code
else if (unicodeChar >= ' ') {
unicodeChar = tolower(unicodeChar);
2007-09-19 07:57:02 +08:00
/* without shift (because characters like '*' can be trigger with
"Shift+8", so we don't want "Shift+*") */
if (!(unicodeChar >= 'a' && unicodeChar <= 'z'))
modifiers = (KeyModifiers)((int)modifiers & ((int)~kKeyShiftModifier));
2007-09-19 07:57:02 +08:00
scancode = kKeyNil;
2007-09-19 07:57:02 +08:00
}
#endif
#ifdef REPORT_KEYS
{
base::UniquePtr<Accelerator> a2(new Accelerator);
a2->addKey(modifiers, scancode, unicodeChar);
buf2 = a2->getString();
2007-09-19 07:57:02 +08:00
}
#endif
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
it != end; ++it) {
2007-09-19 07:57:02 +08:00
#ifdef REPORT_KEYS
printf("%3d==%3d %3d==%3d %s==%s ",
it->scancode, scancode, it->unicodeChar, unicodeChar,
it->getString().c_str(), buf2.c_str();
2007-09-19 07:57:02 +08:00
#endif
if ((it->modifiers == modifiers) &&
((it->scancode != kKeyNil && it->scancode == scancode) ||
(it->unicodeChar && it->unicodeChar == unicodeChar))) {
2007-09-19 07:57:02 +08:00
#ifdef REPORT_KEYS
2009-07-10 09:34:37 +08:00
printf("true\n");
2007-09-19 07:57:02 +08:00
#endif
2009-07-10 09:34:37 +08:00
return true;
2007-09-19 07:57:02 +08:00
}
#ifdef REPORT_KEYS
2009-07-10 09:34:37 +08:00
printf("false\n");
2007-09-19 07:57:02 +08:00
#endif
}
2009-07-10 09:34:37 +08:00
return false;
2007-09-19 07:57:02 +08:00
}
bool Accelerator::checkFromAllegroKeyArray()
{
KeyModifiers modifiers = kKeyNoneModifier;
if (key[KEY_LSHIFT] ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyShiftModifier);
if (key[KEY_RSHIFT] ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyShiftModifier);
if (key[KEY_LCONTROL]) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCtrlModifier);
if (key[KEY_RCONTROL]) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCtrlModifier);
if (key[KEY_ALT] ) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyAltModifier);
if (key[KEY_COMMAND ]) modifiers = (KeyModifiers)((int)modifiers | (int)kKeyCmdModifier);
for (KeyCombos::iterator it = m_combos.begin(), end = m_combos.end();
it != end; ++it) {
if ((it->scancode == 0 || key[it->scancode]) &&
(it->modifiers == modifiers)) {
return true;
}
}
return false;
}
} // namespace ui