Handout
This commit is contained in:
131
kernel/device/keydecoder.cc
Normal file
131
kernel/device/keydecoder.cc
Normal file
@@ -0,0 +1,131 @@
|
||||
#include "keydecoder.h"
|
||||
|
||||
#include "ps2controller.h"
|
||||
|
||||
// Constants used for key decoding
|
||||
constexpr unsigned char BREAK_BIT = 0x80;
|
||||
constexpr unsigned char PREFIX_1 = 0xe0;
|
||||
constexpr unsigned char PREFIX_2 = 0xe1;
|
||||
|
||||
Key KeyDecoder::decode(unsigned char code) {
|
||||
Key key = modifier;
|
||||
|
||||
// All keys that are introduced by the MF II keyboard (compared to the older
|
||||
// AT keyboard) always send a prefix value as first byte.
|
||||
if (code == PREFIX_1 || code == PREFIX_2) {
|
||||
prefix = code;
|
||||
} else {
|
||||
// Releasing a key is, for us, only important for the modifier keys such
|
||||
// as SHIFT, CTRL and ALT, For other, non-modifier keys, we ignore the
|
||||
// break code.
|
||||
bool pressed = (code & BREAK_BIT) == 0;
|
||||
|
||||
// A key's break code is identical to its make code with an additionally
|
||||
// set BREAK_BIT
|
||||
Key::Scancode scancode =
|
||||
static_cast<Key::Scancode>(code & (~BREAK_BIT));
|
||||
|
||||
// We ignore "new" special keys, such as the Windows key
|
||||
if (scancode < Key::Scancode::KEYS) {
|
||||
// save state
|
||||
status[static_cast<size_t>(scancode)] = pressed;
|
||||
|
||||
// Take a closer look at modifier make and break events
|
||||
bool isModifier = true;
|
||||
switch (scancode) {
|
||||
// both shifts are handled equally
|
||||
case Key::Scancode::KEY_LEFT_SHIFT:
|
||||
case Key::Scancode::KEY_RIGHT_SHIFT:
|
||||
modifier.shift = pressed;
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_LEFT_ALT:
|
||||
if (prefix == PREFIX_1) {
|
||||
modifier.alt_right = pressed;
|
||||
} else {
|
||||
modifier.alt_left = pressed;
|
||||
}
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_LEFT_CTRL:
|
||||
if (prefix == PREFIX_1) {
|
||||
modifier.ctrl_right = pressed;
|
||||
} else {
|
||||
modifier.ctrl_left = pressed;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
isModifier = false;
|
||||
}
|
||||
|
||||
// For keys other than modifiers, we only care about the make code
|
||||
if (pressed && !isModifier) {
|
||||
switch (scancode) {
|
||||
case Key::Scancode::KEY_CAPS_LOCK:
|
||||
modifier.caps_lock ^= 1;
|
||||
setLed(PS2Controller::LED_CAPS_LOCK,
|
||||
modifier.caps_lock);
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_SCROLL_LOCK:
|
||||
modifier.scroll_lock ^= 1;
|
||||
setLed(PS2Controller::LED_SCROLL_LOCK,
|
||||
modifier.scroll_lock);
|
||||
break;
|
||||
|
||||
case Key::Scancode::KEY_NUM_LOCK: // Can be both NumLock
|
||||
// and pause
|
||||
// On old keyboards, the pause functionality was only
|
||||
// accessible by pressing Ctrl+NumLock. Modern MF-II
|
||||
// keyboards therefore send exactly this code
|
||||
// combination when the pause key was pressed. Normally,
|
||||
// the pause key does not provide an ASCII code, but we
|
||||
// check that anyway. In either case, we're now done
|
||||
// decoding.
|
||||
if (modifier.ctrl_left) { // pause key
|
||||
key.scancode = scancode;
|
||||
} else { // NumLock
|
||||
modifier.num_lock ^= 1;
|
||||
setLed(PS2Controller::LED_NUM_LOCK,
|
||||
modifier.num_lock);
|
||||
}
|
||||
break;
|
||||
|
||||
// Special case scan code 53: This code is used by both the
|
||||
// minus key on the main keyboard and the division key on
|
||||
// the number block. When the division key was pressed, we
|
||||
// adjust the scancode accordingly.
|
||||
case Key::Scancode::KEY_SLASH:
|
||||
if (prefix == PREFIX_1) {
|
||||
key.scancode = Key::Scancode::KEY_DIV;
|
||||
key.shift = true;
|
||||
} else {
|
||||
key.scancode = scancode;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
key.scancode = scancode;
|
||||
|
||||
// When NumLock is enabled and a key on the keypad was
|
||||
// pressed, we want return the ASCII and scan codes of
|
||||
// the corresponding numerical key instead of the arrow
|
||||
// keys. The keys on the cursor block (prefix ==
|
||||
// PREFIX_1), however, should remain usable. Therefore,
|
||||
// as a little hack, we deactivate the NumLock for these
|
||||
// keys.
|
||||
if (modifier.num_lock && prefix == PREFIX_1) {
|
||||
key.num_lock = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The prefix is only valid for the immediately following code, which
|
||||
// was just handled.
|
||||
prefix = 0;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
Reference in New Issue
Block a user