]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[console] Support changing keyboard map at runtime
authorMichael Brown <mcb30@ipxe.org>
Wed, 16 Feb 2022 00:14:38 +0000 (00:14 +0000)
committerMichael Brown <mcb30@ipxe.org>
Wed, 16 Feb 2022 14:06:33 +0000 (14:06 +0000)
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>
src/core/dynkeymap.c [new file with mode: 0644]
src/core/keymap.c
src/include/ipxe/errfile.h
src/include/ipxe/keymap.h

diff --git a/src/core/dynkeymap.c b/src/core/dynkeymap.c
new file mode 100644 (file)
index 0000000..2f7c499
--- /dev/null
@@ -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 );
index 3fa85f74e3c315d011d128b17252bbc33f1974ee..36db7bd4c45444fcc1da149114e7252e9299c54e 100644 (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;
+}
index 23e406b62cbf51bb610405441c4f41ef6e66cac7..81f555725d6256be5eca50f23483971ad66b7503 100644 (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 )
 
 /** @} */
 
index 392d3ab8fcde2fd2e3ba6afcbea578fd379157b2..8bfbe07a5c4dcdc8d03fddb78ba9bfec3850741f 100644 (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 */