inputd: add VT graphics-mode control op (console suppress)
Add control kinds 3/4 (set VT graphics/text mode) and a graphics_vts set. When a VT is claimed by a graphical client, the console `Consumer` for that VT is suspended — cooked bytes stop being delivered to the text console — while the raw device tap (consumer_raw) keeps feeding the compositor. This is the RedBear equivalent of Linux KDSKBMODE(K_OFF)/KD_GRAPHICS silencing the console keyboard + n_tty for a VT owned by a Wayland compositor. Behaviour-preserving by default: graphics_vts is empty until a compositor opts in via ControlHandle::set_vt_mode(vt, true), so text-console delivery is unchanged. Two control kinds are used instead of a bool to keep the ControlEvent ABI unchanged. Full device-grab arbitration (exclusive routing / EVIOCGRAB) and the VT_PROCESS switch-ack handshake remain TODO — the raw broadcast is sufficient for a single compositor. Part of the Linux-aligned input-stack consolidation. Compile-checked for x86_64-unknown-redox; boot-validation pending build-green.
This commit is contained in:
@@ -271,6 +271,20 @@ impl ControlHandle {
|
||||
let cmd = ControlEvent::from(KeymapActivate { keymap });
|
||||
self.0.write(unsafe { any_as_u8_slice(&cmd) })
|
||||
}
|
||||
|
||||
/// Claim (`graphics = true`) or release (`graphics = false`) a VT for a
|
||||
/// graphical client (a Wayland compositor). Claiming suspends the text
|
||||
/// console for that VT — the RedBear `KDSKBMODE(K_OFF)` equivalent — so a
|
||||
/// compositor reading the raw device tap (`consumer_raw`) owns input while
|
||||
/// the text console stays silent. Releasing restores normal console
|
||||
/// delivery. See inputd `set_vt_mode`.
|
||||
pub fn set_vt_mode(&mut self, vt: usize, graphics: bool) -> io::Result<usize> {
|
||||
let cmd = ControlEvent {
|
||||
kind: if graphics { 3 } else { 4 },
|
||||
data: vt,
|
||||
};
|
||||
self.0.write(unsafe { any_as_u8_slice(&cmd) })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
+55
-14
@@ -77,6 +77,13 @@ struct InputScheme {
|
||||
|
||||
display: Option<String>,
|
||||
vts: BTreeSet<usize>,
|
||||
/// VTs currently owned by a graphical client (a Wayland compositor). While a
|
||||
/// VT is in this set the console `Consumer` for it is SUSPENDED — no cooked
|
||||
/// bytes are delivered to the text console — exactly like Linux
|
||||
/// `KDSKBMODE(K_OFF)` silences the console keyboard/n_tty for a graphics VT.
|
||||
/// The compositor reads the raw device tap (`consumer_raw`) instead. Empty by
|
||||
/// default, so console behaviour is unchanged until a compositor opts in.
|
||||
graphics_vts: BTreeSet<usize>,
|
||||
super_key: bool,
|
||||
active_vt: Option<usize>,
|
||||
active_keymap: KeymapData,
|
||||
@@ -95,6 +102,7 @@ impl InputScheme {
|
||||
|
||||
display: None,
|
||||
vts: BTreeSet::new(),
|
||||
graphics_vts: BTreeSet::new(),
|
||||
super_key: false,
|
||||
active_vt: None,
|
||||
// TODO: configurable init?
|
||||
@@ -145,6 +153,28 @@ impl InputScheme {
|
||||
self.active_vt = Some(new_active);
|
||||
}
|
||||
|
||||
/// Set whether a VT is owned by a graphical client (a compositor).
|
||||
///
|
||||
/// `graphics = true` suspends the text console for that VT (the RedBear
|
||||
/// `KDSKBMODE(K_OFF)` equivalent): the compositor now drives the display and
|
||||
/// reads raw input from `consumer_raw`, so cooked bytes must not also land in
|
||||
/// the console `Consumer`. `graphics = false` restores normal text-console
|
||||
/// delivery. Idempotent; unknown VTs are accepted (a compositor may claim a
|
||||
/// VT it is about to open).
|
||||
fn set_vt_mode(&mut self, vt: usize, graphics: bool) {
|
||||
let changed = if graphics {
|
||||
self.graphics_vts.insert(vt)
|
||||
} else {
|
||||
self.graphics_vts.remove(&vt)
|
||||
};
|
||||
if changed {
|
||||
log::debug!(
|
||||
"VT #{vt} mode -> {}",
|
||||
if graphics { "graphics" } else { "text" }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn switch_keymap(&mut self, new_active: usize) {
|
||||
if new_active == self.active_keymap.get_kind() as usize {
|
||||
return;
|
||||
@@ -399,6 +429,11 @@ impl SchemeSync for InputScheme {
|
||||
match cmd.kind {
|
||||
1 => self.switch_vt(cmd.data),
|
||||
2 => self.switch_keymap(cmd.data),
|
||||
// 3/4: a graphical client (compositor) claims/releases a VT.
|
||||
// `data` is the VT id. Two kinds instead of a bool keeps the
|
||||
// ControlEvent ABI unchanged.
|
||||
3 => self.set_vt_mode(cmd.data, true),
|
||||
4 => self.set_vt_mode(cmd.data, false),
|
||||
k => {
|
||||
log::warn!("unknown control {}", k);
|
||||
}
|
||||
@@ -523,22 +558,28 @@ impl SchemeSync for InputScheme {
|
||||
};
|
||||
|
||||
if let Some(active_vt) = self.active_vt {
|
||||
for handle in self.handles.values_mut() {
|
||||
match handle {
|
||||
Handle::Consumer {
|
||||
pending,
|
||||
notified,
|
||||
vt,
|
||||
..
|
||||
} => {
|
||||
if *vt != active_vt {
|
||||
continue;
|
||||
}
|
||||
// Suppress the text console entirely when the active VT is owned by a
|
||||
// graphical client — the compositor drives it via the raw tap, and
|
||||
// cooked bytes must not also reach a (now hidden) text console.
|
||||
let console_suppressed = self.graphics_vts.contains(&active_vt);
|
||||
if !console_suppressed {
|
||||
for handle in self.handles.values_mut() {
|
||||
match handle {
|
||||
Handle::Consumer {
|
||||
pending,
|
||||
notified,
|
||||
vt,
|
||||
..
|
||||
} => {
|
||||
if *vt != active_vt {
|
||||
continue;
|
||||
}
|
||||
|
||||
pending.extend_from_slice(buf);
|
||||
*notified = false;
|
||||
pending.extend_from_slice(buf);
|
||||
*notified = false;
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user