locking: Lock keys statelessly
Locking is not determined by button state any more, but rather based on the view active at the moment. If pressing/locking a key results in the current view being active, the key is active. If locking a key results in the current view, the unlock view is activated.
This commit is contained in:
@ -38,3 +38,19 @@ pub enum Action {
|
|||||||
},
|
},
|
||||||
ShowPreferences,
|
ShowPreferences,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Action {
|
||||||
|
pub fn is_locked(&self, view_name: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
Action::LockView { lock, unlock: _ } => lock == view_name,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn is_active(&self, view_name: &str) -> bool {
|
||||||
|
match self {
|
||||||
|
Action::SetView(view) => view == view_name,
|
||||||
|
Action::LockView { lock, unlock: _ } => lock == view_name,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -392,7 +392,6 @@ impl Layout {
|
|||||||
name.into(),
|
name.into(),
|
||||||
KeyState {
|
KeyState {
|
||||||
pressed: PressType::Released,
|
pressed: PressType::Released,
|
||||||
locked: false,
|
|
||||||
keycodes,
|
keycodes,
|
||||||
action,
|
action,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
use cairo;
|
use cairo;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use ::action::Action;
|
|
||||||
use ::keyboard;
|
use ::keyboard;
|
||||||
use ::layout::{ Button, Layout };
|
use ::layout::{ Button, Layout };
|
||||||
use ::layout::c::{ EekGtkKeyboard, Point };
|
use ::layout::c::{ EekGtkKeyboard, Point };
|
||||||
@ -53,13 +52,7 @@ mod c {
|
|||||||
for (row_offset, row) in &view.get_rows() {
|
for (row_offset, row) in &view.get_rows() {
|
||||||
for (x_offset, button) in &row.buttons {
|
for (x_offset, button) in &row.buttons {
|
||||||
let state = RefCell::borrow(&button.state).clone();
|
let state = RefCell::borrow(&button.state).clone();
|
||||||
let locked = match state.action {
|
let locked = state.action.is_active(&layout.current_view);
|
||||||
Action::SetView(name) => name == layout.current_view,
|
|
||||||
Action::LockView { lock, unlock: _ } => {
|
|
||||||
lock == layout.current_view
|
|
||||||
},
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if state.pressed == keyboard::PressType::Pressed || locked {
|
if state.pressed == keyboard::PressType::Pressed || locked {
|
||||||
render_button_at_position(
|
render_button_at_position(
|
||||||
renderer, &cr,
|
renderer, &cr,
|
||||||
|
|||||||
@ -23,7 +23,6 @@ pub type KeyCode = u32;
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct KeyState {
|
pub struct KeyState {
|
||||||
pub pressed: PressType,
|
pub pressed: PressType,
|
||||||
pub locked: bool,
|
|
||||||
/// A cache of raw keycodes derived from Action::Sumbit given a keymap
|
/// A cache of raw keycodes derived from Action::Sumbit given a keymap
|
||||||
pub keycodes: Vec<KeyCode>,
|
pub keycodes: Vec<KeyCode>,
|
||||||
/// Static description of what the key does when pressed or released
|
/// Static description of what the key does when pressed or released
|
||||||
@ -31,17 +30,6 @@ pub struct KeyState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KeyState {
|
impl KeyState {
|
||||||
#[must_use]
|
|
||||||
pub fn into_activated(self) -> KeyState {
|
|
||||||
match self.action {
|
|
||||||
Action::LockView { lock: _, unlock: _ } => KeyState {
|
|
||||||
locked: self.locked ^ true,
|
|
||||||
..self
|
|
||||||
},
|
|
||||||
_ => self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn into_released(self) -> KeyState {
|
pub fn into_released(self) -> KeyState {
|
||||||
KeyState {
|
KeyState {
|
||||||
@ -195,7 +183,6 @@ mod tests {
|
|||||||
keys: vec!(KeySym("a".into()), KeySym("c".into())),
|
keys: vec!(KeySym("a".into()), KeySym("c".into())),
|
||||||
},
|
},
|
||||||
keycodes: vec!(9, 10),
|
keycodes: vec!(9, 10),
|
||||||
locked: false,
|
|
||||||
pressed: PressType::Released,
|
pressed: PressType::Released,
|
||||||
},
|
},
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
|
|||||||
@ -619,7 +619,6 @@ pub struct Layout {
|
|||||||
// When the list tracks actual location,
|
// When the list tracks actual location,
|
||||||
// it becomes possible to place popovers and other UI accurately.
|
// it becomes possible to place popovers and other UI accurately.
|
||||||
pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
|
pub pressed_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
|
||||||
pub locked_keys: HashSet<::util::Pointer<RefCell<KeyState>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder structure for picking up layout data from storage
|
/// A builder structure for picking up layout data from storage
|
||||||
@ -650,7 +649,6 @@ impl Layout {
|
|||||||
views: data.views,
|
views: data.views,
|
||||||
keymap_str: data.keymap_str,
|
keymap_str: data.keymap_str,
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
locked_keys: HashSet::new(),
|
|
||||||
margins: data.margins,
|
margins: data.margins,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -714,6 +712,23 @@ impl Layout {
|
|||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_locked_keys(&self) -> Vec<Rc<RefCell<KeyState>>> {
|
||||||
|
let mut out = Vec::new();
|
||||||
|
let view = self.get_current_view();
|
||||||
|
for (_, row) in &view.get_rows() {
|
||||||
|
for (_, button) in &row.buttons {
|
||||||
|
let locked = {
|
||||||
|
let state = RefCell::borrow(&button.state).clone();
|
||||||
|
state.action.is_locked(&self.current_view)
|
||||||
|
};
|
||||||
|
if locked {
|
||||||
|
out.push(button.state.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod procedures {
|
mod procedures {
|
||||||
@ -838,12 +853,13 @@ mod seat {
|
|||||||
// This is guaranteed because pressing a lock button unlocks all others.
|
// This is guaranteed because pressing a lock button unlocks all others.
|
||||||
// TODO: Make some broader guarantee about the resulting view,
|
// TODO: Make some broader guarantee about the resulting view,
|
||||||
// e.g. by maintaining a stack of stuck keys.
|
// e.g. by maintaining a stack of stuck keys.
|
||||||
|
// FIXME: This doesn't record changes in layout.locked_keys
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn unstick_locks(layout: &mut Layout) -> ViewChange {
|
fn unstick_locks(layout: &mut Layout) -> ViewChange {
|
||||||
let mut new_view = None;
|
let mut new_view = None;
|
||||||
for key in layout.locked_keys.clone() {
|
for key in layout.get_locked_keys().clone() {
|
||||||
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
let key: &Rc<RefCell<KeyState>> = key.borrow();
|
||||||
let mut key = RefCell::borrow_mut(key);
|
let key = RefCell::borrow(key);
|
||||||
match &key.action {
|
match &key.action {
|
||||||
Action::LockView { lock: _, unlock: view } => {
|
Action::LockView { lock: _, unlock: view } => {
|
||||||
new_view = Some(view.clone());
|
new_view = Some(view.clone());
|
||||||
@ -854,7 +870,6 @@ mod seat {
|
|||||||
a,
|
a,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
key.locked = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewChange {
|
ViewChange {
|
||||||
@ -899,10 +914,7 @@ mod seat {
|
|||||||
|
|
||||||
// update
|
// update
|
||||||
let key = key.into_released();
|
let key = key.into_released();
|
||||||
let key = match action {
|
let mut locked = key.action.is_locked(&layout.current_view);
|
||||||
Action::LockView { lock: _, unlock: _ } => key.into_activated(),
|
|
||||||
_ => key,
|
|
||||||
};
|
|
||||||
|
|
||||||
// process changes
|
// process changes
|
||||||
match action {
|
match action {
|
||||||
@ -918,13 +930,12 @@ mod seat {
|
|||||||
try_set_view(layout, view)
|
try_set_view(layout, view)
|
||||||
},
|
},
|
||||||
Action::LockView { lock, unlock } => {
|
Action::LockView { lock, unlock } => {
|
||||||
// The button that triggered this will be in the right state
|
locked ^= true;
|
||||||
// due to commit at the end.
|
|
||||||
unstick_locks(layout)
|
unstick_locks(layout)
|
||||||
// It doesn't matter what the resulting view should be,
|
// It doesn't matter what the resulting view should be,
|
||||||
// it's getting changed anyway.
|
// it's getting changed anyway.
|
||||||
.choose_view(
|
.choose_view(
|
||||||
match key.locked {
|
match locked {
|
||||||
true => lock.clone(),
|
true => lock.clone(),
|
||||||
false => unlock.clone(),
|
false => unlock.clone(),
|
||||||
}
|
}
|
||||||
@ -966,11 +977,6 @@ mod seat {
|
|||||||
let pointer = ::util::Pointer(rckey.clone());
|
let pointer = ::util::Pointer(rckey.clone());
|
||||||
// Apply state changes
|
// Apply state changes
|
||||||
layout.pressed_keys.remove(&pointer);
|
layout.pressed_keys.remove(&pointer);
|
||||||
if key.locked {
|
|
||||||
layout.locked_keys.insert(pointer);
|
|
||||||
} else {
|
|
||||||
layout.locked_keys.remove(&pointer);
|
|
||||||
}
|
|
||||||
// Commit activated button state changes
|
// Commit activated button state changes
|
||||||
RefCell::replace(rckey, key);
|
RefCell::replace(rckey, key);
|
||||||
}
|
}
|
||||||
@ -985,7 +991,6 @@ mod test {
|
|||||||
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
|
pub fn make_state() -> Rc<RefCell<::keyboard::KeyState>> {
|
||||||
Rc::new(RefCell::new(::keyboard::KeyState {
|
Rc::new(RefCell::new(::keyboard::KeyState {
|
||||||
pressed: PressType::Released,
|
pressed: PressType::Released,
|
||||||
locked: false,
|
|
||||||
keycodes: Vec::new(),
|
keycodes: Vec::new(),
|
||||||
action: Action::SetView("default".into()),
|
action: Action::SetView("default".into()),
|
||||||
}))
|
}))
|
||||||
@ -1064,7 +1069,6 @@ mod test {
|
|||||||
current_view: String::new(),
|
current_view: String::new(),
|
||||||
keymap_str: CString::new("").unwrap(),
|
keymap_str: CString::new("").unwrap(),
|
||||||
kind: ArrangementKind::Base,
|
kind: ArrangementKind::Base,
|
||||||
locked_keys: HashSet::new(),
|
|
||||||
pressed_keys: HashSet::new(),
|
pressed_keys: HashSet::new(),
|
||||||
// Lots of bottom margin
|
// Lots of bottom margin
|
||||||
margins: Margins {
|
margins: Margins {
|
||||||
|
|||||||
Reference in New Issue
Block a user