[console] Support changing keyboard map at runtime

Provide the special keyboard map named "dynamic" which allows the
active keyboard map to be selected at runtime via the ${keymap}
setting, e.g.:

  #define KEYBOARD_MAP dynamic

  iPXE> set keymap uk

Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/594/head
Michael Brown 2022-02-16 00:14:38 +00:00
parent 674963e2a6
commit 304333dace
4 changed files with 174 additions and 2 deletions

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2022 Michael Brown <mbrown@fensystems.co.uk>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
* You can also choose to distribute this program under the terms of
* the Unmodified Binary Distribution Licence (as given in the file
* COPYING.UBDL), provided that you have satisfied its requirements.
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** @file
*
* Dynamic keyboard mappings
*
*/
#include <stdlib.h>
#include <errno.h>
#include <ipxe/settings.h>
#include <ipxe/keymap.h>
/**
* Require a keyboard map
*
* @v name Keyboard map name
*/
#define REQUIRE_KEYMAP( name ) REQUIRE_OBJECT ( keymap_ ## name )
/** Keyboard map setting */
const struct setting keymap_setting __setting ( SETTING_MISC, keymap ) = {
.name = "keymap",
.description = "Keyboard map",
.type = &setting_type_string,
};
/**
* Apply keyboard map settings
*
* @ret rc Return status code
*/
static int keymap_apply ( void ) {
struct keymap *keymap;
char *name;
int rc;
/* Fetch keyboard map name */
fetch_string_setting_copy ( NULL, &keymap_setting, &name );
/* Identify keyboard map */
if ( name ) {
/* Identify named keyboard map */
keymap = keymap_find ( name );
if ( ! keymap ) {
DBGC ( &keymap_setting, "KEYMAP could not identify "
"\"%s\"\n", name );
rc = -ENOENT;
goto err_unknown;
}
} else {
/* Use default keyboard map */
keymap = NULL;
}
/* Set keyboard map */
keymap_set ( keymap );
/* Success */
rc = 0;
err_unknown:
free ( name );
return rc;
}
/** Keyboard map setting applicator */
struct settings_applicator keymap_applicator __settings_applicator = {
.apply = keymap_apply,
};
/* Provide virtual "dynamic" keyboard map for linker */
PROVIDE_SYMBOL ( obj_keymap_dynamic );
/* Drag in keyboard maps via keymap_setting */
REQUIRING_SYMBOL ( keymap_setting );
/* Require all known keyboard maps */
REQUIRE_KEYMAP ( al );
REQUIRE_KEYMAP ( by );
REQUIRE_KEYMAP ( cf );
REQUIRE_KEYMAP ( cz );
REQUIRE_KEYMAP ( de );
REQUIRE_KEYMAP ( dk );
REQUIRE_KEYMAP ( es );
REQUIRE_KEYMAP ( et );
REQUIRE_KEYMAP ( fi );
REQUIRE_KEYMAP ( fr );
REQUIRE_KEYMAP ( gr );
REQUIRE_KEYMAP ( hu );
REQUIRE_KEYMAP ( il );
REQUIRE_KEYMAP ( it );
REQUIRE_KEYMAP ( lt );
REQUIRE_KEYMAP ( mk );
REQUIRE_KEYMAP ( mt );
REQUIRE_KEYMAP ( nl );
REQUIRE_KEYMAP ( no );
REQUIRE_KEYMAP ( no_latin1 );
REQUIRE_KEYMAP ( pl );
REQUIRE_KEYMAP ( pt );
REQUIRE_KEYMAP ( ro );
REQUIRE_KEYMAP ( ru );
REQUIRE_KEYMAP ( se );
REQUIRE_KEYMAP ( sg );
REQUIRE_KEYMAP ( sr_latin );
REQUIRE_KEYMAP ( ua );
REQUIRE_KEYMAP ( uk );
REQUIRE_KEYMAP ( us );

View File

@ -23,6 +23,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ctype.h>
#include <ipxe/keys.h>
#include <ipxe/keymap.h>
@ -49,7 +50,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static TABLE_START ( keymap_start, KEYMAP );
/** Current keyboard mapping */
static struct keymap *keymap = keymap_start;
static struct keymap *keymap_current = keymap_start;
/**
* Remap a key
@ -58,6 +59,7 @@ static struct keymap *keymap = keymap_start;
* @ret mapped Mapped character
*/
unsigned int key_remap ( unsigned int character ) {
struct keymap *keymap = keymap_current;
unsigned int mapped = ( character & KEYMAP_MASK );
struct keymap_key *key;
@ -88,6 +90,42 @@ unsigned int key_remap ( unsigned int character ) {
/* Clear flags */
mapped &= ASCII_MASK;
DBGC2 ( &keymap, "KEYMAP mapped %04x => %02x\n", character, mapped );
DBGC2 ( &keymap_current, "KEYMAP mapped %04x => %02x\n",
character, mapped );
return mapped;
}
/**
* Find keyboard map by name
*
* @v name Keyboard map name
* @ret keymap Keyboard map, or NULL if not found
*/
struct keymap * keymap_find ( const char *name ) {
struct keymap *keymap;
/* Find matching keyboard map */
for_each_table_entry ( keymap, KEYMAP ) {
if ( strcmp ( keymap->name, name ) == 0 )
return keymap;
}
return NULL;
}
/**
* Set keyboard map
*
* @v keymap Keyboard map, or NULL to use default
*/
void keymap_set ( struct keymap *keymap ) {
/* Use default keymap if none specified */
if ( ! keymap )
keymap = keymap_start;
/* Set new keyboard map */
if ( keymap != keymap_current )
DBGC ( &keymap_current, "KEYMAP using \"%s\"\n", keymap->name );
keymap_current = keymap;
}

View File

@ -395,6 +395,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ERRFILE_efi_cachedhcp ( ERRFILE_OTHER | 0x00550000 )
#define ERRFILE_linux_sysfs ( ERRFILE_OTHER | 0x00560000 )
#define ERRFILE_linux_acpi ( ERRFILE_OTHER | 0x00570000 )
#define ERRFILE_dynkeymap ( ERRFILE_OTHER | 0x00580000 )
/** @} */

View File

@ -73,5 +73,7 @@ struct keymap {
#define KEYMAP_ALTGR 0x0800
extern unsigned int key_remap ( unsigned int character );
extern struct keymap * keymap_find ( const char *name );
extern void keymap_set ( struct keymap *keymap );
#endif /* _IPXE_KEYMAP_H */