1/*
2 * Copyright 1999-2009 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Jeremy Friesner
7 */
8
9
10#include "KeyInfos.h"
11
12#include <ctype.h>
13#include <sstream>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string>
17#include <strings.h>
18
19#include <InterfaceDefs.h>
20
21
22#define NUM_KEYS 128
23#define MAX_UTF8_LENGTH 5
24	// up to 4 chars, plus a \0 terminator
25
26
27struct KeyLabelMap {
28	const char* fLabel;
29	uint8 fKeyCode;
30};
31
32
33// This is a table of keys-codes that have special, hard-coded labels.
34static const struct KeyLabelMap keyLabels[] = {
35	{"<unset>",		0},
36	{"Esc",			1},
37	{"F1",			2},
38	{"F2",			3},
39	{"F3",			4},
40	{"F4",			5},
41	{"F5",			6},
42	{"F6",			7},
43	{"F7",			8},
44	{"F8",			9},
45	{"F9",			10},
46	{"F10",			11},
47	{"F11",			12},
48	{"F12",			13},
49	{"SysRq",		14},
50	{"ScrlLck",		15},
51	{"Pause",		16},
52	{"Bcksp",		30},
53	{"Insert",		31},
54	{"Home",		32},
55	{"PgUp",		33},
56	{"Num Lock",	34},
57	{"Kpd /",		35},
58	{"Kpd *",		36},
59	{"Kpd -",		37},
60	{"Tab",			38},
61	{"Delete",		52},
62	{"End",			53},
63	{"PgDn",		54},
64	{"Kpd 7",		55},
65	{"Kpd 8",		56},
66	{"Kpd 9",		57},
67	{"Kpd +",		58},
68	{"Caps Lock",	59},
69	{"Enter",		71},
70	{"Kpd 4",		72},
71	{"Kpd 5",		73},
72	{"Kpd 6",		74},
73	{"L.Shift",		75},
74	{"R.Shift",		86},
75	{"Up",			87},
76	{"Kpd 1",		88},
77	{"Kpd 2",		89},
78	{"Kpd 3",		90},
79	{"Kpd Entr",	91},
80	{"L.Control",	92},
81	{"L.Alt",		93},
82	{"Space",		94},
83	{"R.Alt",		95},
84	{"R.Control",	96},
85	{"Left",		97},
86	{"Down",		98},
87	{"Right",		99},
88	{"Kpd 0",		100},
89	{"Kpd .",		101},
90	{"L.Command",	102},
91	{"R.Command",	103},
92	{"Menu",		104},
93	{"PowerOn",		107},
94};
95
96
97// Key description strings (e.g. "A" or "Escape"). NULL if no description is
98// available.
99static const char* keyDescriptions[NUM_KEYS];
100
101
102// series of optional up-to-(4+1)-byte terminated UTF-8 character strings...
103static char utfDescriptions[NUM_KEYS * MAX_UTF8_LENGTH];
104
105
106static const char*
107FindSpecialKeyLabelFor(uint8 keyCode, uint32& last)
108{
109	while ((keyLabels[last].fKeyCode < keyCode)
110		&& (last < (sizeof(keyLabels) / sizeof(struct KeyLabelMap)) - 1)) {
111		last++;
112	}
113
114	if (keyLabels[last].fKeyCode == keyCode)
115		return keyLabels[last].fLabel;
116	else
117		return NULL;
118}
119
120
121void
122InitKeyIndices()
123{
124	uint32 nextSpecial = 0;
125	key_map* map;
126	char* keys;
127	get_key_map(&map, &keys);
128
129	if (map == NULL || keys == NULL)
130		return;
131
132	for (uint8 j = 0; j < NUM_KEYS; j++) {
133		keyDescriptions[j] = NULL;
134			// default
135
136		const char* specialLabel = FindSpecialKeyLabelFor(j, nextSpecial);
137		int32 keyCode = map->normal_map[j];
138
139		if (keyCode >= 0) {
140			const char* mapDesc = &keys[keyCode];
141			uint8 length = *mapDesc;
142
143			for (int m = 0; m < MAX_UTF8_LENGTH; m++)
144				if (m < length)
145					utfDescriptions[j * MAX_UTF8_LENGTH + m] = mapDesc[m + 1];
146				else
147					utfDescriptions[j * MAX_UTF8_LENGTH + m] = '\0';
148
149			if (specialLabel != NULL)
150				keyDescriptions[j] = specialLabel;
151			else {
152				// If it's an ASCII letter, capitalize it.
153				char& c = utfDescriptions[j * MAX_UTF8_LENGTH];
154
155				if ((length == 1) && (isalpha(c)))
156					c = toupper(c);
157
158				if (length > 1 || (length == 1 && c > ' '))
159					keyDescriptions[j] = &c;
160			}
161		} else
162			utfDescriptions[j * MAX_UTF8_LENGTH] = 0x00;
163	}
164
165	free(keys);
166	free(map);
167}
168
169
170const char*
171GetKeyUTF8(uint8 keyIndex)
172{
173	return &utfDescriptions[keyIndex * MAX_UTF8_LENGTH];
174}
175
176
177const char*
178GetKeyName(uint32 keyIndex)
179{
180	if (keyIndex >= NUM_KEYS)
181		return NULL;
182	return keyDescriptions[keyIndex];
183}
184
185
186BString
187GetFallbackKeyName(uint32 keyCode)
188{
189	BString keyCodeName = "KeyCode ";
190	std::stringstream sstream;
191	sstream << std::hex << keyCode;
192	keyCodeName.Append(sstream.str().c_str());
193	return keyCodeName;
194}
195
196
197int
198GetNumKeyIndices()
199{
200	return NUM_KEYS;
201}
202
203
204uint32
205FindKeyCode(const char* keyName)
206{
207	if (strncmp(keyName, "KeyCode ", 7) == 0)
208		return strtoul(keyName + 7, NULL, 16);
209
210	for (uint8 i = 0; i < NUM_KEYS; i++) {
211		if ((keyDescriptions[i])
212			&& (strcasecmp(keyName, keyDescriptions[i]) == 0)) {
213			return i;
214		}
215	}
216
217	return 0;
218		// default to sentinel value
219}
220