Since there is some renewed interest in the topic, here is the code that maps the virtual scancodes to physical keys for the 3 os:
class QwertyCode {
public:
/* some keys are not really handled (shift, alt, ctrl, capslock etc) */
typedef enum {
INVALID,
NUMSQUARE, NUM1, NUM2, NUM3, NUM4, NUM5, NUM6, NUM7, NUM8, NUM9, NUM0, NUMMINUS, NUMEQUAL, BACKSPACE,
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRACKET, RBRACKET,
CAPSLOCK, A, S, D, F, G, H, J, K, L, SEMICOLON, APOSTROPHE, ANTISLASH,
LSHIFT, Z, X, C, V, B, N, M, COMMA, DOT, SLASH, RSHIFT,
LCONTROL, LWIN, LALT, SPACEBAR, RALT, RWIN, RCONTROL,
ESCAPE, RETURN
} Code;
Code code;
QwertyCode() : code(INVALID) {}
QwertyCode(int i) : code((Code)i) {}
operator int() const { return code; }
bool isValid() const { return code > INVALID && code <= RETURN; }
static QwertyCode fromScanCode(int scan_code) {
#ifdef TARGET_DARWIN
int q2s[RETURN+1] =
{-1,
10, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51,
48, 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30,
57, 0, 1, 2, 3, 5, 4, 38, 40, 37, 41, 39, 42,
56, 6, 7, 8, 9, 11, 45, 46, 43, 47, 44, 60,
59, 58, 55, 49, 54, 61, -1,
53, 36
};
xassert(q2s[RETURN] == 36);
#elif defined(TARGET_WIN32)
int q2s[RETURN+1] =
{-1,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
-1, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 43,
42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
29, 91, 56, 57, 56, 92, 29,
1, 28 /* return */};
xassert(q2s[RETURN] == 28);
#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID)
int q2s[RETURN+1] =
{-1,
49, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
-1, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 51,
50, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
37,115, 64, 65,113,116, -1,
9, 36};
xassert(q2s[RETURN] == 36);
#else
#error todo..
#endif
for (int i=0; i < RETURN+1; ++i) {
if (scan_code == q2s[i]) return (QwertyCode)i;
}
return INVALID;
}
static QwertyCode fromAscii(char asc) {
// the star '*' marks invalid entries
const char *lst = "*^1234567890-=\b\tqwertyuiop[]*asdfghjkl;'\\*zxcvbnm,./**** ***\033\015";
xassert(strlen(lst) == RETURN+1);
const char *p = strchr(lst, asciiToLower(asc));
if (p) return QwertyCode((Code)(p - lst));
else return QwertyCode();
}
// range of values: x=[0..15], y=[0..5]
void keyBounds(float &x, float &y, float &w, float &h) {
x = y = 0; w = 1; h = 1;
if (code == INVALID) {
w = 0;
} else if (code >= NUMSQUARE && code <= BACKSPACE) {
y = 0;
x = (code - NUMSQUARE);
if (code == BACKSPACE) w = 2;
} else if (code >= TAB && code <= RBRACKET) {
y = 1;
if (code == TAB) {
w = 1.5;
} else x = 1.5 + (code - TAB - 1);
} else if (code >= CAPSLOCK && code <= ANTISLASH) {
y = 2;
if (code == CAPSLOCK) {
w = 1.8;
} else x = 1.8 + (code - A);
} else if (code >= LSHIFT && code <= RSHIFT) {
y = 3;
if (code == LSHIFT) {
w = 2.4;
} else x = 2.4 + (code - LSHIFT - 1);
if (code == RSHIFT) w = 5 - 2.4;
} else if (code >= LCONTROL && code <= RCONTROL) {
y = 4;
float xx[] = { 0, 1.5, 3, 4.5, 10.5, 12, 13.5, 15 };
xassert(C_ARRAY_LENGTH(xx) == (RCONTROL - LCONTROL + 2));
int i = code - LCONTROL;
x = xx[i]; w = xx[i+1] - xx[i];
} else if (code == RETURN) {
y = 1; x = 13.8; w = 1.2; h = 2;
}
}
std::string toString() const {
const char *str[RETURN+1] =
{"INVALID",
"NUMSQUARE", "NUM1", "NUM2", "NUM3", "NUM4", "NUM5", "NUM6", "NUM7", "NUM8", "NUM9", "NUM0", "NUMMINUS", "NUMEQUAL", "BACKSPACE",
"TAB", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "LBRACKET", "RBRACKET",
"CAPSLOCK", "A", "S", "D", "F", "G", "H", "J", "K", "L", "SEMICOLON", "APOSTROPHE", "ANTISLASH",
"LSHIFT", "Z", "X", "C", "V", "B", "N", "M", "COMMA", "DOT", "SLASH", "RSHIFT",
"LCONTROL", "LWIN", "LALT", "SPACEBAR", "RALT", "RWIN", "RCONTROL",
"ESCAPE", "RETURN" };
xassert(str[RETURN] && strcmp(str[RETURN], "RETURN") == 0);
if (code >= 0 && code <= RETURN) return str[code]; else return "???";
}
};