2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2020 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <grub/types.h>
20 #include <grub/misc.h>
25 #include <grub/extcmd.h>
26 #include <grub/i18n.h>
27 #include <grub/term.h>
29 GRUB_MOD_LICENSE ("GPLv3+");
31 #define MAX_KEYMAP 255
40 static struct keymap setkey_keymap
;
44 const char *name
; /* the name in unshifted state */
45 int code
; /* scan code */
48 /* The table for key symbols. (from GRUB4DOS) */
49 static struct keysym keysym_table
[] =
51 {"escape", GRUB_TERM_ESC
}, // ESC
52 {"exclam", 0x21}, // '!'
54 {"numbersign", 0x23}, // '#'
55 {"dollar", 0x24}, // '$'
56 {"percent", 0x25}, // '%'
57 {"caret", 0x5E}, // '^'
58 {"ampersand", 0x26}, // '&'
59 {"asterisk", 0x2A}, // '*'
60 {"parenleft", 0x28}, // '('
61 {"parenright", 0x29}, // ')'
62 {"minus", 0x2D}, // '-'
63 {"underscore", 0x5F}, // '_'
64 {"equal", 0x3D}, // '='
65 {"plus", 0x2B}, // '+'
66 {"backspace", GRUB_TERM_BACKSPACE
}, // BS
67 {"ctrlbackspace", GRUB_TERM_CTRL
| GRUB_TERM_BACKSPACE
}, // (DEL)
68 {"tab", GRUB_TERM_TAB
}, // Tab
69 {"bracketleft", 0x5B}, // '['
70 {"braceleft", 0x7B}, // '{'
71 {"bracketright", 0x5D}, // ']'
72 {"braceright", 0x7D}, // '}'
73 {"enter", 0x0D}, // Enter
74 {"semicolon", 0x3B}, // ';'
75 {"colon", 0x3A}, // ':'
76 {"quote", 0x27}, // '\''
77 {"doublequote", 0x22}, // '"'
78 {"backquote", 0x60}, // '`'
79 {"tilde", 0x7E}, // '~'
80 {"backslash", 0x5C}, // '\\'
82 {"comma", 0x2C}, // ','
83 {"less", 0x3C}, // '<'
84 {"period", 0x2E}, // '.'
85 {"greater", 0x3E}, // '>'
86 {"slash", 0x2F}, // '/'
87 {"question", 0x3F}, // '?'
88 {"space", 0x20}, // Space
89 {"F1", GRUB_TERM_KEY_F1
},
90 {"F2", GRUB_TERM_KEY_F2
},
91 {"F3", GRUB_TERM_KEY_F3
},
92 {"F4", GRUB_TERM_KEY_F4
},
93 {"F5", GRUB_TERM_KEY_F5
},
94 {"F6", GRUB_TERM_KEY_F6
},
95 {"F7", GRUB_TERM_KEY_F7
},
96 {"F8", GRUB_TERM_KEY_F8
},
97 {"F9", GRUB_TERM_KEY_F9
},
98 {"F10", GRUB_TERM_KEY_F10
},
99 {"F11", GRUB_TERM_KEY_F11
},
100 {"F12", GRUB_TERM_KEY_F12
},
101 {"home", GRUB_TERM_KEY_HOME
},
102 {"uparrow", GRUB_TERM_KEY_UP
},
103 {"pageup", GRUB_TERM_KEY_NPAGE
}, // PgUp
104 {"leftarrow", GRUB_TERM_KEY_LEFT
},
105 {"center", GRUB_TERM_KEY_CENTER
}, // keypad center key
106 {"rightarrow", GRUB_TERM_KEY_RIGHT
},
107 {"end", GRUB_TERM_KEY_END
},
108 {"downarrow", GRUB_TERM_KEY_DOWN
},
109 {"pagedown", GRUB_TERM_KEY_PPAGE
}, // PgDn
110 {"insert", GRUB_TERM_KEY_INSERT
}, // Insert
111 {"delete", GRUB_TERM_KEY_DC
}, // Delete
112 {"shiftF1", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F1
},
113 {"shiftF2", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F2
},
114 {"shiftF3", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F3
},
115 {"shiftF4", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F4
},
116 {"shiftF5", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F5
},
117 {"shiftF6", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F6
},
118 {"shiftF7", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F7
},
119 {"shiftF8", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F8
},
120 {"shiftF9", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F9
},
121 {"shiftF10", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F10
},
122 {"shiftF11", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F11
},
123 {"shiftF12", GRUB_TERM_SHIFT
| GRUB_TERM_KEY_F12
},
124 {"ctrlF1", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F1
},
125 {"ctrlF2", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F2
},
126 {"ctrlF3", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F3
},
127 {"ctrlF4", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F4
},
128 {"ctrlF5", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F5
},
129 {"ctrlF6", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F6
},
130 {"ctrlF7", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F7
},
131 {"ctrlF8", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F8
},
132 {"ctrlF9", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F9
},
133 {"ctrlF10", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F10
},
134 {"ctrlF11", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F11
},
135 {"ctrlF12", GRUB_TERM_CTRL
| GRUB_TERM_KEY_F12
},
136 // A=Alt or AltGr. Provided by steve.
137 {"Aq", GRUB_TERM_ALT
| 0x71},
138 {"Aw", GRUB_TERM_ALT
| 0x77},
139 {"Ae", GRUB_TERM_ALT
| 0x65},
140 {"Ar", GRUB_TERM_ALT
| 0x72},
141 {"At", GRUB_TERM_ALT
| 0x74},
142 {"Ay", GRUB_TERM_ALT
| 0x79},
143 {"Au", GRUB_TERM_ALT
| 0x75},
144 {"Ai", GRUB_TERM_ALT
| 0x69},
145 {"Ao", GRUB_TERM_ALT
| 0x6F},
146 {"Ap", GRUB_TERM_ALT
| 0x70},
147 {"Aa", GRUB_TERM_ALT
| 0x61},
148 {"As", GRUB_TERM_ALT
| 0x73},
149 {"Ad", GRUB_TERM_ALT
| 0x64},
150 {"Af", GRUB_TERM_ALT
| 0x66},
151 {"Ag", GRUB_TERM_ALT
| 0x67},
152 {"Ah", GRUB_TERM_ALT
| 0x68},
153 {"Aj", GRUB_TERM_ALT
| 0x6A},
154 {"Ak", GRUB_TERM_ALT
| 0x6B},
155 {"Al", GRUB_TERM_ALT
| 0x6C},
156 {"Az", GRUB_TERM_ALT
| 0x7A},
157 {"Ax", GRUB_TERM_ALT
| 0x78},
158 {"Ac", GRUB_TERM_ALT
| 0x63},
159 {"Av", GRUB_TERM_ALT
| 0x76},
160 {"Ab", GRUB_TERM_ALT
| 0x62},
161 {"An", GRUB_TERM_ALT
| 0x6E},
162 {"Am", GRUB_TERM_ALT
| 0x6D},
163 {"A1", GRUB_TERM_ALT
| 0x31},
164 {"A2", GRUB_TERM_ALT
| 0x32},
165 {"A3", GRUB_TERM_ALT
| 0x33},
166 {"A4", GRUB_TERM_ALT
| 0x34},
167 {"A5", GRUB_TERM_ALT
| 0x35},
168 {"A6", GRUB_TERM_ALT
| 0x36},
169 {"A7", GRUB_TERM_ALT
| 0x37},
170 {"A8", GRUB_TERM_ALT
| 0x38},
171 {"A9", GRUB_TERM_ALT
| 0x39},
172 {"A0", GRUB_TERM_ALT
| 0x30},
174 //{"shiftoem102", 0x7c},
175 {"Aminus", GRUB_TERM_ALT
| 0x2D},
176 {"Aequal", GRUB_TERM_ALT
| 0x3D},
177 {"Abracketleft", GRUB_TERM_ALT
| 0x5B},
178 {"Abracketright", GRUB_TERM_ALT
| 0x5D},
179 {"Asemicolon", GRUB_TERM_ALT
| 0x3B},
180 {"Aquote", GRUB_TERM_ALT
| 0x27},
181 {"Abackquote", GRUB_TERM_ALT
| 0x60},
182 {"Abackslash", GRUB_TERM_ALT
| 0x5C},
183 {"Acomma", GRUB_TERM_ALT
| 0x2C},
184 {"Aperiod", GRUB_TERM_ALT
| 0x2E},
185 {"Aslash", GRUB_TERM_ALT
| 0x2F},
186 {"Acolon", GRUB_TERM_ALT
| 0x3A},
187 {"Aplus", GRUB_TERM_ALT
| 0x2B},
188 {"Aless", GRUB_TERM_ALT
| 0x3C},
189 {"Aunderscore", GRUB_TERM_ALT
| 0x5F},
190 {"Agreater", GRUB_TERM_ALT
| 0x3E},
191 {"Aquestion", GRUB_TERM_ALT
| 0x3F},
192 {"Atilde", GRUB_TERM_ALT
| 0x7E},
193 {"Abraceleft", GRUB_TERM_ALT
| 0x7B},
194 {"Abar", GRUB_TERM_ALT
| 0x7C},
195 {"Abraceright", GRUB_TERM_ALT
| 0x7D},
196 {"Adoublequote", GRUB_TERM_ALT
| 0x22},
199 static int grub_keymap_getkey (int key
)
202 if (key
== GRUB_TERM_NO_KEY
)
204 if (setkey_keymap
.cnt
> MAX_KEYMAP
)
205 setkey_keymap
.cnt
= MAX_KEYMAP
;
206 for (i
= 0; i
< setkey_keymap
.cnt
; i
++)
208 if (key
== setkey_keymap
.in
[i
])
210 key
= setkey_keymap
.out
[i
];
218 grub_keymap_reset (void)
220 grub_memset (&setkey_keymap
, 0, sizeof (struct keymap
));
224 grub_keymap_add (int in
, int out
)
226 if (in
== GRUB_TERM_NO_KEY
|| out
== GRUB_TERM_NO_KEY
)
227 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid key: %d -> %d", in
, out
);
228 if (setkey_keymap
.cnt
>= MAX_KEYMAP
)
229 return grub_error (GRUB_ERR_OUT_OF_MEMORY
,
230 "keymap FULL %d", setkey_keymap
.cnt
);
231 setkey_keymap
.in
[setkey_keymap
.cnt
] = in
;
232 setkey_keymap
.out
[setkey_keymap
.cnt
] = out
;
234 return GRUB_ERR_NONE
;
238 grub_keymap_enable (void)
240 grub_key_remap
= grub_keymap_getkey
;
244 grub_keymap_disable (void)
246 grub_key_remap
= NULL
;
250 grub_keymap_status (void)
253 if (setkey_keymap
.cnt
> MAX_KEYMAP
)
254 setkey_keymap
.cnt
= MAX_KEYMAP
;
255 for (i
= 0; i
< setkey_keymap
.cnt
; i
++)
257 grub_printf ("0x%x -> 0x%x\n", setkey_keymap
.in
[i
], setkey_keymap
.out
[i
]);
261 static const struct grub_arg_option options
[] =
263 {"reset", 'r', 0, N_("Reset keymap."), 0, 0},
264 {"enable", 'e', 0, N_("Enable keymap."), 0, 0},
265 {"disable", 'd', 0, N_("Disable keymap."), 0, 0},
266 {"status", 's', 0, N_("Display keymap."), 0, 0},
279 ishex (const char *str
)
281 if (grub_strlen (str
) < 3 || str
[0] != '0')
283 if (str
[1] != 'x' && str
[1] != 'X')
289 parse_key (const char *str
)
293 return grub_strtol (str
, NULL
, 16);
294 if (grub_strlen (str
) == 1)
296 for (i
= 0; i
< (int) (sizeof (keysym_table
) / sizeof (keysym_table
[0])); i
++)
298 if (grub_strcmp (str
, keysym_table
[i
].name
) == 0)
299 return keysym_table
[i
].code
;
301 grub_error (GRUB_ERR_BAD_ARGUMENT
, "invalid key %s", str
);
306 grub_cmd_setkey (grub_extcmd_context_t ctxt
, int argc
, char **args
)
308 struct grub_arg_list
*state
= ctxt
->state
;
310 if (state
[SETKEY_ENABLE
].set
)
312 grub_keymap_enable ();
315 if (state
[SETKEY_DISABLE
].set
)
317 grub_keymap_disable ();
320 if (state
[SETKEY_RESET
].set
)
322 grub_keymap_reset ();
325 if (state
[SETKEY_STATUS
].set
)
327 grub_keymap_status ();
333 ("Key names: 0-9, A-Z, a-z or escape, exclam, at, numbersign, dollar,"
334 "percent, caret, ampersand, asterisk, parenleft, parenright, minus,"
335 "underscore, equal, plus, backspace, tab, bracketleft, braceleft,"
336 "bracketright, braceright, enter, semicolon, colon, quote, doublequote,"
337 "backquote, tilde, backslash, bar, comma, less, period, greater,"
338 "slash, question, alt, space, delete, [ctrl|shift]F1-12."
339 "For Alt+ prefix with A, e.g. \'setkey at Aequal\'.");
342 in
= parse_key (args
[1]);
343 out
= parse_key (args
[0]);
346 grub_keymap_add (in
, out
);
351 static void grub_keymap_add_by_string(const char *src
, const char *dst
)
357 out
= parse_key(src
);
361 grub_keymap_add (in
, out
);
365 #include "keyboard_layout.c"
367 static grub_err_t
grub_cmd_set_keylayout (grub_extcmd_context_t ctxt
, int argc
, char **args
)
371 ventoy_set_keyboard_layout(args
[0]);
375 static grub_extcmd_t cmd
, setcmd
;
377 GRUB_MOD_INIT(setkey
)
379 cmd
= grub_register_extcmd ("setkey", grub_cmd_setkey
, 0, N_("NEW_KEY USA_KEY"),
380 N_("Map default USA_KEY to NEW_KEY."), options
);
381 setcmd
= grub_register_extcmd ("set_keyboard_layout", grub_cmd_set_keylayout
, 0, N_("layout"),
382 N_("Set keyboard layout."), NULL
);
385 GRUB_MOD_FINI(setkey
)
387 grub_unregister_extcmd (cmd
);