SchOS/cmd/inputtest/main.c
Nexoniarz d0f7acf9eb Initial commit: Schunix as it stands before the SchOS rename
An x86-64 operating system built from xv6, now largely rewritten: SMP,
a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF
rasteriser, and a Linux-numbered syscall ABI.

No history before this point -- the tree was never under version control.
This commit exists so the rename that follows has something to undo to.
2026-08-09 13:47:01 +02:00

124 lines
3.2 KiB
C

// inputtest -- read raw events from /dev/input/eventN.
//
// The point of the raw devices is everything the console cannot say: which
// key was released, whether one is still held, and where the mouse went. None
// of that shows up in a character stream, so none of it can be tested by
// typing into a shell.
//
// inputtest read the keyboard until Esc is released
// inputtest mouse read the mouse until interrupted
// inputtest -n N stop after N events (used by the boot check)
//
// Prints one line per event: type, code and value, decoded where there is a
// name for it.
#include "types.h"
#include "user.h"
#include "fcntl.h"
#include "input.h"
static void
puts_(const char *s)
{
int n = 0;
while (s[n]) n++;
write(1, (void*)s, n);
}
static void
putn_(int v)
{
char buf[12];
int i = 0, neg = 0;
if (v < 0) { neg = 1; v = -v; }
if (v == 0) buf[i++] = '0';
while (v) { buf[i++] = '0' + (v % 10); v /= 10; }
if (neg) buf[i++] = '-';
while (i--) write(1, &buf[i], 1);
}
static const char *
typename_(int t)
{
switch (t) {
case EV_SYN: return "SYN";
case EV_KEY: return "KEY";
case EV_REL: return "REL";
default: return "?";
}
}
static int
streq(const char *a, const char *b)
{
while (*a && *a == *b) { a++; b++; }
return *a == *b;
}
int
main(int argc, char **argv)
{
const char *path = "/dev/input/event0";
int limit = 0, count = 0, i;
int fd;
struct input_event ev;
for (i = 1; i < argc; i++) {
if (streq(argv[i], "mouse"))
path = "/dev/input/event1";
else if (streq(argv[i], "-n") && i + 1 < argc) {
const char *p = argv[++i];
limit = 0;
while (*p >= '0' && *p <= '9') limit = limit * 10 + (*p++ - '0');
}
}
fd = open((char*)path, O_RDONLY);
if (fd < 0) {
puts_("inputtest: cannot open ");
puts_(path);
puts_("\n");
exit();
}
puts_("inputtest: reading ");
puts_(path);
puts_("\n");
for (;;) {
int n = read(fd, &ev, sizeof(ev));
// A short read would mean the device handed back part of a struct,
// which would desynchronise every event after it. Saying so is more
// use than silently carrying on with garbage.
if (n == 0) { puts_("inputtest: end of stream\n"); break; }
if (n < 0) { puts_("inputtest: read error\n"); break; }
if (n != sizeof(ev)) {
puts_("inputtest: SHORT READ -- events are not whole\n");
break;
}
puts_(" ");
puts_(typename_(ev.type));
puts_(" code ");
putn_(ev.code);
puts_(" value ");
putn_(ev.value);
if (ev.type == EV_KEY)
puts_(ev.value ? " (press)" : " (release)");
puts_("\n");
// Esc released ends the keyboard run, so a person can stop it without
// a signal. The boot check uses -n instead.
if (ev.type == EV_KEY && ev.code == KEY_ESC && ev.value == 0)
break;
if (limit && ++count >= limit) {
puts_("inputtest: event limit reached\n");
break;
}
}
close(fd);
puts_("inputtest: done\n");
exit();
}