The Pedigree Project 0.1
KeymapManager.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/machine/HidInputManager.h"
22#include "pedigree/kernel/machine/Keyboard.h"
23#include "pedigree/kernel/machine/KeymapManager.h"
24#include "pedigree/kernel/machine/keymaps/KeymapEnUs.h"
25#include "pedigree/kernel/utilities/utility.h"
26
27// #define DEBUG_KEYMAP
28
29#ifdef DEBUG_KEYMAP
30#define KM_NOTICE NOTICE
31#else
32#define KM_NOTICE(...)
33#endif
34
35#define KEYMAP_INDEX(combinator, modifiers, scancode) \
36 (((combinator & 0xFF) << 11) | ((modifiers & 0xF) << 7) | (scancode & 0x7F))
37#define KEYMAP_MAX_INDEX KEYMAP_INDEX(0xFF, 0xF, 0x7F)
38
40
42 : m_pSparseTable(0),
43 m_pDataTable(0),
44 m_bLeftCtrl(false),
45 m_bLeftShift(false),
46 m_bLeftAlt(false),
47 m_bRightCtrl(false),
48 m_bRightShift(false),
49 m_bRightAlt(false),
50 m_bCapsLock(false),
51 m_nCombinator(0),
52 m_bHaveLoadedKeymap(false) {
53 void* sparseBuffer = ASSUME_ALIGNMENT(sparseBuff, sizeof(void*));
54 void* dataBuffer = ASSUME_ALIGNMENT(dataBuff, sizeof(void*));
55
56 m_pSparseTable = reinterpret_cast<SparseEntry*>(sparseBuffer);
57 m_pDataTable = reinterpret_cast<KeymapEntry*>(dataBuffer);
58}
59
61
62void KeymapManager::useKeymap(uint8_t* pSparseTable, uint8_t* pDataTable) {
63 void* sparseBuffer = ASSUME_ALIGNMENT(pSparseTable, sizeof(void*));
64 void* dataBuffer = ASSUME_ALIGNMENT(pDataTable, sizeof(void*));
65
66 SparseEntry* oldSparse = m_pSparseTable;
67 KeymapEntry* oldData = m_pDataTable;
68
69 // Set the table pointers
70 m_pSparseTable = reinterpret_cast<SparseEntry*>(sparseBuffer);
71 m_pDataTable = reinterpret_cast<KeymapEntry*>(dataBuffer);
72
73 // Check for a sensible keymap (40 == return key)
74 if (!resolveHidKeycode(40)) {
75 ERROR("KeymapManager: new keymap check failed, restoring old keymap");
76 m_pSparseTable = oldSparse;
77 m_pDataTable = oldData;
78 } else if (m_bHaveLoadedKeymap) {
79 delete[] oldSparse;
80 delete[] oldData;
81 }
82
83 // Make the HID input manager update all its keys
85
86 // We've now loaded a keymap - all future loads should free the previous
87 // keymap once the new one is loaded.
89}
90
91bool KeymapManager::useCompiledKeymap(uint32_t* pCompiledKeymap, size_t keymapLength) {
92 // File format: 0 Sparse tree offset
93 // 4 Data tree offset
94 // ... Sparse tree & data tree.
95
96 uint32_t sparseTableOffset = pCompiledKeymap[0];
97 uint32_t dataTableOffset = pCompiledKeymap[1];
98 uint32_t sparseTableSize = dataTableOffset - sparseTableOffset;
99 uint32_t dataTableSize = keymapLength - dataTableOffset;
100
101 // Preserve the previous keymap in case we need to restore it.
102 SparseEntry* oldSparse = m_pSparseTable;
103 KeymapEntry* oldData = m_pDataTable;
104
105 // Set up our new tables.
106 m_pSparseTable = new SparseEntry[sparseTableSize / sizeof(SparseEntry)];
107 m_pDataTable = new KeymapEntry[dataTableSize / sizeof(KeymapEntry)];
108
109 MemoryCopy(m_pSparseTable, adjust_pointer(pCompiledKeymap, sparseTableOffset), sparseTableSize);
110 MemoryCopy(m_pDataTable, adjust_pointer(pCompiledKeymap, dataTableOffset), dataTableSize);
111
112 // Check for sensible keymap.
113 if (!resolveHidKeycode(40)) {
114 ERROR("KeymapManager: new keymap check failed, restoring old keymap");
115 m_pSparseTable = oldSparse;
116 m_pDataTable = oldData;
117
118 return false;
119 } else if (m_bHaveLoadedKeymap) {
120 delete[] oldSparse;
121 delete[] oldData;
122 }
123
124 // Make the HID input manager update all its keys
126
127 // We've now loaded a keymap - all future loads should free the previous
128 // keymap once the new one is loaded.
129 m_bHaveLoadedKeymap = true;
130
131 return true;
132}
133
134bool KeymapManager::handleHidModifier(uint8_t keyCode, bool bDown) {
135 // If the key isn't a modifier, return false right away
136 if (!((keyCode >= HidLeftCtrl && keyCode <= HidRightGui) || keyCode == HidCapsLock))
137 return false;
138 // Handle modifier keys, enabled on keyDown, disabled on keyUp
139 if (keyCode == HidLeftCtrl)
140 m_bLeftCtrl = bDown;
141 if (keyCode == HidRightCtrl)
142 m_bRightCtrl = bDown;
143 if (keyCode == HidLeftShift)
144 m_bLeftShift = bDown;
145 if (keyCode == HidRightShift)
146 m_bRightShift = bDown;
147 if (keyCode == HidLeftAlt)
148 m_bLeftAlt = bDown;
149 if (keyCode == HidRightAlt)
150 m_bRightAlt = bDown;
151 // Handle CapsLock key, changes on keyUp
152 if (keyCode == HidCapsLock && !bDown)
154 return true;
155}
156
157uint64_t KeymapManager::resolveHidKeycode(uint8_t keyCode) {
158 KM_NOTICE("resolveHidKeycode(" << keyCode << ")");
159
160 // Get the modifiers
161 bool bCtrl = m_bLeftCtrl || m_bRightCtrl;
162 bool bShift = m_bLeftShift || m_bRightShift;
163 bool bAlt = m_bLeftAlt, bAltGr = m_bRightAlt;
164
165 bool bUseUpper = false; // Use the upper case keymap
166
167 if (m_bCapsLock ^ bShift)
168 bUseUpper = true;
169
170 // Try and grab a keymap entry for the scancode with all modifiers enabled.
171 KeymapEntry* pKeymapEntry = getKeymapEntry(bCtrl, bShift, bAlt, bAltGr, m_nCombinator, keyCode);
172 // Fallback and try without combinator
173 if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags)) {
174 KM_NOTICE("keymap: falling back: -combinator");
175 pKeymapEntry = getKeymapEntry(bCtrl, bShift, bAlt, bAltGr, 0, keyCode);
176 }
177 // Fallback and try without combinator and Ctrl
178 if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags)) {
179 KM_NOTICE("keymap: falling back: -combinator, -ctrl");
180 pKeymapEntry = getKeymapEntry(false, bShift, bAlt, bAltGr, 0, keyCode);
181 }
182 // Fallback and try with only Shift
183 if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags)) {
184 KM_NOTICE("keymap: falling back: -combinator, -ctrl, -alt");
185 pKeymapEntry = getKeymapEntry(false, bShift, false, false, 0, keyCode);
186 }
187 // Fallback and try with no modifier enabled
188 if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags)) {
189 KM_NOTICE("keymap: falling back: -combinator, -ctrl, -alt, -shift");
190 pKeymapEntry = getKeymapEntry(false, false, false, false, 0, keyCode);
191 }
192 // This key has no entry at all in the keymap
193 if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags)) {
194 KM_NOTICE("keymap: no fallback possible, key not in keymap");
195 return 0;
196 }
197
198 KM_NOTICE("keymap: successfully got a keymap entry");
199
200 // Does this key set any combinator?
201 uint32_t nCombinator = pKeymapEntry->flags & 0xFF;
202 if (nCombinator) {
203 // If the key sets the same combinator that we're currently using,
204 // the "dead" key becomes live and shows the default key.
205 if (nCombinator == m_nCombinator) {
206 // Unset combinator and fall through to display default glyph
207 m_nCombinator = 0;
208 } else {
209 // Change combinator
210 m_nCombinator = nCombinator;
211 return 0;
212 }
213 } else {
214 // Dead keys should be reset here
215 m_nCombinator = 0;
216 }
217
218 uint64_t key = pKeymapEntry->value;
219
220 if (pKeymapEntry->flags & KeymapEntry::Special)
221 key |= Keyboard::Special;
222 else if (bUseUpper && key >= 'a' && key <= 'z')
223 key -= ('a' - 'A');
224 else if (!bUseUpper && key >= 'A' && key <= 'Z')
225 key += ('a' - 'A');
226
227 if (bCtrl)
228 key |= Keyboard::Ctrl;
229 if (bShift)
230 key |= Keyboard::Shift;
231 if (bAlt)
232 key |= Keyboard::Alt;
233 if (bAltGr)
234 key |= Keyboard::AltGr;
235
236 return key;
237}
238
240 bool bAltGr, uint8_t nCombinator,
241 uint8_t keyCode) {
242 KM_NOTICE("getKeymapEntry(ctrl=" << bCtrl << ", shift=" << bShift << ", alt=" << bAlt
243 << ", altgr=" << bAltGr << ", comb=" << nCombinator
244 << ", code=" << keyCode << ")");
245
246 // Grab the keymap table index for this key
247 size_t modifiers = 0;
248 if (bCtrl)
249 modifiers |= IndexCtrl;
250 if (bShift)
251 modifiers |= IndexShift;
252 if (bAlt)
253 modifiers |= IndexAlt;
254 if (bAltGr)
255 modifiers |= IndexAltGr;
256 size_t nIndex = KEYMAP_INDEX(nCombinator, modifiers, keyCode);
257
258 KM_NOTICE("idx=" << nIndex << ", mods=" << modifiers << ", code=" << keyCode);
259
260 // Now walk the sparse tree
261 size_t bisect = (KEYMAP_MAX_INDEX + 1) / 2;
262 size_t size = (KEYMAP_MAX_INDEX + 1) / 2;
263 SparseEntry* pSparse = m_pSparseTable;
264 size_t nDataIndex = 0;
265 while (true) {
266 if (nIndex < bisect) {
267 if (!pSparse->left)
268 return 0;
269 if (pSparse->left & SparseEntry::DataFlag) {
270 size_t nOffset = nIndex - (bisect - size);
271 nDataIndex = (pSparse->left & ~SparseEntry::DataFlag) + nOffset * sizeof(KeymapEntry);
272 break;
273 }
274 size /= 2;
275 bisect = bisect - size;
276 pSparse = &m_pSparseTable[pSparse->left / sizeof(SparseEntry)];
277 } else {
278 if (!pSparse->right)
279 return 0;
280 if (pSparse->right & SparseEntry::DataFlag) {
281 size_t nOffset = nIndex - bisect;
282 nDataIndex = (pSparse->right & ~SparseEntry::DataFlag) + nOffset * sizeof(KeymapEntry);
283 break;
284 }
285 size /= 2;
286 bisect = bisect + size;
287 pSparse = &m_pSparseTable[pSparse->right / sizeof(SparseEntry)];
288 }
289 }
290
291 // Return the found keymap entry
292 return &m_pDataTable[nDataIndex / sizeof(KeymapEntry)];
293}
294
295// These tables originated from qemu
296// Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
297static const uint8_t pc102ToHidTableNormal[] = {
298 0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
299 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c, 0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
300 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33, 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
301 0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, 0xe2, 0x2c, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
302 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f, 0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
303 0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x64, 0x44, 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
304 0x00, 0x00, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
305 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65};
306
307static const uint8_t pc102ToHidTableEscape[] = {
308 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
310 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a, 0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
313 0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
314 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
316
317uint8_t KeymapManager::convertPc102ScancodeToHidKeycode(uint8_t scancode, EscapeState& escape) {
318 // Handle escape scancode 0xE0
319 if (scancode == 0xE0) {
320 escape = EscapeE0;
321 return 0;
322 }
323
324 // Handle escape scancode 0xE1
325 if (scancode == 0xE1) {
326 escape = EscapeE1;
327 return 0;
328 }
329
330 // Treat 0xE1 0x1D as 0xE0 (escape scancode)
331 if (scancode == 0x1D && escape == EscapeE1) {
332 escape = EscapeE0;
333 return 0;
334 }
335
336 if (escape) {
337 escape = EscapeNone;
338 KM_NOTICE("keymap: using escape table to convert PC102 scancode " << scancode);
339 return pc102ToHidTableEscape[scancode & 0x7F];
340 } else {
341 KM_NOTICE("keymap: using normal table to convert PC102 scancode " << scancode);
342 return pc102ToHidTableNormal[scancode & 0x7F];
343 }
344}
static HidInputManager & instance()
Singleton design.
void updateKeys()
Apply modifier or keymap changes to all keys in down state.
bool handleHidModifier(uint8_t keyCode, bool bDown)
static KeymapManager m_Instance
Static instance.
bool m_bLeftCtrl
State of the modifiers, true if down, false if up.
bool useCompiledKeymap(uint32_t *pCompiledKeymap, size_t keymapLength)
Changes the current keymap to the given (compiled) one.
KeymapEntry * getKeymapEntry(bool bCtrl, bool bShift, bool bAlt, bool bAltGr, uint8_t nCombinator, uint8_t keyCode)
Returns the keymap entry corresponding to given keycode and modifiers.
uint8_t m_nCombinator
Index of the current active combinator, if any.
SparseEntry * m_pSparseTable
The sparse and data tables for the current keymap.
virtual ~KeymapManager()
Default destructor.
uint8_t convertPc102ScancodeToHidKeycode(uint8_t scancode, EscapeState &escape)
Converts a pc102 scancode into a HID keycode.
bool m_bCapsLock
True if caps lock is on.
uint64_t resolveHidKeycode(uint8_t keyCode)
KeymapManager()
Default constructor.
void useKeymap(uint8_t *pSparseTable, uint8_t *pDataTable)
Changes the current keymap to the given one.
Structure representing an entry in the keymap table.
Structure representing an entry in the sparse table.