mirror of https://github.com/ipxe/ipxe.git
[console] Centralise handling of key modifiers
Handle Ctrl and CapsLock key modifiers within key_remap(), to provide consistent behaviour across different console types. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/591/head
parent
871dd236d4
commit
f2a59d5973
|
@ -6,6 +6,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
#define BDA_SEG 0x0040
|
#define BDA_SEG 0x0040
|
||||||
#define BDA_EBDA 0x000e
|
#define BDA_EBDA 0x000e
|
||||||
#define BDA_EQUIPMENT_WORD 0x0010
|
#define BDA_EQUIPMENT_WORD 0x0010
|
||||||
|
#define BDA_KB0 0x0017
|
||||||
|
#define BDA_KB0_CTRL 0x04
|
||||||
|
#define BDA_KB0_CAPSLOCK 0x040
|
||||||
#define BDA_FBMS 0x0013
|
#define BDA_FBMS 0x0013
|
||||||
#define BDA_TICKS 0x006c
|
#define BDA_TICKS 0x006c
|
||||||
#define BDA_MIDNIGHT 0x0070
|
#define BDA_MIDNIGHT 0x0070
|
||||||
|
|
|
@ -361,6 +361,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
|
||||||
*/
|
*/
|
||||||
static int bios_getchar ( void ) {
|
static int bios_getchar ( void ) {
|
||||||
uint16_t keypress;
|
uint16_t keypress;
|
||||||
|
uint8_t kb0;
|
||||||
unsigned int scancode;
|
unsigned int scancode;
|
||||||
unsigned int character;
|
unsigned int character;
|
||||||
const char *ansi_seq;
|
const char *ansi_seq;
|
||||||
|
@ -385,16 +386,28 @@ static int bios_getchar ( void ) {
|
||||||
bios_inject_lock--;
|
bios_inject_lock--;
|
||||||
scancode = ( keypress >> 8 );
|
scancode = ( keypress >> 8 );
|
||||||
character = ( keypress & 0xff );
|
character = ( keypress & 0xff );
|
||||||
|
get_real ( kb0, BDA_SEG, BDA_KB0 );
|
||||||
|
|
||||||
/* If it's a normal character, map (if applicable) and return it */
|
/* If it's a normal character, map (if applicable) and return it */
|
||||||
if ( character && ( character < 0x80 ) ) {
|
if ( character && ( character < 0x80 ) ) {
|
||||||
if ( scancode < SCANCODE_RSHIFT ) {
|
|
||||||
return key_remap ( character );
|
/* Handle special scancodes */
|
||||||
} else if ( scancode == SCANCODE_NON_US ) {
|
if ( scancode == SCANCODE_NON_US ) {
|
||||||
return key_remap ( character | KEYMAP_PSEUDO );
|
/* Treat as "\|" with high bit set */
|
||||||
} else {
|
character |= KEYMAP_PSEUDO;
|
||||||
|
} else if ( scancode >= SCANCODE_RSHIFT ) {
|
||||||
|
/* Non-remappable scancode (e.g. numeric keypad) */
|
||||||
return character;
|
return character;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apply modifiers */
|
||||||
|
if ( kb0 & BDA_KB0_CTRL )
|
||||||
|
character |= KEYMAP_CTRL;
|
||||||
|
if ( kb0 & BDA_KB0_CAPSLOCK )
|
||||||
|
character |= KEYMAP_CAPSLOCK_REDO;
|
||||||
|
|
||||||
|
/* Map and return */
|
||||||
|
return key_remap ( character );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise, check for a special key that we know about */
|
/* Otherwise, check for a special key that we know about */
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <ipxe/keys.h>
|
||||||
#include <ipxe/keymap.h>
|
#include <ipxe/keymap.h>
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
|
@ -31,6 +33,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** ASCII character mask */
|
||||||
|
#define ASCII_MASK 0x7f
|
||||||
|
|
||||||
|
/** Control character mask */
|
||||||
|
#define CTRL_MASK 0x1f
|
||||||
|
|
||||||
|
/** Upper case character mask */
|
||||||
|
#define UPPER_MASK 0x5f
|
||||||
|
|
||||||
|
/** Case toggle bit */
|
||||||
|
#define CASE_TOGGLE ( ASCII_MASK & ~UPPER_MASK )
|
||||||
|
|
||||||
/** Default keyboard mapping */
|
/** Default keyboard mapping */
|
||||||
static TABLE_START ( keymap_start, KEYMAP );
|
static TABLE_START ( keymap_start, KEYMAP );
|
||||||
|
|
||||||
|
@ -41,21 +55,36 @@ static struct keymap *keymap = keymap_start;
|
||||||
* Remap a key
|
* Remap a key
|
||||||
*
|
*
|
||||||
* @v character Character read from console
|
* @v character Character read from console
|
||||||
* @ret character Mapped character
|
* @ret mapped Mapped character
|
||||||
*/
|
*/
|
||||||
unsigned int key_remap ( unsigned int character ) {
|
unsigned int key_remap ( unsigned int character ) {
|
||||||
|
unsigned int mapped = ( character & KEYMAP_MASK );
|
||||||
struct keymap_key *key;
|
struct keymap_key *key;
|
||||||
|
|
||||||
|
/* Invert case before remapping if applicable */
|
||||||
|
if ( ( character & KEYMAP_CAPSLOCK_UNDO ) && isalpha ( mapped ) )
|
||||||
|
mapped ^= CASE_TOGGLE;
|
||||||
|
|
||||||
/* Remap via table */
|
/* Remap via table */
|
||||||
for ( key = keymap->basic ; key->from ; key++ ) {
|
for ( key = keymap->basic ; key->from ; key++ ) {
|
||||||
if ( key->from == character ) {
|
if ( mapped == key->from ) {
|
||||||
character = key->to;
|
mapped = key->to;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear pseudo key flag */
|
/* Handle Ctrl-<key> and CapsLock */
|
||||||
character &= ~KEYMAP_PSEUDO;
|
if ( isalpha ( mapped ) ) {
|
||||||
|
if ( character & KEYMAP_CTRL ) {
|
||||||
|
mapped &= CTRL_MASK;
|
||||||
|
} else if ( character & KEYMAP_CAPSLOCK ) {
|
||||||
|
mapped ^= CASE_TOGGLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return character;
|
/* Clear flags */
|
||||||
|
mapped &= ASCII_MASK;
|
||||||
|
|
||||||
|
DBGC2 ( &keymap, "KEYMAP mapped %04x => %02x\n", character, mapped );
|
||||||
|
return mapped;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,9 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers,
|
||||||
} else if ( keycode <= USBKBD_KEY_Z ) {
|
} else if ( keycode <= USBKBD_KEY_Z ) {
|
||||||
/* Alphabetic keys */
|
/* Alphabetic keys */
|
||||||
key = ( keycode - USBKBD_KEY_A + 'a' );
|
key = ( keycode - USBKBD_KEY_A + 'a' );
|
||||||
|
if ( modifiers & USBKBD_SHIFT ) {
|
||||||
|
key -= ( 'a' - 'A' );
|
||||||
|
}
|
||||||
} else if ( keycode <= USBKBD_KEY_0 ) {
|
} else if ( keycode <= USBKBD_KEY_0 ) {
|
||||||
/* Numeric key row */
|
/* Numeric key row */
|
||||||
if ( modifiers & USBKBD_SHIFT ) {
|
if ( modifiers & USBKBD_SHIFT ) {
|
||||||
|
@ -125,17 +128,15 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers,
|
||||||
/* Remap key if applicable */
|
/* Remap key if applicable */
|
||||||
if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) ||
|
if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) ||
|
||||||
( keycode == USBKBD_KEY_NON_US ) ) {
|
( keycode == USBKBD_KEY_NON_US ) ) {
|
||||||
key = key_remap ( key );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle upper/lower case and Ctrl-<key> */
|
/* Apply modifiers */
|
||||||
if ( islower ( key ) ) {
|
if ( modifiers & USBKBD_CTRL )
|
||||||
if ( modifiers & USBKBD_CTRL ) {
|
key |= KEYMAP_CTRL;
|
||||||
key -= ( 'a' - CTRL_A );
|
if ( leds & USBKBD_LED_CAPS_LOCK )
|
||||||
} else if ( ( modifiers & USBKBD_SHIFT ) ||
|
key |= KEYMAP_CAPSLOCK;
|
||||||
( leds & USBKBD_LED_CAPS_LOCK ) ) {
|
|
||||||
key -= ( 'a' - 'A' );
|
/* Remap key */
|
||||||
}
|
key = key_remap ( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
|
|
|
@ -40,9 +40,30 @@ struct keymap {
|
||||||
/** Define a keyboard mapping */
|
/** Define a keyboard mapping */
|
||||||
#define __keymap __table_entry ( KEYMAP, 01 )
|
#define __keymap __table_entry ( KEYMAP, 01 )
|
||||||
|
|
||||||
|
/** Mappable character mask */
|
||||||
|
#define KEYMAP_MASK 0xff
|
||||||
|
|
||||||
/** Pseudo key flag */
|
/** Pseudo key flag */
|
||||||
#define KEYMAP_PSEUDO 0x80
|
#define KEYMAP_PSEUDO 0x80
|
||||||
|
|
||||||
|
/** Ctrl key flag */
|
||||||
|
#define KEYMAP_CTRL 0x0100
|
||||||
|
|
||||||
|
/** CapsLock key flag */
|
||||||
|
#define KEYMAP_CAPSLOCK 0x0200
|
||||||
|
|
||||||
|
/** Undo CapsLock key flag
|
||||||
|
*
|
||||||
|
* Used when the keyboard driver has already interpreted the CapsLock
|
||||||
|
* key, in which case the effect needs to be undone before remapping
|
||||||
|
* in order to correctly handle keyboard mappings that swap alphabetic
|
||||||
|
* and non-alphabetic keys.
|
||||||
|
*/
|
||||||
|
#define KEYMAP_CAPSLOCK_UNDO 0x0400
|
||||||
|
|
||||||
|
/** Undo and redo CapsLock key flags */
|
||||||
|
#define KEYMAP_CAPSLOCK_REDO ( KEYMAP_CAPSLOCK | KEYMAP_CAPSLOCK_UNDO )
|
||||||
|
|
||||||
extern unsigned int key_remap ( unsigned int character );
|
extern unsigned int key_remap ( unsigned int character );
|
||||||
|
|
||||||
#endif /* _IPXE_KEYMAP_H */
|
#endif /* _IPXE_KEYMAP_H */
|
||||||
|
|
|
@ -55,8 +55,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
|
|
||||||
#define ATTR_DEFAULT ATTR_FCOL_WHITE
|
#define ATTR_DEFAULT ATTR_FCOL_WHITE
|
||||||
|
|
||||||
#define CTRL_MASK 0x1f
|
|
||||||
|
|
||||||
/* Set default console usage if applicable */
|
/* Set default console usage if applicable */
|
||||||
#if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) )
|
#if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) )
|
||||||
#undef CONSOLE_EFI
|
#undef CONSOLE_EFI
|
||||||
|
@ -286,6 +284,9 @@ static int efi_getchar ( void ) {
|
||||||
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
|
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
|
||||||
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conin_ex = efi_conin_ex;
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conin_ex = efi_conin_ex;
|
||||||
const char *ansi_seq;
|
const char *ansi_seq;
|
||||||
|
unsigned int character;
|
||||||
|
unsigned int shift;
|
||||||
|
unsigned int toggle;
|
||||||
EFI_KEY_DATA key;
|
EFI_KEY_DATA key;
|
||||||
EFI_STATUS efirc;
|
EFI_STATUS efirc;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -318,24 +319,35 @@ static int efi_getchar ( void ) {
|
||||||
key.KeyState.KeyToggleState, key.Key.UnicodeChar,
|
key.KeyState.KeyToggleState, key.Key.UnicodeChar,
|
||||||
key.Key.ScanCode );
|
key.Key.ScanCode );
|
||||||
|
|
||||||
/* Remap key. There is unfortunately no way to avoid
|
/* If key has a Unicode representation, remap and return it.
|
||||||
* remapping the numeric keypad, since EFI destroys the scan
|
* There is unfortunately no way to avoid remapping the
|
||||||
* code information that would allow us to differentiate
|
* numeric keypad, since EFI destroys the scan code
|
||||||
* between main keyboard and numeric keypad.
|
* information that would allow us to differentiate between
|
||||||
|
* main keyboard and numeric keypad.
|
||||||
*/
|
*/
|
||||||
key.Key.UnicodeChar = key_remap ( key.Key.UnicodeChar );
|
if ( ( character = key.Key.UnicodeChar ) != 0 ) {
|
||||||
|
|
||||||
/* Translate Ctrl-<key> */
|
/* Apply shift state */
|
||||||
if ( ( key.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID ) &&
|
shift = key.KeyState.KeyShiftState;
|
||||||
( key.KeyState.KeyShiftState & ( EFI_LEFT_CONTROL_PRESSED |
|
if ( shift & EFI_SHIFT_STATE_VALID ) {
|
||||||
EFI_RIGHT_CONTROL_PRESSED ) ) ) {
|
if ( shift & ( EFI_LEFT_CONTROL_PRESSED |
|
||||||
key.Key.UnicodeChar &= CTRL_MASK;
|
EFI_RIGHT_CONTROL_PRESSED ) ) {
|
||||||
|
character |= KEYMAP_CTRL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Apply toggle state */
|
||||||
|
toggle = key.KeyState.KeyToggleState;
|
||||||
|
if ( toggle & EFI_TOGGLE_STATE_VALID ) {
|
||||||
|
if ( toggle & EFI_CAPS_LOCK_ACTIVE ) {
|
||||||
|
character |= KEYMAP_CAPSLOCK_REDO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remap and return key */
|
||||||
|
return key_remap ( character );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If key has a Unicode representation, return it */
|
|
||||||
if ( key.Key.UnicodeChar )
|
|
||||||
return key.Key.UnicodeChar;
|
|
||||||
|
|
||||||
/* Otherwise, check for a special key that we know about */
|
/* Otherwise, check for a special key that we know about */
|
||||||
if ( ( ansi_seq = scancode_to_ansi_seq ( key.Key.ScanCode ) ) ) {
|
if ( ( ansi_seq = scancode_to_ansi_seq ( key.Key.ScanCode ) ) ) {
|
||||||
/* Start of escape sequence: return ESC (0x1b) */
|
/* Start of escape sequence: return ESC (0x1b) */
|
||||||
|
|
Loading…
Reference in New Issue