Skip to main content

input/
input.rs

1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! Print what the seat's devices are doing, with auto-repeat wired in.
5//!
6//! ```text
7//! cargo run -p drmkit-input --example input
8//! ```
9//!
10//! Needs read access to `/dev/input/event*`: the `input` group, or root.
11//! Without it libinput enumerates the seat and opens nothing, which looks
12//! like a keyboard that does not work -- so run it with
13//! `DRMKIT_LOG_LEVEL=debug` to hear libinput say why.
14//!
15//! Escape stops it. So does thirty seconds of nothing happening.
16
17use std::os::fd::AsFd as _;
18use std::time::{Duration, Instant};
19
20use drmkit_input::{
21    InputEvent, KeyEvent, KeyRepeater, Keyboard, KeymapNames, RepeatConfig, Seat, SeatOptions,
22};
23use rustix::event::{PollFd, PollFlags, poll};
24
25/// evdev `KEY_ESC`.
26const KEY_ESC: u32 = 1;
27
28fn main() {
29    let mut seat = match Seat::open(&SeatOptions::default()) {
30        Ok(seat) => seat,
31        Err(error) => {
32            eprintln!("{error}");
33            std::process::exit(1);
34        }
35    };
36    let mut keyboard = Keyboard::from_names(&KeymapNames::default()).expect("keymap");
37    let mut repeater = KeyRepeater::new(RepeatConfig::default()).expect("timer");
38
39    let started = Instant::now();
40    let mut events = Vec::new();
41    let mut repeats: Vec<KeyEvent> = Vec::new();
42    let mut leds = keyboard.leds();
43
44    loop {
45        {
46            let seat_fd = seat.as_fd();
47            let timer_fd = repeater.fd();
48            let mut fds = [
49                PollFd::new(&seat_fd, PollFlags::IN),
50                PollFd::new(&timer_fd, PollFlags::IN),
51            ];
52            let timeout = Duration::from_secs(30).try_into().expect("timeout");
53            if poll(&mut fds, Some(&timeout)).expect("poll") == 0 {
54                println!("nothing for thirty seconds");
55                return;
56            }
57        }
58
59        let now = u32::try_from(started.elapsed().as_millis()).unwrap_or(u32::MAX);
60
61        events.clear();
62        seat.dispatch(&mut events).expect("dispatch");
63        for event in &mut events {
64            match event {
65                InputEvent::Key(key) => {
66                    keyboard.process_key(key);
67                    repeater.on_key(key, keyboard.should_repeat(key.key));
68                    if report(key) {
69                        return;
70                    }
71                }
72                other => println!("{other:?}"),
73            }
74        }
75
76        repeats.clear();
77        repeater.dispatch(now, &mut repeats).expect("repeat");
78        for key in &mut repeats {
79            // Resolved, not replayed: a Shift pressed since the key went down
80            // changes what this types.
81            keyboard.resolve(key);
82            report(key);
83        }
84
85        let current = keyboard.leds();
86        if current != leds {
87            seat.set_leds(current);
88            leds = current;
89        }
90    }
91}
92
93/// Print one key. Returns whether it was Escape coming up.
94fn report(key: &KeyEvent) -> bool {
95    println!(
96        "key {:>3} {}{} sym {:#06x} {:?}",
97        key.key,
98        if key.pressed { "down" } else { "up  " },
99        if key.repeat { " (repeat)" } else { "" },
100        key.sym,
101        key.utf8
102    );
103    key.key == KEY_ESC && !key.pressed
104}