1
0
mirror of https://github.com/taigrr/arduinolibs synced 2025-01-18 04:33:12 -08:00
arduinolibs/gen/genkeymap.cpp
2016-03-05 13:21:25 +10:00

305 lines
8.6 KiB
C++

/*
* Copyright (C) 2016 Southern Storm Software, Pty Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// Generates the keymap state machine table for the Terminal class.
#include <stdio.h>
#include <stdint.h>
#include <vector>
#include "../libraries/Terminal/USBKeysExtra.h"
typedef struct {
const char *sequence;
int code;
} EscKey;
static EscKey const escKeys[] = {
// Based on the key sequence tables from:
// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h2-PC-Style-Function-Keys
// http://aperiodic.net/phil/archives/Geekery/term-function-keys.html
// Also some miscellaneous codes from other sources like the Linux console.
// Cursor control keys.
{"[A", KEY_UP_ARROW},
{"OA", KEY_UP_ARROW},
{"A", KEY_UP_ARROW},
{"[B", KEY_DOWN_ARROW},
{"OB", KEY_DOWN_ARROW},
{"B", KEY_DOWN_ARROW},
{"[C", KEY_RIGHT_ARROW},
{"OC", KEY_RIGHT_ARROW},
{"C", KEY_RIGHT_ARROW},
{"[D", KEY_LEFT_ARROW},
{"OD", KEY_LEFT_ARROW},
{"D", KEY_LEFT_ARROW},
{"[H", KEY_HOME},
{"OH", KEY_HOME},
{"[1~", KEY_HOME},
{"[F", KEY_END},
{"OF", KEY_END},
{"[4~", KEY_END},
{"[2~", KEY_INSERT},
{"[3~", KEY_DELETE},
{"[5~", KEY_PAGE_UP},
{"[6~", KEY_PAGE_DOWN},
// Numeric keypad. Mostly mapped back to ASCII.
{"O ", ' '},
{"? ", ' '},
{"OI", KEY_TAB},
{"?I", KEY_TAB},
{"OM", KEY_RETURN},
{"?M", KEY_RETURN},
{"Oj", '*'},
{"?j", '*'},
{"Ok", '+'},
{"?k", '+'},
{"Ol", ','},
{"?l", ','},
{"Om", '-'},
{"?m", '-'},
{"On", '.'},
{"?n", '.'},
{"Oo", '/'},
{"?o", '/'},
{"Op", '0'},
{"?p", '0'},
{"Oq", '1'},
{"?q", '1'},
{"Or", '2'},
{"?r", '2'},
{"Os", '3'},
{"?s", '3'},
{"Ot", '4'},
{"?t", '4'},
{"Ou", '5'},
{"?u", '5'},
{"Ov", '6'},
{"?v", '6'},
{"Ow", '7'},
{"?w", '7'},
{"Ox", '8'},
{"?x", '8'},
{"Oy", '9'},
{"?y", '9'},
{"OX", '='},
{"?X", '='},
// Function keys.
{"[11~", KEY_F1},
{"P", KEY_F1},
{"OP", KEY_F1},
{"[[A", KEY_F1},
{"[12~", KEY_F2},
{"Q", KEY_F2},
{"OQ", KEY_F2},
{"[[B", KEY_F2},
{"[13~", KEY_F3},
{"R", KEY_F3},
{"OR", KEY_F3},
{"[[C", KEY_F3},
{"[14~", KEY_F4},
{"S", KEY_F4},
{"OS", KEY_F4},
{"[[D", KEY_F4},
{"[15~", KEY_F5},
{"[[E", KEY_F5},
{"[17~", KEY_F6},
{"[18~", KEY_F7},
{"[19~", KEY_F8},
{"[20~", KEY_F9},
{"[21~", KEY_F10},
{"[23~", KEY_F11},
{"[24~", KEY_F12},
{"[25~", KEY_F13},
{"[11;2~", KEY_F13},
{"O2P", KEY_F13},
{"[26~", KEY_F14},
{"[12;2~", KEY_F14},
{"O2Q", KEY_F14},
{"[28~", KEY_F15},
{"[13;2~", KEY_F15},
{"O2R", KEY_F15},
{"[29~", KEY_F16},
{"[14;2~", KEY_F16},
{"O2S", KEY_F16},
{"[31~", KEY_F17},
{"[15;2~", KEY_F17},
{"[32~", KEY_F18},
{"[17;2~", KEY_F18},
{"[33~", KEY_F19},
{"[18;2~", KEY_F19},
{"[34~", KEY_F20},
{"[19;2~", KEY_F20},
{"[20;2~", KEY_F21},
{"[23$", KEY_F21},
{"[21;2~", KEY_F22},
{"[24$", KEY_F22},
{"[23;2~", KEY_F23},
{"[11^", KEY_F23},
{"[24;2~", KEY_F24},
{"[12^", KEY_F24},
// Other keys.
{"[Z", KEY_BACK_TAB},
{"OZ", KEY_BACK_TAB},
{"[P", KEY_PAUSE},
{"[G", KEY_NUMPAD_5},
};
#define numEscKeys (sizeof(escKeys) / sizeof(escKeys[0]))
class Node
{
public:
explicit Node(Node *parent = 0);
~Node();
void add(const char *str, int code);
void dumpRules(std::vector<uint8_t> *vec);
int ch;
int code;
int offset;
Node *firstChild;
Node *lastChild;
Node *nextChild;
};
Node::Node(Node *parent)
: ch(0)
, code(-1)
, offset(0)
, firstChild(0)
, lastChild(0)
, nextChild(0)
{
if (parent) {
if (parent->lastChild)
parent->lastChild->nextChild = this;
else
parent->firstChild = this;
parent->lastChild = this;
}
}
Node::~Node()
{
Node *child = firstChild;
Node *next;
while (child != 0) {
next = child->nextChild;
delete child;
child = next;
}
}
void Node::add(const char *str, int code)
{
int ch = str[0] & 0xFF;
Node *child = firstChild;
while (child != 0) {
if (child->ch == ch)
break;
child = child->nextChild;
}
if (!child) {
child = new Node(this);
child->ch = ch;
}
if (str[1] == '\0') {
// Leaf node at the end of a string.
child->code = code;
} else {
// Interior node with more children.
child->add(str + 1, code);
}
}
void Node::dumpRules(std::vector<uint8_t> *vec)
{
Node *child;
// First pass: Output the recognizers for this level.
offset = vec->size();
child = firstChild;
while (child != 0) {
if (child->firstChild) {
// Interior nodes need 3 bytes for the character and offset.
vec->push_back((uint8_t)(child->ch | 0x80));
vec->push_back(0);
vec->push_back(0);
} else {
// Leaf nodes need 2 bytes for the character and code.
vec->push_back((uint8_t)(child->ch));
vec->push_back((uint8_t)(child->code));
if (child->code > 255)
printf("Code 0x%X exceeds 255 - need to change table format\n", child->code);
}
child = child->nextChild;
}
vec->push_back(0); // Terminate this level.
// Second pass: Output the recognizers for the child levels.
child = firstChild;
while (child != 0) {
if (child->firstChild)
child->dumpRules(vec);
child = child->nextChild;
}
// Third pass: Back-patch the links to the child recognizers.
int posn = offset;
child = firstChild;
while (child != 0) {
if (child->firstChild) {
int value = child->offset;
(*vec)[posn + 1] = (uint8_t)value;
(*vec)[posn + 2] = (uint8_t)(value >> 8);
posn += 3;
} else {
posn += 2;
}
child = child->nextChild;
}
}
int main(int argc, char *argv[])
{
Node *root = new Node();
for (unsigned index = 0; index < numEscKeys; ++index)
root->add(escKeys[index].sequence, escKeys[index].code);
std::vector<uint8_t> vec;
root->dumpRules(&vec);
printf("static uint8_t const keymap[%d] PROGMEM = {\n", (int)vec.size());
for (unsigned index = 0; index < vec.size(); ++index) {
if ((index % 12) == 0)
printf(" ");
printf("0x%02X", (int)(vec[index]));
if ((index % 12) == 11)
printf(",\n");
else
printf(", ");
}
printf("};\n");
delete root;
return 0;
}