All the above written, I think an USB HID device based approach is superior.
In Grub, you can do
if keystatus; then
keystatus --alt
state=$?
keystatus --ctrl
state=${state}$?
keystatus --shift
state=${state}$?
else
state=xxx
fi
to obtain the Shift, Control, and Alt, modifier key states. The
state variable will contain three characters, first character corresponding to Alt, second to Ctrl, and third to Shift. If the corresponding key is pressed, it will be 0; if not pressed, 1. (This is because in general, True corresponds to exit status 0, and False to 1.) If the state checking is not supported,
state will be
xxx. This yields eight "modes" Grub can choose from trivially:
if [ x${state} == x110 ]; then
default=shift
elif [ x${state} == x101 ]; then
default=ctrl
elif [ x${state} == x100 ]; then
default=shift+ctrl
elif [ x${state} == x011 ]; then
default=alt
elif [ x${state} == x010 ]; then
default=shift+alt
elif [ x${state} == x001 ]; then
default=ctrl+alt
elif [ x${state} == x000 ]; then
default=shift+ctrl+alt
fi
where
default is the special Grub variable that chooses which boot entry is used unless user intervenes. You can obviously do anything you want inside the if clauses.
For USB keyboards, the modifier key state is contained within each keypress/release report. This means that if you have two keyboards, and press a modifier key on one, pressing a standard key on the other will/should not have the modifier key applied. Semi-unfortunately, Grub
does combine modifier keys from all active terminals, so it is kind of important to have the USB HID device send the modifier key reports only until Grub has started, i.e. for say a second longer than the BIOS/EFI takes to run on the machine.
In a
separate thread, I asked feedback for an ultra-cheap USB gamepad using WCH CH551G microcontroller with an 8051 core that one can buy from LCSC for
under USD $0.40 apiece. This has a native USB interface, and the MCU series were extensively discussed here in
this thread. This would be basically perfect for such an use case. You could, for example, connect it to any ESP via UART or SPI.
In fact, this gives me a project idea I could use with my ARM-based SBCs (that use U-Boot and not Grub, though): CH551G mini display controller with bootloader graphics, for use with small OLED or TFT display modules (controlled via 4-wire SPI):
One would need to add USB commands to Grub/U-Boot for loading prepared images and USB HID commands to for a proper query-response interface, but that would not be a big endeavour. Without any changes to Grub, this circuit can be used for the Shift/Ctrl/Alt "messaging".
During proper OS use, the display could be exposed as a tiny framebuffer via USB Serial, HID, or even just as a bulk USB endpoint, so that one could use the display with e.g. a simple Python or C program, to show the appliance status... One of my SBCs has 1.8V UART only, so the schematic includes 74LVC1T45 level shifters. CH551G and CH552G have the same pinout, but CH552G has an ADC; P3.2 and P1.4 (and P1.1, connected to VUSB via a voltage divider) can be used for analog inputs.