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/machine/KeymapManager.h"
21 #include "pedigree/kernel/Log.h"
22 #include "pedigree/kernel/machine/HidInputManager.h"
23 #include "pedigree/kernel/machine/Keyboard.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), m_pDataTable(0), m_bLeftCtrl(false),
43  m_bLeftShift(false), m_bLeftAlt(false), m_bRightCtrl(false),
44  m_bRightShift(false), m_bRightAlt(false), m_bCapsLock(false),
45  m_nCombinator(0), m_bHaveLoadedKeymap(false)
46 {
47  void *sparseBuffer = ASSUME_ALIGNMENT(sparseBuff, sizeof(void *));
48  void *dataBuffer = ASSUME_ALIGNMENT(dataBuff, sizeof(void *));
49 
50  m_pSparseTable = reinterpret_cast<SparseEntry *>(sparseBuffer);
51  m_pDataTable = reinterpret_cast<KeymapEntry *>(dataBuffer);
52 }
53 
55 {
56 }
57 
58 void KeymapManager::useKeymap(uint8_t *pSparseTable, uint8_t *pDataTable)
59 {
60  void *sparseBuffer = ASSUME_ALIGNMENT(pSparseTable, sizeof(void *));
61  void *dataBuffer = ASSUME_ALIGNMENT(pDataTable, sizeof(void *));
62 
63  SparseEntry *oldSparse = m_pSparseTable;
64  KeymapEntry *oldData = m_pDataTable;
65 
66  // Set the table pointers
67  m_pSparseTable = reinterpret_cast<SparseEntry *>(sparseBuffer);
68  m_pDataTable = reinterpret_cast<KeymapEntry *>(dataBuffer);
69 
70  // Check for a sensible keymap (40 == return key)
71  if (!resolveHidKeycode(40))
72  {
73  ERROR("KeymapManager: new keymap check failed, restoring old keymap");
74  m_pSparseTable = oldSparse;
75  m_pDataTable = oldData;
76  }
77  else if (m_bHaveLoadedKeymap)
78  {
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.
88  m_bHaveLoadedKeymap = true;
89 }
90 
92  uint32_t *pCompiledKeymap, size_t keymapLength)
93 {
94  // File format: 0 Sparse tree offset
95  // 4 Data tree offset
96  // ... Sparse tree & data tree.
97 
98  uint32_t sparseTableOffset = pCompiledKeymap[0];
99  uint32_t dataTableOffset = pCompiledKeymap[1];
100  uint32_t sparseTableSize = dataTableOffset - sparseTableOffset;
101  uint32_t dataTableSize = keymapLength - dataTableOffset;
102 
103  // Preserve the previous keymap in case we need to restore it.
104  SparseEntry *oldSparse = m_pSparseTable;
105  KeymapEntry *oldData = m_pDataTable;
106 
107  // Set up our new tables.
108  m_pSparseTable = new SparseEntry[sparseTableSize / sizeof(SparseEntry)];
109  m_pDataTable = new KeymapEntry[dataTableSize / sizeof(KeymapEntry)];
110 
111  MemoryCopy(
112  m_pSparseTable, adjust_pointer(pCompiledKeymap, sparseTableOffset),
113  sparseTableSize);
114  MemoryCopy(
115  m_pDataTable, adjust_pointer(pCompiledKeymap, dataTableOffset),
116  dataTableSize);
117 
118  // Check for sensible keymap.
119  if (!resolveHidKeycode(40))
120  {
121  ERROR("KeymapManager: new keymap check failed, restoring old keymap");
122  m_pSparseTable = oldSparse;
123  m_pDataTable = oldData;
124 
125  return false;
126  }
127  else if (m_bHaveLoadedKeymap)
128  {
129  delete[] oldSparse;
130  delete[] oldData;
131  }
132 
133  // Make the HID input manager update all its keys
135 
136  // We've now loaded a keymap - all future loads should free the previous
137  // keymap once the new one is loaded.
138  m_bHaveLoadedKeymap = true;
139 
140  return true;
141 }
142 
143 bool KeymapManager::handleHidModifier(uint8_t keyCode, bool bDown)
144 {
145  // If the key isn't a modifier, return false right away
146  if (!((keyCode >= HidLeftCtrl && keyCode <= HidRightGui) ||
147  keyCode == HidCapsLock))
148  return false;
149  // Handle modifier keys, enabled on keyDown, disabled on keyUp
150  if (keyCode == HidLeftCtrl)
151  m_bLeftCtrl = bDown;
152  if (keyCode == HidRightCtrl)
153  m_bRightCtrl = bDown;
154  if (keyCode == HidLeftShift)
155  m_bLeftShift = bDown;
156  if (keyCode == HidRightShift)
157  m_bRightShift = bDown;
158  if (keyCode == HidLeftAlt)
159  m_bLeftAlt = bDown;
160  if (keyCode == HidRightAlt)
161  m_bRightAlt = bDown;
162  // Handle CapsLock key, changes on keyUp
163  if (keyCode == HidCapsLock && !bDown)
165  return true;
166 }
167 
168 uint64_t KeymapManager::resolveHidKeycode(uint8_t keyCode)
169 {
170  KM_NOTICE("resolveHidKeycode(" << keyCode << ")");
171 
172  // Get the modifiers
173  bool bCtrl = m_bLeftCtrl || m_bRightCtrl;
174  bool bShift = m_bLeftShift || m_bRightShift;
175  bool bAlt = m_bLeftAlt, bAltGr = m_bRightAlt;
176 
177  bool bUseUpper = false; // Use the upper case keymap
178 
179  if (m_bCapsLock ^ bShift)
180  bUseUpper = true;
181 
182  // Try and grab a keymap entry for the scancode with all modifiers enabled.
183  KeymapEntry *pKeymapEntry =
184  getKeymapEntry(bCtrl, bShift, bAlt, bAltGr, m_nCombinator, keyCode);
185  // Fallback and try without combinator
186  if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags))
187  {
188  KM_NOTICE("keymap: falling back: -combinator");
189  pKeymapEntry = getKeymapEntry(bCtrl, bShift, bAlt, bAltGr, 0, keyCode);
190  }
191  // Fallback and try without combinator and Ctrl
192  if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags))
193  {
194  KM_NOTICE("keymap: falling back: -combinator, -ctrl");
195  pKeymapEntry = getKeymapEntry(false, bShift, bAlt, bAltGr, 0, keyCode);
196  }
197  // Fallback and try with only Shift
198  if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags))
199  {
200  KM_NOTICE("keymap: falling back: -combinator, -ctrl, -alt");
201  pKeymapEntry = getKeymapEntry(false, bShift, false, false, 0, keyCode);
202  }
203  // Fallback and try with no modifier enabled
204  if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags))
205  {
206  KM_NOTICE("keymap: falling back: -combinator, -ctrl, -alt, -shift");
207  pKeymapEntry = getKeymapEntry(false, false, false, false, 0, keyCode);
208  }
209  // This key has no entry at all in the keymap
210  if (!pKeymapEntry || (!pKeymapEntry->value && !pKeymapEntry->flags))
211  {
212  KM_NOTICE("keymap: no fallback possible, key not in keymap");
213  return 0;
214  }
215 
216  KM_NOTICE("keymap: successfully got a keymap entry");
217 
218  // Does this key set any combinator?
219  uint32_t nCombinator = pKeymapEntry->flags & 0xFF;
220  if (nCombinator)
221  {
222  // If the key sets the same combinator that we're currently using,
223  // the "dead" key becomes live and shows the default key.
224  if (nCombinator == m_nCombinator)
225  {
226  // Unset combinator and fall through to display default glyph
227  m_nCombinator = 0;
228  }
229  else
230  {
231  // Change combinator
232  m_nCombinator = nCombinator;
233  return 0;
234  }
235  }
236  else
237  {
238  // Dead keys should be reset here
239  m_nCombinator = 0;
240  }
241 
242  uint64_t key = pKeymapEntry->value;
243 
244  if (pKeymapEntry->flags & KeymapEntry::Special)
245  key |= Keyboard::Special;
246  else if (bUseUpper && key >= 'a' && key <= 'z')
247  key -= ('a' - 'A');
248  else if (!bUseUpper && key >= 'A' && key <= 'Z')
249  key += ('a' - 'A');
250 
251  if (bCtrl)
252  key |= Keyboard::Ctrl;
253  if (bShift)
254  key |= Keyboard::Shift;
255  if (bAlt)
256  key |= Keyboard::Alt;
257  if (bAltGr)
258  key |= Keyboard::AltGr;
259 
260  return key;
261 }
262 
264  bool bCtrl, bool bShift, bool bAlt, bool bAltGr, uint8_t nCombinator,
265  uint8_t keyCode)
266 {
267  KM_NOTICE(
268  "getKeymapEntry(ctrl=" << bCtrl << ", shift=" << bShift
269  << ", alt=" << bAlt << ", altgr=" << bAltGr
270  << ", comb=" << nCombinator
271  << ", code=" << keyCode << ")");
272 
273  // Grab the keymap table index for this key
274  size_t modifiers = 0;
275  if (bCtrl)
276  modifiers |= IndexCtrl;
277  if (bShift)
278  modifiers |= IndexShift;
279  if (bAlt)
280  modifiers |= IndexAlt;
281  if (bAltGr)
282  modifiers |= IndexAltGr;
283  size_t nIndex = KEYMAP_INDEX(nCombinator, modifiers, keyCode);
284 
285  KM_NOTICE(
286  "idx=" << nIndex << ", mods=" << modifiers << ", code=" << keyCode);
287 
288  // Now walk the sparse tree
289  size_t bisect = (KEYMAP_MAX_INDEX + 1) / 2;
290  size_t size = (KEYMAP_MAX_INDEX + 1) / 2;
291  SparseEntry *pSparse = m_pSparseTable;
292  size_t nDataIndex = 0;
293  while (true)
294  {
295  if (nIndex < bisect)
296  {
297  if (!pSparse->left)
298  return 0;
299  if (pSparse->left & SparseEntry::DataFlag)
300  {
301  size_t nOffset = nIndex - (bisect - size);
302  nDataIndex = (pSparse->left & ~SparseEntry::DataFlag) +
303  nOffset * sizeof(KeymapEntry);
304  break;
305  }
306  size /= 2;
307  bisect = bisect - size;
308  pSparse = &m_pSparseTable[pSparse->left / sizeof(SparseEntry)];
309  }
310  else
311  {
312  if (!pSparse->right)
313  return 0;
314  if (pSparse->right & SparseEntry::DataFlag)
315  {
316  size_t nOffset = nIndex - bisect;
317  nDataIndex = (pSparse->right & ~SparseEntry::DataFlag) +
318  nOffset * sizeof(KeymapEntry);
319  break;
320  }
321  size /= 2;
322  bisect = bisect + size;
323  pSparse = &m_pSparseTable[pSparse->right / sizeof(SparseEntry)];
324  }
325  }
326 
327  // Return the found keymap entry
328  return &m_pDataTable[nDataIndex / sizeof(KeymapEntry)];
329 }
330 
331 // These tables originated from qemu
332 // Copyright (c) 2007 OpenMoko, Inc. (andrew@openedhand.com)
333 static const uint8_t pc102ToHidTableNormal[] = {
334  0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
335  0x2d, 0x2e, 0x2a, 0x2b, 0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
336  0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16, 0x07, 0x09, 0x0a, 0x0b,
337  0x0d, 0x0e, 0x0f, 0x33, 0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
338  0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55, 0xe2, 0x2c, 0x39, 0x3a,
339  0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
340  0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59, 0x5a, 0x5b, 0x62, 0x63,
341  0x00, 0x00, 0x64, 0x44, 0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
342  0x00, 0x00, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85,
343  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
344  0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65};
345 
346 static const uint8_t pc102ToHidTableEscape[] = {
347  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
348  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
349  0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
351  0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46, 0xe6, 0x00, 0x00, 0x00,
352  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
353  0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d, 0x51, 0x4e, 0x49, 0x4c,
354  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
358 
360  uint8_t scancode, EscapeState &escape)
361 {
362  // Handle escape scancode 0xE0
363  if (scancode == 0xE0)
364  {
365  escape = EscapeE0;
366  return 0;
367  }
368 
369  // Handle escape scancode 0xE1
370  if (scancode == 0xE1)
371  {
372  escape = EscapeE1;
373  return 0;
374  }
375 
376  // Treat 0xE1 0x1D as 0xE0 (escape scancode)
377  if (scancode == 0x1D && escape == EscapeE1)
378  {
379  escape = EscapeE0;
380  return 0;
381  }
382 
383  if (escape)
384  {
385  escape = EscapeNone;
386  KM_NOTICE(
387  "keymap: using escape table to convert PC102 scancode "
388  << scancode);
389  return pc102ToHidTableEscape[scancode & 0x7F];
390  }
391  else
392  {
393  KM_NOTICE(
394  "keymap: using normal table to convert PC102 scancode "
395  << scancode);
396  return pc102ToHidTableNormal[scancode & 0x7F];
397  }
398 }
virtual ~KeymapManager()
Default destructor.
KeymapManager()
Default constructor.
void useKeymap(uint8_t *pSparseTable, uint8_t *pDataTable)
Changes the current keymap to the given one.
uint64_t resolveHidKeycode(uint8_t keyCode)
bool m_bCapsLock
True if caps lock is on.
static HidInputManager & instance()
Singleton design.
void updateKeys()
Apply modifier or keymap changes to all keys in down state.
uint8_t convertPc102ScancodeToHidKeycode(uint8_t scancode, EscapeState &escape)
Converts a pc102 scancode into a HID keycode.
static KeymapManager m_Instance
Static instance.
bool handleHidModifier(uint8_t keyCode, bool bDown)
uint8_t m_nCombinator
Index of the current active combinator, if any.
Structure representing an entry in the sparse table.
bool m_bHaveLoadedKeymap
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.
SparseEntry * m_pSparseTable
The sparse and data tables for the current keymap.
#define ERROR(text)
Definition: Log.h:82
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.
Structure representing an entry in the keymap table.
Definition: KeymapManager.h:73