Files
vystem-b/docs/shelter/devs/kbdinput.md
2026-05-27 19:34:54 +02:00

6.0 KiB

Keyboard input subsystem

Introduction

The keyboard input subsystem is responsible for abstracting keyboard devices and keyboards events. It's defined in shelter/lib/include/devs/input/kbd.h and implemented in shelter/lib/src/devs/input/kbd.c. It's still in the early stage and isn't finished for the moment.

Overview

The keyboard input subsystem is based on two key concepts:

  • keyboard devices: this is the standard abstraction for any keyboard-like devices
  • keyboard events: provides a standard way to interpret any events from any keyboard devices

The keyboard input subsystem is initialized using sh_kbd_init_devs().

Keyboard devices

Driver side

The keyboard device structure look like this:

typedef struct {
  sh_uint8 kbd_id;
  sh_queue_KBD_EVENT *events_queue;
  sh_bool present;
  sh_bool ver_maj;
  sh_bool ver_num;
  sh_bool shift;
  sh_bool alt;
  sh_bool ctrl;
  sh_bool win;
  sh_SPIN_LOCK spinlock;
} sh_kbd_DEVICE;

Each keyboard device is identified with a keyboard id. When a keyboard is unregistered, the keyboard id can be recycled for a new keyboard device. There is a maximum of 256 keyboards id, and so 256 maximum registered keyboard devices at the same time.

The keyboard id 0 is reserved for the PS2 keyboard. It's always valid, even if there is no PS2 controller.

The present boolean defines if the keyboard is present. If present is SH_FALSE, no actions except unregistering the keyboard is allowed on the keyboard device.

The present boolean for the keyboard od keyboard id 0 indicates if the PS2 controller is available.

There is two primitives to register keyboards devices:

  • sh_kbd_register_ps2(sh_bool is_present,sh_kbd_DRIVER_HANDLE **handle): register the PS2 keyboard, reserved for the PS2 driver
  • sh_kbd_register(sh_bool is_present,sh_kbd_DRIVER_HANDLE **handle): register a new keyboard device

Upon registration, a sh_kbd_DRIVER_HANDLE struct is completed. It became non valid when the keyboard is unregistered. It is reserved for driver usage only.

Two primitives accessible to drivers require this driver handle:

  • sh_kbd_set_flag(sh_kbd_DRIVER_HANDLE *handle,sh_uint8 flag,sh_bool value): set a flag about the keyboard corresponding to the provided driver handle
  • sh_kbd_push_events(sh_kbd_DRIVER_HANDLE *handle,sh_kbd_EVENT *event): push an event in the events queue of the keyboard device corresponding to the provided driver handle

There is, for the moment, no primitive to unregister a keyboard.

Consumer side

Four functions are available for consumers:

  • sh_kbd_enumerate_devices(sh_kbd_ENUMERATION *enumeration): complete a sh_kbd_ENUMERATION structure, each bit set to 1 correspond to a valid keyboard id
  • sh_kbd_get_handle(sh_uint8 kbd_id,sh_kbd_CONSUMER_HANDLE **handle): return a valid consumer handle for the provided keyboard id. It uses sh_malloc
  • sh_kbd_destroy_handle(sh_kbd_CONSUMER_HANDLE **handle): free the provided consumer handle
  • sh_kbd_read_flag(sh_kbd_DRIVER_HANDLE *d_handle,sh_kbd_CONSUMER_HANDLE *c_handle,sh_uint8 flag,sh_bool *value): read a flag about the keyboard corresponding to the provided handle. Accepts either a driver or consumer handle, but fails if both handle are provided.

The possible flags to read/write are: SH_KBD_FLAG_PRESENT, SH_KBD_FLAG_VER_MAJ, SH_KBD_FLAG_VER_NUM, SH_KBD_FLAG_SHIFT, SH_KBD_FLAG_ALT, SH_KBD_FLAG_CTRL, SH_KBD_FLAG_WIN.

There is, for the moment, no way to read keyboards events.

Keyboard events

A keyboard event is represented by this structure:

typedef struct {
  sh_uint16 scancode;
  sh_bool pressed;
  sh_uint8 context_shift_win;
  sh_uint8 context_alt;
  sh_uint8 context_ctrl;
  sh_uint8 context_lock_status;
  sh_uint8 event_type;
  sh_uint64 timestamp;
} sh_kbd_EVENT;

All non-pause events contain a snapshot of keyboard context state at emission time, before the state of corresponding flag in the keyboard device changes. These fields remain valid even for SH_EVENT_TYPE_KBD_CONTEXT:

  • context_shift_win:
    • Bit 0: shift active, checked with macro SH_KBD_EVENT_SHIFT_ACTIVE
    • Bit 1: win active, checked with macro SH_KBD_EVENT_WIN_ACTIVE
  • context_alt:
    • Bit 0: right alt active, checked with macro SH_KBD_EVENT_RIGHT_ACTIVE
    • Bit 1: left alt active, checked with macro SH_KBD_EVENT_LEFT_ACTIVE
  • context_ctrl:
    • Bit 0: right control active, checked with macro SH_KBD_EVENT_RIGHT_ACTIVE
    • Bit 1: left control active, checked with macro SH_KBD_EVENT_LEFT_ACTIVE
  • context_lock_status:
    • Bit 0: numlock active, checked with SH_KBD_EVENT_NUMLOCK_ACTIVE
    • Bit 0: capslock active, checked with SH_KBD_EVENT_CAPSLOCK_ACTIVE

There is a precise way of interpreting what this structure mean. It start by checking the value of event_type.

SH_EVENT_TYPE_KBD_PAUSE

The event is a press of the pause key. The scancode and pressed fields should be ignored.

SH_EVENT_TYPE_KBD_CONTEXT

This event is a press of a modifier key. It allows to abstract modifiers keys events accross all types of keyboards.

The scancode must be one of the following:

  • SH_KBD_CONTEXT_LSHIFT
  • SH_KBD_CONTEXT_RSHIFT
  • SH_KBD_CONTEXT_LCTRL
  • SH_KBD_CONTEXT_RCTRL
  • SH_KBD_CONTEXT_LALT
  • SH_KBD_CONTEXT_RALT
  • SH_KBD_CONTEXT_WIN
  • SH_KBD_CONTEXT_NUMLOCK
  • SH_KBD_CONTEXT_CAPSLOCK

You need to check the pressed boolean to know if the key was pressed or released.

SH_EVENT_TYPE_PS2_NORMAL

This event type represents a standard PS2 Set1 scancode. The scancode is put in the low 8 bits of the scancode fields. The high 8 bits are set to 0.

You need to check the pressed boolean to know if the key was pressed or released.

SH_EVENT_TYPE_PS2_E0

This event type represents an extended PS2 Set1 scancode prefixed by 0xE0. The scancode is put in the low 8 bits of the scancode fields. The high 8 bits are set to 0xE0.

You need to check the pressed boolean to know if the key was pressed or released.

Notes

For SH_EVENT_TYPE_PS2_NORMAL and SH_EVENT_TYPE_PS2_E0 events type, the scancode, when pressed is SH_FALSE, keeps its bit 8 to 1.