From c4ca7e6b38a50ba9a4c2b475066e48453d4e2092 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Wed, 29 Jul 2026 14:29:29 +0200 Subject: [PATCH] drivers/input: partial fix of indistinguishable ASCII and special keycodes As analyzed, the NuttX initial keyboard API design uses event type KBD_SPECPRESS/KBD_SPECREL to deliver special keys and KBD_PRESS/KBD_RELEASE to deliver ASCII codes. But it seems that this design choice has not been followed in virtio-input, goldfish_events and sim_keyboard designs and result is that external keyboard special keys events are mapped to KEYCODE_xxx values which start from 0 and overlaps with ASCII keys. The issue is tracked under #19527 number. This set of changes correct events reporting for mentioned keyboards to report right event type for special keys. The solution is only partial at this phase. Virtual and more complex keyboards usually deliver key pressures as scancodes (key position on keyboard) and mapping to ASCII for keys which corresponds to letter and other similar keys lacks mapping of national alphabets, second row symbols and switch to capital letter according to modifiers. Signed-off-by: Pavel Pisa --- arch/sim/src/sim/sim_keyboard.c | 16 +- drivers/input/CMakeLists.txt | 1 + drivers/input/Make.defs | 1 + drivers/input/goldfish_events.c | 17 +- drivers/input/keyboard_upper.c | 92 ---------- drivers/input/virtio_key_decode.c | 281 ++++++++++++++++++++++++++++++ drivers/virtio/virtio-input.c | 18 +- include/nuttx/input/keyboard.h | 4 +- 8 files changed, 328 insertions(+), 102 deletions(-) create mode 100644 drivers/input/virtio_key_decode.c diff --git a/arch/sim/src/sim/sim_keyboard.c b/arch/sim/src/sim/sim_keyboard.c index d08556ae8e022..ec3c075d8f614 100644 --- a/arch/sim/src/sim/sim_keyboard.c +++ b/arch/sim/src/sim/sim_keyboard.c @@ -204,7 +204,7 @@ static uint32_t translate_x11_key(uint32_t code) return KEYCODE_F24; default: - return code; + return KEYCODE_NORMAL; } } @@ -246,10 +246,16 @@ int sim_kbd_initialize(void) void sim_kbdevent(uint32_t key, bool is_press) { uint32_t trans_key; + bool is_special; struct sim_dev_s *priv = (struct sim_dev_s *) &g_simkeyboard; - uint32_t types[2] = + static const uint32_t types[2][2] = { - KEYBOARD_RELEASE, KEYBOARD_PRESS + { + KEYBOARD_RELEASE, KEYBOARD_PRESS + }, + { + KBD_SPECREL, KBD_SPECPRESS + } }; if (priv->eventloop == 0) @@ -258,9 +264,11 @@ void sim_kbdevent(uint32_t key, bool is_press) } trans_key = translate_x11_key(key); + is_special = trans_key != KEYCODE_NORMAL; + trans_key = is_special ? trans_key : key; iinfo("key=%04x\n", key); /* Report data changes */ - keyboard_event(&priv->lower, trans_key, types[is_press]); + keyboard_event(&priv->lower, trans_key, types[is_special][is_press]); } diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index 236da9ca944cd..4527d2c953019 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -104,6 +104,7 @@ if(CONFIG_INPUT) if(CONFIG_INPUT_KEYBOARD) list(APPEND SRCS keyboard_upper.c) + list(APPEND SRCS virtio_key_decode.c) endif() if(CONFIG_INPUT_KMATRIX) diff --git a/drivers/input/Make.defs b/drivers/input/Make.defs index 1c3d7432b019e..e5408655a97fe 100644 --- a/drivers/input/Make.defs +++ b/drivers/input/Make.defs @@ -104,6 +104,7 @@ endif ifeq ($(CONFIG_INPUT_KEYBOARD),y) CSRCS += keyboard_upper.c + CSRCS += virtio_key_decode.c endif ifeq ($(CONFIG_INPUT_DJOYSTICK),y) diff --git a/drivers/input/goldfish_events.c b/drivers/input/goldfish_events.c index 6e371d53641da..e6486cc3263ed 100644 --- a/drivers/input/goldfish_events.c +++ b/drivers/input/goldfish_events.c @@ -108,11 +108,24 @@ static bool goldfish_events_send_keyboard_event(FAR struct goldfish_events_s *events, FAR struct goldfish_input_event *evt) { + uint32_t trans_key; + bool is_special; + static const uint32_t types[2][2] = + { + { + KEYBOARD_RELEASE, KEYBOARD_PRESS + }, + { + KBD_SPECREL, KBD_SPECPRESS + } + }; + if (evt->type == EV_KEY) { + trans_key = keyboard_translate_virtio_code(evt->code, &is_special); keyboard_event(&(events->keyboardlower), - keyboard_translate_virtio_code(evt->code), - !evt->value); + trans_key, + types[is_special][evt->value & 1]); return true; } diff --git a/drivers/input/keyboard_upper.c b/drivers/input/keyboard_upper.c index 5436a270e5210..994190e57d117 100644 --- a/drivers/input/keyboard_upper.c +++ b/drivers/input/keyboard_upper.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -423,94 +422,3 @@ void keyboard_event(FAR struct keyboard_lowerhalf_s *lower, uint32_t keycode, nxmutex_unlock(&upper->lock); } - -/**************************************************************************** - * keyboard_translate_virtio_code - ****************************************************************************/ - -uint32_t keyboard_translate_virtio_code(uint16_t keycode) -{ - switch (keycode) - { - case KEY_DELETE: - return KEYCODE_FWDDEL; - case KEY_BACKSPACE: - return KEYCODE_BACKDEL; - case KEY_HOME: - return KEYCODE_HOME; - case KEY_END: - return KEYCODE_END; - case KEY_LEFT: - return KEYCODE_LEFT; - case KEY_RIGHT: - return KEYCODE_RIGHT; - case KEY_UP: - return KEYCODE_UP; - case KEY_DOWN: - return KEYCODE_DOWN; - case KEY_PAGEUP: - return KEYCODE_PAGEUP; - case KEY_PAGEDOWN: - return KEYCODE_PAGEDOWN; - case KEY_ENTER: - return KEYCODE_ENTER; - case KEY_CAPSLOCK: - return KEYCODE_CAPSLOCK; - case KEY_SCROLLLOCK: - return KEYCODE_SCROLLLOCK; - case KEY_NUMLOCK: - return KEYCODE_NUMLOCK; - case KEY_SYSRQ: - return KEYCODE_PRTSCRN; - case KEY_F1: - return KEYCODE_F1; - case KEY_F2: - return KEYCODE_F2; - case KEY_F3: - return KEYCODE_F3; - case KEY_F4: - return KEYCODE_F4; - case KEY_F5: - return KEYCODE_F5; - case KEY_F6: - return KEYCODE_F6; - case KEY_F7: - return KEYCODE_F7; - case KEY_F8: - return KEYCODE_F8; - case KEY_F9: - return KEYCODE_F9; - case KEY_F10: - return KEYCODE_F10; - case KEY_F11: - return KEYCODE_F11; - case KEY_F12: - return KEYCODE_F12; - case KEY_F13: - return KEYCODE_F13; - case KEY_F14: - return KEYCODE_F14; - case KEY_F15: - return KEYCODE_F15; - case KEY_F16: - return KEYCODE_F16; - case KEY_F17: - return KEYCODE_F17; - case KEY_F18: - return KEYCODE_F18; - case KEY_F19: - return KEYCODE_F19; - case KEY_F20: - return KEYCODE_F20; - case KEY_F21: - return KEYCODE_F21; - case KEY_F22: - return KEYCODE_F22; - case KEY_F23: - return KEYCODE_F23; - case KEY_F24: - return KEYCODE_F24; - default: - return keycode; - } -} diff --git a/drivers/input/virtio_key_decode.c b/drivers/input/virtio_key_decode.c new file mode 100644 index 0000000000000..7db6879c5f2a3 --- /dev/null +++ b/drivers/input/virtio_key_decode.c @@ -0,0 +1,281 @@ +/**************************************************************************** + * drivers/input/virtio_key_decode.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * keyboard_translate_virtio_code + ****************************************************************************/ + +uint32_t keyboard_translate_virtio_code(uint16_t keycode, bool *special) +{ + *special = true; + switch (keycode) + { + case KEY_DELETE: + return KEYCODE_FWDDEL; + case KEY_BACKSPACE: + return KEYCODE_BACKDEL; + case KEY_HOME: + return KEYCODE_HOME; + case KEY_END: + return KEYCODE_END; + case KEY_LEFT: + return KEYCODE_LEFT; + case KEY_RIGHT: + return KEYCODE_RIGHT; + case KEY_UP: + return KEYCODE_UP; + case KEY_DOWN: + return KEYCODE_DOWN; + case KEY_PAGEUP: + return KEYCODE_PAGEUP; + case KEY_PAGEDOWN: + return KEYCODE_PAGEDOWN; + case KEY_ENTER: + return KEYCODE_ENTER; + case KEY_CAPSLOCK: + return KEYCODE_CAPSLOCK; + case KEY_SCROLLLOCK: + return KEYCODE_SCROLLLOCK; + case KEY_NUMLOCK: + return KEYCODE_NUMLOCK; + case KEY_SYSRQ: + return KEYCODE_PRTSCRN; + case KEY_F1: + return KEYCODE_F1; + case KEY_F2: + return KEYCODE_F2; + case KEY_F3: + return KEYCODE_F3; + case KEY_F4: + return KEYCODE_F4; + case KEY_F5: + return KEYCODE_F5; + case KEY_F6: + return KEYCODE_F6; + case KEY_F7: + return KEYCODE_F7; + case KEY_F8: + return KEYCODE_F8; + case KEY_F9: + return KEYCODE_F9; + case KEY_F10: + return KEYCODE_F10; + case KEY_F11: + return KEYCODE_F11; + case KEY_F12: + return KEYCODE_F12; + case KEY_F13: + return KEYCODE_F13; + case KEY_F14: + return KEYCODE_F14; + case KEY_F15: + return KEYCODE_F15; + case KEY_F16: + return KEYCODE_F16; + case KEY_F17: + return KEYCODE_F17; + case KEY_F18: + return KEYCODE_F18; + case KEY_F19: + return KEYCODE_F19; + case KEY_F20: + return KEYCODE_F20; + case KEY_F21: + return KEYCODE_F21; + case KEY_F22: + return KEYCODE_F22; + case KEY_F23: + return KEYCODE_F23; + case KEY_F24: + return KEYCODE_F24; + default: + } + + *special = false; + switch (keycode) + { + case KEY_ESC: + return '\e'; + case KEY_1: + return '1'; + case KEY_2: + return '2'; + case KEY_3: + return '3'; + case KEY_4: + return '4'; + case KEY_5: + return '5'; + case KEY_6: + return '6'; + case KEY_7: + return '7'; + case KEY_8: + return '8'; + case KEY_9: + return '9'; + case KEY_0: + return '0'; + case KEY_MINUS: + return '-'; + case KEY_EQUAL: + return '='; + case KEY_TAB: + return '\t'; + case KEY_Q: + return 'q'; + case KEY_W: + return 'w'; + case KEY_E: + return 'e'; + case KEY_R: + return 'r'; + case KEY_T: + return 't'; + case KEY_Y: + return 'y'; + case KEY_U: + return 'u'; + case KEY_I: + return 'i'; + case KEY_O: + return 'o'; + case KEY_P: + return 'p'; + case KEY_LEFTBRACE: + return '('; + case KEY_RIGHTBRACE: + return ')'; + case KEY_A: + return 'a'; + case KEY_S: + return 's'; + case KEY_D: + return 'd'; + case KEY_F: + return 'f'; + case KEY_G: + return 'g'; + case KEY_H: + return 'h'; + case KEY_J: + return 'j'; + case KEY_K: + return 'k'; + case KEY_L: + return 'l'; + case KEY_SEMICOLON: + return ';'; + case KEY_APOSTROPHE: + return '\''; + case KEY_BACKSLASH: + return '\\'; + case KEY_Z: + return 'z'; + case KEY_X: + return 'x'; + case KEY_C: + return 'c'; + case KEY_V: + return 'v'; + case KEY_B: + return 'b'; + case KEY_N: + return 'n'; + case KEY_M: + return 'm'; + case KEY_COMMA: + return ','; + case KEY_DOT: + return '.'; + case KEY_SLASH: + return '/'; + case KEY_KPASTERISK: + return '*'; + case KEY_SPACE: + return ' '; + case KEY_KP7: + return '7'; + case KEY_KP8: + return '8'; + case KEY_KP9: + return '9'; + case KEY_KPMINUS: + return '-'; + case KEY_KP4: + return '4'; + case KEY_KP5: + return '5'; + case KEY_KP6: + return '6'; + case KEY_KPPLUS: + return '+'; + case KEY_KP1: + return '1'; + case KEY_KP2: + return '2'; + case KEY_KP3: + return '3'; + case KEY_KP0: + return '0'; + case KEY_KPDOT: + return '.'; + default: + } + + return 0; +} diff --git a/drivers/virtio/virtio-input.c b/drivers/virtio/virtio-input.c index e8561a1c5132a..d68007452bda6 100644 --- a/drivers/virtio/virtio-input.c +++ b/drivers/virtio/virtio-input.c @@ -117,11 +117,23 @@ static void virtio_input_send_keyboard_event(FAR struct virtio_input_priv *priv, FAR struct virtio_input_event *event) { + static const uint32_t types[2][2] = + { + { + KEYBOARD_RELEASE, KEYBOARD_PRESS + }, + { + KBD_SPECREL, KBD_SPECPRESS + } + }; + if (event->type == EV_KEY) { - priv->keyboardsample.code = - keyboard_translate_virtio_code(event->code); - priv->keyboardsample.type = event->value; + uint32_t trans_key; + bool is_special; + trans_key = keyboard_translate_virtio_code(event->code, &is_special); + priv->keyboardsample.code = trans_key; + priv->keyboardsample.type = types[is_special][event->value & 1]; } else if (event->type == EV_SYN && event->code == SYN_REPORT) { diff --git a/include/nuttx/input/keyboard.h b/include/nuttx/input/keyboard.h index 0f52d9bf179fc..98b408a4d648b 100644 --- a/include/nuttx/input/keyboard.h +++ b/include/nuttx/input/keyboard.h @@ -27,6 +27,8 @@ * Included Files ****************************************************************************/ +#include + #include #include @@ -95,7 +97,7 @@ int keyboard_unregister(FAR struct keyboard_lowerhalf_s *lower, * Name: keyboard_translate_virtio_code ****************************************************************************/ -uint32_t keyboard_translate_virtio_code(uint16_t keycode); +uint32_t keyboard_translate_virtio_code(uint16_t keycode, bool *special); #undef EXTERN #ifdef __cplusplus