Xorg on a framebuffer -- the fbdev video driver, the evdev input driver, libpciaccess -- asks the kernel a fixed set of questions before it draws anything, and gives up on the first wrong answer. These are those answers. evdev: EVIOCGVERSION, GID, GNAME, GPHYS, GUNIQ, GPROP, GBIT, GKEY, GABS, GREP and the accepted setters. Xorg and libinput decide what a device *is* from the capability bitmaps; /dev/input/eventN answered only EVIOCGRAB, which reads as no device at all. Each device's bitmaps are its defaults plus whatever it has reported, so a USB tablet makes the pointer absolute. fbdev: FBIOPUT_VSCREENINFO succeeds for the mode already set, as on Linux -- the fbdev driver sets it every time it starts -- and still refuses any other. FBIOPAN_DISPLAY to the origin; FBIOBLANK. The console: KDSETMODE(KD_GRAPHICS) stops it drawing on a terminal, KDSKBMODE(K_OFF) stops keys reaching its tty, and VT_PROCESS now does the switch handshake: leaving the terminal sends relsig and waits for VT_RELDISP, arriving sends acqsig. A terminal whose owner has died goes back to the kernel whole, so a crashed X cannot leave the console dead. /sys: boot_vga, a writable enable, and graphics/fb0 under the display device, which is how the fbdev driver pairs a card with /dev/fb0. ports/linux-headers: <linux/*.h> into musl's prefix, from sabotage- linux's kernel-headers 4.19.88-2. Its checksum is recorded from the first download; upstream publishes none. cmd/xready makes each call and checks the answer, including the switch handshake on tty2 and an owner that dies holding it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
157 lines
5.1 KiB
C
157 lines
5.1 KiB
C
#pragma once
|
|
|
|
#include "core/types.h"
|
|
|
|
// Raw input events -- Linux's evdev interface.
|
|
//
|
|
// The console gives characters. That is the right thing for a shell and the
|
|
// wrong thing for everything else: a character stream has no key *releases*,
|
|
// no way to tell left shift from right, no notion of a key being held, and no
|
|
// mouse at all. A game holding W to walk forward, or a compositor deciding
|
|
// which window a click landed in, needs the events underneath the characters.
|
|
//
|
|
// The layout is Linux's, deliberately. It is what every program that reads input
|
|
// already speaks -- SDL, X, libinput, every game engine -- so a program that
|
|
// runs on Linux reads input here without a porting layer. It costs nothing to
|
|
// match: the struct is four fields.
|
|
//
|
|
// Nodes are /dev/input/event0 (keyboard) and /dev/input/event1 (mouse).
|
|
|
|
struct input_timeval {
|
|
int64 tv_sec;
|
|
int64 tv_usec;
|
|
};
|
|
|
|
struct input_event {
|
|
struct input_timeval time;
|
|
uint16 type;
|
|
uint16 code;
|
|
int32 value;
|
|
};
|
|
|
|
// Event types.
|
|
#define EV_SYN 0x00
|
|
#define EV_KEY 0x01
|
|
#define EV_REL 0x02
|
|
#define EV_ABS 0x03
|
|
#define EV_MSC 0x04
|
|
#define EV_LED 0x11
|
|
#define EV_REP 0x14
|
|
#define EV_MAX 0x1f
|
|
|
|
#define SYN_REPORT 0
|
|
|
|
// Relative axes.
|
|
// Absolute axes, for a pointing device that reports where it *is* rather than
|
|
// how far it moved -- a tablet, a touchscreen, or a VM's absolute pointer.
|
|
// Same numbering as Linux, because /dev/input/eventN claims to speak evdev.
|
|
#define ABS_X 0x00
|
|
#define ABS_Y 0x01
|
|
|
|
#define REL_X 0x00
|
|
#define REL_Y 0x01
|
|
#define REL_WHEEL 0x08
|
|
#define REL_MAX 0x0f
|
|
#define ABS_MAX 0x3f
|
|
|
|
// Buttons live in the EV_KEY code space alongside keys, which is why the
|
|
// keyboard's codes stop well below 0x100.
|
|
#define BTN_LEFT 0x110
|
|
#define BTN_RIGHT 0x111
|
|
#define BTN_MIDDLE 0x112
|
|
|
|
// Key codes worth naming. The rest are the AT scancode-set-1 numbers, which
|
|
// Linux's keycodes were derived from and still match for everything below
|
|
// 0x54 -- that is not a coincidence and it is why the PS/2 path needs no
|
|
// translation table for unprefixed bytes.
|
|
#define KEY_RESERVED 0
|
|
#define KEY_ESC 1
|
|
#define KEY_ENTER 28
|
|
#define KEY_LEFTCTRL 29
|
|
#define KEY_LEFTSHIFT 42
|
|
#define KEY_RIGHTSHIFT 54
|
|
#define KEY_LEFTALT 56
|
|
#define KEY_SPACE 57
|
|
#define KEY_RIGHTCTRL 97
|
|
#define KEY_RIGHTALT 100
|
|
#define KEY_HOME 102
|
|
#define KEY_UP 103
|
|
#define KEY_PAGEUP 104
|
|
#define KEY_LEFT 105
|
|
#define KEY_RIGHT 106
|
|
#define KEY_END 107
|
|
#define KEY_DOWN 108
|
|
#define KEY_PAGEDOWN 109
|
|
#define KEY_INSERT 110
|
|
#define KEY_DELETE 111
|
|
#define KEY_LEFTMETA 125
|
|
#define KEY_RIGHTMETA 126
|
|
|
|
#define KEY_MAX 0x2ff // Linux's; the bitmaps are this wide
|
|
|
|
// EVIOCGRAB -- take/release exclusive access to a device.
|
|
//
|
|
// Linux's _IOW('E', 0x90, int). Spelled as the resulting constant rather than
|
|
// built from an _IOW macro because SchOS has no ioctl-encoding macros and
|
|
// inventing a set just for this would be a bigger change than the feature.
|
|
// A non-zero argument grabs, zero releases; the argument is passed by value.
|
|
#define EVIOCGRAB 0x40044590
|
|
#define EVIOCREVOKE 0x40044591
|
|
|
|
// The queries a program makes before it reads anything: what the device is
|
|
// called, what it can report, what state it is in now. Xorg's evdev driver
|
|
// and libinput both decide what a device *is* -- keyboard, mouse, tablet --
|
|
// from the capability bitmaps alone, and treat a device that answers ENOTTY
|
|
// as no device at all.
|
|
//
|
|
// Linux's _IOC encoding: direction in bits 31:30 (2 read, 1 write), the size
|
|
// of the argument in 29:16, the type ('E') in 15:8, the number in 7:0. The
|
|
// variable-length ones carry the caller's buffer size in the size field, so
|
|
// they are matched with it masked out.
|
|
#define EVIOC_DIR(r) (((uint)(r) >> 30) & 3)
|
|
#define EVIOC_SIZE(r) (((uint)(r) >> 16) & 0x3fff)
|
|
#define EVIOC_TYPE(r) (((uint)(r) >> 8) & 0xff)
|
|
#define EVIOC_NR(r) ((uint)(r) & 0xff)
|
|
|
|
#define EVIOCGVERSION 0x80044501
|
|
#define EVIOCGID 0x80084502
|
|
#define EVIOCGREP 0x80084503
|
|
#define EVIOCSREP 0x40084503
|
|
#define EVIOCSCLOCKID 0x400445a0
|
|
// By number, with the length taken from the request:
|
|
#define EVIOCNR_GNAME 0x06
|
|
#define EVIOCNR_GPHYS 0x07
|
|
#define EVIOCNR_GUNIQ 0x08
|
|
#define EVIOCNR_GPROP 0x09
|
|
#define EVIOCNR_GKEY 0x18
|
|
#define EVIOCNR_GLED 0x19
|
|
#define EVIOCNR_GSND 0x1a
|
|
#define EVIOCNR_GSW 0x1b
|
|
#define EVIOCNR_GBIT 0x20 // + event type, 0x20..0x3f
|
|
#define EVIOCNR_GABS 0x40 // + axis, 0x40..0x7f
|
|
#define EVIOCNR_SABS 0xc0 // + axis
|
|
|
|
struct input_id {
|
|
uint16 bustype;
|
|
uint16 vendor;
|
|
uint16 product;
|
|
uint16 version;
|
|
};
|
|
|
|
struct input_absinfo {
|
|
int32 value;
|
|
int32 minimum;
|
|
int32 maximum;
|
|
int32 fuzz;
|
|
int32 flat;
|
|
int32 resolution;
|
|
};
|
|
|
|
#define BUS_I8042 0x11
|
|
#define INPUT_PROP_POINTER 0x00
|
|
|
|
// Which device an event came from. Both are minor numbers under the input
|
|
// major, and both are the index into the driver's array.
|
|
#define INPUT_KBD 0
|
|
#define INPUT_MOUSE 1
|
|
#define NINPUTDEV 2
|