aboutsummaryrefslogtreecommitdiff
path: root/src/input
diff options
context:
space:
mode:
authorSalman Farooq <salman.farooq3310@gmail.com>2024-06-30 22:37:44 +0500
committerIvan Molodetskikh <yalterz@gmail.com>2024-07-05 08:40:25 +0300
commitd3aebdbec4ae2c1ac4199cdd4e95a8d218362b25 (patch)
treeec57d3537a83f005785ffa132b4ad97a17369c75 /src/input
parenta56e4ff436cc4f36d7cda89e985d51e37f0b4f78 (diff)
downloadniri-d3aebdbec4ae2c1ac4199cdd4e95a8d218362b25.tar.gz
niri-d3aebdbec4ae2c1ac4199cdd4e95a8d218362b25.tar.bz2
niri-d3aebdbec4ae2c1ac4199cdd4e95a8d218362b25.zip
Implement key repeat for compositor binds
Diffstat (limited to 'src/input')
-rw-r--r--src/input/mod.rs57
1 files changed, 55 insertions, 2 deletions
diff --git a/src/input/mod.rs b/src/input/mod.rs
index 2a1073f9..7fa363c0 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -294,6 +294,19 @@ impl State {
let time = Event::time_msec(&event);
let pressed = event.state() == KeyState::Pressed;
+ // Stop bind key repeat on any release. This won't work 100% correctly in cases like:
+ // 1. Press Mod
+ // 2. Press Left (repeat starts)
+ // 3. Press PgDown (new repeat starts)
+ // 4. Release Left (PgDown repeat stops)
+ // But it's good enough for now.
+ // FIXME: handle this properly.
+ if !pressed {
+ if let Some(token) = self.niri.bind_repeat_timer.take() {
+ self.niri.event_loop.remove(token);
+ }
+ }
+
let Some(Some(bind)) = self.niri.seat.get_keyboard().unwrap().input(
self,
event.key_code(),
@@ -330,12 +343,44 @@ impl State {
return;
};
- // Filter actions when the key is released or the session is locked.
if !pressed {
return;
}
- self.handle_bind(bind);
+ self.handle_bind(bind.clone());
+
+ // Start the key repeat timer if necessary.
+ if !bind.repeat {
+ return;
+ }
+
+ // Stop the previous key repeat if any.
+ if let Some(token) = self.niri.bind_repeat_timer.take() {
+ self.niri.event_loop.remove(token);
+ }
+
+ let config = self.niri.config.borrow();
+ let config = &config.input.keyboard;
+
+ let repeat_rate = config.repeat_rate;
+ if repeat_rate == 0 {
+ return;
+ }
+ let repeat_duration = Duration::from_secs_f64(1. / f64::from(repeat_rate));
+
+ let repeat_timer =
+ Timer::from_duration(Duration::from_millis(u64::from(config.repeat_delay)));
+
+ let token = self
+ .niri
+ .event_loop
+ .insert_source(repeat_timer, move |_, _, state| {
+ state.handle_bind(bind.clone());
+ TimeoutAction::ToDuration(repeat_duration)
+ })
+ .unwrap();
+
+ self.niri.bind_repeat_timer = Some(token);
}
pub fn handle_bind(&mut self, bind: Bind) {
@@ -2132,6 +2177,7 @@ fn should_intercept_key(
modifiers: Modifiers::empty(),
},
action,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
});
@@ -2181,6 +2227,7 @@ fn find_bind(
modifiers: Modifiers::empty(),
},
action,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
});
@@ -2512,6 +2559,7 @@ mod tests {
modifiers: Modifiers::COMPOSITOR | Modifiers::CTRL,
},
action: Action::CloseWindow,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
}]);
@@ -2645,6 +2693,7 @@ mod tests {
modifiers: Modifiers::COMPOSITOR,
},
action: Action::CloseWindow,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
},
@@ -2654,6 +2703,7 @@ mod tests {
modifiers: Modifiers::SUPER,
},
action: Action::FocusColumnLeft,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
},
@@ -2663,6 +2713,7 @@ mod tests {
modifiers: Modifiers::empty(),
},
action: Action::FocusWindowDown,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
},
@@ -2672,6 +2723,7 @@ mod tests {
modifiers: Modifiers::COMPOSITOR | Modifiers::SUPER,
},
action: Action::FocusWindowUp,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
},
@@ -2681,6 +2733,7 @@ mod tests {
modifiers: Modifiers::SUPER | Modifiers::ALT,
},
action: Action::FocusColumnRight,
+ repeat: true,
cooldown: None,
allow_when_locked: false,
},