gardesk/gardm / 02efb57

Browse files

Reset caps/num lock state on greeter startup

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
02efb57d6e7246a8f87be8dc6e69172894f46636
Parents
3042f28
Tree
e4a5658

2 changed files

StatusFile+-
M Cargo.toml 1 1
M gardm-greeter/src/window.rs 55 0
Cargo.tomlmodified
@@ -30,7 +30,7 @@ nix = { version = "0.27", features = ["user", "process", "signal"] }
3030
 pam-client = "0.5"
3131
 
3232
 # X11
33
-x11rb = { version = "0.13", features = ["allow-unsafe-code", "randr"] }
33
+x11rb = { version = "0.13", features = ["allow-unsafe-code", "randr", "xkb"] }
3434
 
3535
 # Graphics
3636
 cairo-rs = { version = "0.18", features = ["png"] }
gardm-greeter/src/window.rsmodified
@@ -4,6 +4,7 @@
44
 
55
 use anyhow::{Context, Result};
66
 use x11rb::connection::Connection;
7
+use x11rb::protocol::xkb::{self, ConnectionExt as XkbConnectionExt};
78
 use x11rb::protocol::xproto::*;
89
 use x11rb::rust_connection::RustConnection;
910
 use x11rb::wrapper::ConnectionExt as _;
@@ -179,6 +180,10 @@ impl GreeterWindow {
179180
             .context("Failed to set input focus")?;
180181
         conn.flush()?;
181182
 
183
+        // Reset keyboard modifier state (caps lock, num lock) to avoid
184
+        // inconsistent state when returning from Wayland sessions
185
+        reset_keyboard_modifiers(&conn);
186
+
182187
         tracing::info!(width, height, "Created greeter window");
183188
 
184189
         Ok(Self {
@@ -310,3 +315,53 @@ impl Drop for GreeterWindow {
310315
         let _ = self.conn.flush();
311316
     }
312317
 }
318
+
319
+/// Reset keyboard modifier state (caps lock, num lock) to OFF
320
+///
321
+/// This ensures a consistent keyboard state when the greeter starts,
322
+/// avoiding issues when returning from Wayland sessions where the X server
323
+/// and physical keyboard state may be out of sync.
324
+fn reset_keyboard_modifiers(conn: &RustConnection) {
325
+    // Initialize XKB extension
326
+    if let Err(e) = conn.xkb_use_extension(1, 0) {
327
+        tracing::warn!("Failed to initialize XKB extension: {}", e);
328
+        return;
329
+    }
330
+
331
+    // Use XKB to clear locked modifiers (caps lock = modifier 1, num lock = modifier 4)
332
+    // The affect_mod_locks mask specifies which modifiers to affect
333
+    // The mod_locks value specifies the new lock state (0 = unlocked)
334
+    //
335
+    // Modifier bits (X11/XKB standard):
336
+    // - Shift: bit 0
337
+    // - Lock (Caps): bit 1
338
+    // - Control: bit 2
339
+    // - Mod1 (Alt): bit 3
340
+    // - Mod2 (Num Lock): bit 4
341
+
342
+    // Clear caps lock (bit 1) and num lock (bit 4)
343
+    let affect_locks = ModMask::LOCK | ModMask::M2; // caps lock + num lock
344
+    let clear_locks = ModMask::from(0u16);          // set to 0 (unlocked)
345
+
346
+    // xkb_latch_lock_state signature:
347
+    // device_spec, affect_mod_locks, mod_locks, lock_group, group_lock,
348
+    // affect_mod_latches, latch_group, group_latch
349
+    match conn.xkb_latch_lock_state(
350
+        xkb::ID::USE_CORE_KBD.into(),
351
+        affect_locks,          // affect_mod_locks - which locks to change
352
+        clear_locks,           // mod_locks - new lock state (0 = off)
353
+        false,                 // lock_group - don't change group lock
354
+        xkb::Group::M1,        // group_lock - ignored since lock_group is false
355
+        ModMask::from(0u16),   // affect_mod_latches - don't change latches
356
+        false,                 // latch_group
357
+        0u16,                  // group_latch
358
+    ) {
359
+        Ok(_) => {
360
+            let _ = conn.flush();
361
+            tracing::debug!("Reset keyboard modifier locks (caps lock, num lock)");
362
+        }
363
+        Err(e) => {
364
+            tracing::warn!("Failed to reset keyboard modifiers: {}", e);
365
+        }
366
+    }
367
+}