diff --git a/Documentation/components/drivers/character/input/keypad-keyboard.rst b/Documentation/components/drivers/character/input/keypad-keyboard.rst index 5e726b887dd..4e6b899cb3e 100644 --- a/Documentation/components/drivers/character/input/keypad-keyboard.rst +++ b/Documentation/components/drivers/character/input/keypad-keyboard.rst @@ -26,6 +26,159 @@ released is needed by applications as well. Thus, in addition to normal and special key press events, it may also be necessary to encode normal and special key release events. +Writing a Keyboard Driver +========================= + +A keyboard driver registers with the keyboard upper half, which owns the +character device and the buffering. This is the whole contract, and it is +what makes a keyboard work with every application that reads one: the +``kbd`` dump, the LVGL terminal, NXDoom, and anything written later. + +.. code-block:: c + + #include + + struct mykbd_dev_s + { + struct keyboard_lowerhalf_s lower; /* Must be found by container_of */ + ... + }; + + /* Register once, at board bring-up. The open, close and write callbacks + * of the lower half are all optional: a driver that has nothing to do + * when the device is opened can register with the structure zeroed. + */ + + keyboard_register(&priv->lower, "/dev/kbd0", CONFIG_MYKBD_NBUFFER); + + /* Report each key as it changes state */ + + keyboard_event(&priv->lower, keycode, type); + +Do not store the driver state in ``lower.priv``. ``keyboard_register()`` +overwrites that field with the upper half's own state, so a lower half +callback recovers the driver state with ``container_of()`` instead. + +Reporting the Right Event Type +------------------------------ + +``type`` has **four** values, and getting this wrong is a silent failure: +the build is clean and the symptom is a key that does nothing. + +====================== ===== ========================================= +Type Value ``code`` carries +====================== ===== ========================================= +``KEYBOARD_PRESS`` 0 The character that the key produces +``KEYBOARD_RELEASE`` 1 The character of the key that came up +``KEYBOARD_SPECPRESS`` 2 A value from ``enum kbd_keycode_e`` +``KEYBOARD_SPECREL`` 3 A value from ``enum kbd_keycode_e`` +====================== ===== ========================================= + +A key that produces a character is reported with its character and the +plain press and release types. A key that does not, such as an arrow, a +function key or a modifier, is reported with a keycode and one of the SPEC +types. + +The distinction matters because the two ranges overlap. ``KEYCODE_UP`` is +7 and so is the ASCII bell, so an application that receives a 7 has no way +to tell them apart other than by the event type. A driver that reports +every key as ``KEYBOARD_PRESS`` will have its arrow keys silently dropped +by any application that follows this contract. + +Choosing the Device Name +------------------------ + +Register as ``/dev/kbd0``. Applications look for a keyboard under that +name, and a keyboard registered anywhere else is out of reach of all of +them unless the user knows to point each one at it by hand. + +The USB HID driver is the exception: it names its devices ``/dev/kbda`` +onwards, because they come and go as keyboards are plugged in and more +than one can be present at a time. + +Matrix Keyboards +---------------- + +A matrix keyboard does not need a driver of its own. ``INPUT_KMATRIX`` +scans the matrix, debounces it and reports the events, so a board provides +a keymap and four GPIO callbacks and nothing more. See +``include/nuttx/input/kmatrix.h``. + +Wrap a keymap entry in ``KMATRIX_SPECIAL()`` to declare that it holds a +keycode rather than a character, so that the key is reported with a SPEC +event type: + +.. code-block:: c + + static const uint32_t g_keymap[] = + { + '1', '2', '3', + KMATRIX_SPECIAL(KEYCODE_UP), KMATRIX_SPECIAL(KEYCODE_DOWN), '0', + }; + +Testing a New Keyboard +---------------------- + +``system/kbd`` prints every event that a keyboard reports, whatever the +hardware behind it is, so it is the first thing to run on a new one:: + + nsh> kbd /dev/kbd0 + kbd: reading /dev/kbd0, keyboard events + press code 97 'a' + release code 97 'a' + specpress keycode 7 + specrel keycode 7 + +An application can also be brought up against a keyboard that does not +exist yet. ``UINPUT_KEYBOARD`` registers ``/dev/ukeyboard``, whose events +are injected by writing ``struct keyboard_event_s`` to it, and ``kbd -i`` +injects whatever it reads from its own stdin. + +.. note:: + + The leading u is for uinput, not for USB. It marks a device that + software feeds rather than hardware, and the same prefix names + ``/dev/utouch``, ``/dev/ubutton`` and ``/dev/usensor``. A USB keyboard + is ``/dev/kbda``, with no prefix at all. + +:: + + nsh> kbd -i /dev/ukeyboard + kbd: injecting into /dev/ukeyboard, type to send, Ctrl-D to stop + +Given a second device it forwards every key of one keyboard onto another +instead of reading its own stdin, so a real keyboard and an injected one +can drive the same application:: + + nsh> kbd -i /dev/ukeyboard /dev/kbd0 & + kbd: forwarding /dev/kbd0 into /dev/ukeyboard + +An application cannot do that on its own, since it opens a single device. + +Point an application at ``/dev/ukeyboard`` and it is driven from the serial +console, or from whatever is on the other end of it. This is the way to +work on the application side of a board port before its keyboard driver +exists, and the way to reach a board whose keyboard is not at hand. + +Raise ``UINPUT_KEYBOARD_BUFNUMBER`` before doing so. It counts events +rather than keys, so the default of eight holds four keystrokes, and a +console hands over a whole line at once. The upper half overwrites the +oldest event when the buffer is full, so what arrives is the tail of the +line and nothing says that the rest was dropped. + +Byte Stream Compatibility +========================= + +An application that has not been converted to read events can select +``INPUT_KEYBOARD_BYTESTREAM``, which makes every keyboard deliver the byte +stream described below instead of events. This is a property of the build +rather than of the driver, so it applies to every keyboard at once and a +configuration cannot mix the two. + +The byte stream cannot express a key release, and it cannot express a +special key at all unless ``LIBC_KBDCODEC`` is enabled. An application +that needs either has to read the events. + **Encoding/Decoding** Layer. An optional encoding/decoding layer can be used with the basic character driver to encode the keyboard events into the text data stream. The function interfaces that