Skip to content

Commit 7b3ae90

Browse files
committed
Fixes for extras, tap-hold, shift-select
Update sensitivity based on state of `shift` key. Distinguish basic from non-basic keycodes. Non-basic not allowed with shift select. Show "Left" or "Right" only once when multiple modifiers are combined. Update how internal state is handled in tap-hold, render with line separator, and handle shift-select. Show QMK features only on QMK keyboard, using a `is_qmk` `meta.json` setting. Only allow shift-select where this is enabled. Also only apply QMK features in backend crate when QMK layout is used.
1 parent 3b84291 commit 7b3ae90

File tree

13 files changed

+283
-183
lines changed

13 files changed

+283
-183
lines changed

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ members = [ "tools", "ffi", "backend", "widgets" ]
1111
[dependencies]
1212
cascade = "1"
1313
futures = "0.3.13"
14-
# 3.24 is packaged by focal
15-
gtk = { version = "0.15.0", features = ["v3_24"] }
14+
gtk = { version = "0.15.0", features = ["v3_22"] }
1615
libc = "0.2"
1716
once_cell = "1.4"
1817
pangocairo = "0.15.0"

backend/src/keycode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ impl std::fmt::Display for Keycode {
127127
write!(f, " | ")?;
128128
}
129129
write!(f, "{}", mod_name)?;
130+
has_mod = true;
130131
}
131132
if !(scancode_name == "NONE" && has_mod) {
132133
write!(f, "{}", scancode_name)?;
@@ -140,6 +141,7 @@ impl std::fmt::Display for Keycode {
140141
write!(f, " | ")?;
141142
}
142143
write!(f, "{}", mod_name)?;
144+
has_mod = true;
143145
}
144146
write!(f, ", {})", scancode_name)?;
145147
}

backend/src/layout/meta.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ pub struct Meta {
2020
pub has_brightness: bool,
2121
/// Has LED with color (i.e. not monochrome)
2222
pub has_color: bool,
23-
/// Supports mod-tap bindings (assumes QMK mod-tap encoding)
23+
/// Supports mod-tap and other QMK features
2424
#[serde(default)]
25-
pub has_mod_tap: bool,
25+
pub is_qmk: bool,
2626
#[serde(default)]
2727
/// Disable "Invert F Keys" option
2828
pub no_fn_f: bool,

backend/src/layout/mod.rs

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use once_cell::sync::Lazy;
12
use std::{collections::HashMap, fs, path::Path};
23

34
mod meta;
@@ -61,6 +62,14 @@ macro_rules! keyboards {
6162
// Calls the `keyboards!` macro
6263
include!(concat!(env!("OUT_DIR"), "/keyboards.rs"));
6364

65+
pub fn is_qmk_basic(name: &str) -> bool {
66+
static QMK_KEYMAP: Lazy<HashMap<String, u16>> =
67+
Lazy::new(|| parse_keymap_json(layout_data("system76/launch_1").unwrap().2).0);
68+
QMK_KEYMAP
69+
.get(name)
70+
.map_or(false, |scancode| *scancode <= 0xff)
71+
}
72+
6473
impl Layout {
6574
pub fn from_data(
6675
meta_json: &str,
@@ -131,35 +140,36 @@ impl Layout {
131140

132141
/// Get the scancode number corresponding to a name
133142
pub fn scancode_to_name(&self, scancode: u16) -> Option<Keycode> {
134-
// XXX only on QMK?
135-
if scancode >= QK_MOD_TAP && scancode <= QK_MOD_TAP_MAX {
136-
let mods = Mods::from_bits((scancode >> 8) & 0x1f)?;
137-
let kc = scancode & 0xff;
138-
let kc_name = self.scancode_names.get(&kc)?;
139-
Some(Keycode::MT(mods, kc_name.clone()))
140-
} else if scancode >= QK_LAYER_TAP && scancode <= QK_LAYER_TAP_MAX {
141-
let layer = ((scancode >> 8) & 0xf) as u8;
142-
let kc = scancode & 0xff;
143-
let kc_name = self.scancode_names.get(&kc)?;
144-
Some(Keycode::LT(layer, kc_name.clone()))
145-
} else if scancode >= QK_MODS && scancode <= QK_MODS_MAX {
146-
let mods = Mods::from_bits((scancode >> 8) & 0x1f)?;
147-
let kc = scancode & 0xff;
148-
let kc_name = self.scancode_names.get(&kc)?;
149-
Some(Keycode::Basic(mods, kc_name.clone()))
150-
} else {
151-
let kc_name = self.scancode_names.get(&scancode)?;
152-
if let Some(mods) = Mods::from_mod_str(kc_name) {
153-
Some(Keycode::Basic(mods, "NONE".to_string()))
154-
} else {
155-
Some(Keycode::Basic(Mods::empty(), kc_name.clone()))
143+
if self.meta.is_qmk {
144+
if scancode >= QK_MOD_TAP && scancode <= QK_MOD_TAP_MAX {
145+
let mods = Mods::from_bits((scancode >> 8) & 0x1f)?;
146+
let kc = scancode & 0xff;
147+
let kc_name = self.scancode_names.get(&kc)?;
148+
return Some(Keycode::MT(mods, kc_name.clone()));
149+
} else if scancode >= QK_LAYER_TAP && scancode <= QK_LAYER_TAP_MAX {
150+
let layer = ((scancode >> 8) & 0xf) as u8;
151+
let kc = scancode & 0xff;
152+
let kc_name = self.scancode_names.get(&kc)?;
153+
return Some(Keycode::LT(layer, kc_name.clone()));
154+
} else if scancode >= QK_MODS && scancode <= QK_MODS_MAX {
155+
let mods = Mods::from_bits((scancode >> 8) & 0x1f)?;
156+
let kc = scancode & 0xff;
157+
let kc_name = self.scancode_names.get(&kc)?;
158+
return Some(Keycode::Basic(mods, kc_name.clone()));
156159
}
157160
}
161+
let kc_name = self.scancode_names.get(&scancode)?;
162+
if let Some(mods) = Mods::from_mod_str(kc_name) {
163+
Some(Keycode::Basic(mods, "NONE".to_string()))
164+
} else {
165+
Some(Keycode::Basic(Mods::empty(), kc_name.clone()))
166+
}
158167
}
159168

160169
/// Get the name corresponding to a scancode number
161170
pub fn scancode_from_name(&self, name: &Keycode) -> Option<u16> {
162171
match name {
172+
Keycode::MT(_, _) | Keycode::LT(_, _) if !self.meta.is_qmk => None,
163173
Keycode::MT(mods, keycode_name) => {
164174
let kc = *self.keymap.get(keycode_name)?;
165175
Some(QK_MOD_TAP | (mods.bits() << 8) | (kc & 0xff))
@@ -174,17 +184,26 @@ impl Layout {
174184
}
175185
Keycode::Basic(mods, keycode_name) => {
176186
if mods.is_empty() {
177-
self.keymap.get(keycode_name).copied()
178-
} else if let Some(mod_name) = mods.as_mod_str() {
179-
self.keymap.get(mod_name).copied()
180-
} else {
187+
return self.keymap.get(keycode_name).copied();
188+
} else if keycode_name == "NONE" {
189+
if let Some(mod_name) = mods.as_mod_str() {
190+
return self.keymap.get(mod_name).copied();
191+
}
192+
}
193+
if self.meta.is_qmk {
181194
let kc = *self.keymap.get(keycode_name)?;
182195
Some((mods.bits() << 8) | (kc & 0xff))
196+
} else {
197+
None
183198
}
184199
}
185200
}
186201
}
187202

203+
pub fn has_scancode(&self, scancode_name: &str) -> bool {
204+
self.keymap.get(scancode_name).is_some()
205+
}
206+
188207
pub fn f_keys(&self) -> impl Iterator<Item = &str> {
189208
self.default.map.iter().filter_map(|(k, v)| {
190209
if let Some(num) = v[0].strip_prefix('F') {

layouts/picker.json

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,30 +169,30 @@
169169
"keysym": "LEFT_ALT",
170170
"label": "Left Alt"
171171
},
172-
{
173-
"keysym": "RIGHT_ALT",
174-
"label": "Right Alt"
175-
},
176172
{
177173
"keysym": "LEFT_CTRL",
178174
"label": "Left Ctrl"
179175
},
180-
{
181-
"keysym": "RIGHT_CTRL",
182-
"label": "Right Ctrl"
183-
},
184176
{
185177
"keysym": "LEFT_SHIFT",
186178
"label": "Left Shift"
187179
},
188-
{
189-
"keysym": "RIGHT_SHIFT",
190-
"label": "Right Shift"
191-
},
192180
{
193181
"keysym": "LEFT_SUPER",
194182
"label": "Left Super"
195183
},
184+
{
185+
"keysym": "RIGHT_ALT",
186+
"label": "Right Alt"
187+
},
188+
{
189+
"keysym": "RIGHT_CTRL",
190+
"label": "Right Ctrl"
191+
},
192+
{
193+
"keysym": "RIGHT_SHIFT",
194+
"label": "Right Shift"
195+
},
196196
{
197197
"keysym": "RIGHT_SUPER",
198198
"label": "Right Super"

layouts/system76/launch_1/meta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"num_layers": 4,
66
"has_brightness": true,
77
"has_color": true,
8-
"has_mod_tap": true,
8+
"is_qmk": true,
99
"no_fn_f": true,
1010
"pressed_color": "#202020",
1111
"keyboard": "system76/launch_1"

layouts/system76/launch_2/meta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"num_layers": 4,
66
"has_brightness": true,
77
"has_color": true,
8-
"has_mod_tap": true,
8+
"is_qmk": true,
99
"no_fn_f": true,
1010
"pressed_color": "#202020",
1111
"keyboard": "system76/launch_2"

layouts/system76/launch_lite_1/meta.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"num_layers": 4,
66
"has_brightness": true,
77
"has_color": true,
8-
"has_mod_tap": true,
8+
"is_qmk": true,
99
"no_fn_f": true,
1010
"pressed_color": "#202020",
1111
"keyboard": "system76/launch_lite_1"

src/keyboard.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ impl Keyboard {
283283
}
284284
}
285285

286-
fn layout(&self) -> &Layout {
286+
pub fn layout(&self) -> &Layout {
287287
&self.inner().board.layout()
288288
}
289289

@@ -303,11 +303,6 @@ impl Keyboard {
303303
&self.inner().layer_stack
304304
}
305305

306-
// XXX
307-
pub fn has_scancode(&self, scancode_name: &Keycode) -> bool {
308-
self.layout().scancode_from_name(scancode_name).is_some()
309-
}
310-
311306
pub async fn keymap_set(&self, key_index: usize, layer: usize, scancode_name: &Keycode) {
312307
if let Err(err) = self.board().keys()[key_index]
313308
.set_scancode(layer, scancode_name)

src/keyboard_layer.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,36 @@ impl WidgetImpl for KeyboardLayerInner {
161161
cr.stroke().unwrap();
162162
}
163163

164-
// Draw label
165-
let text = widget.page().get_label(k);
166-
let layout = cascade! {
167-
widget.create_pango_layout(Some(&text));
168-
..set_width((w * pango::SCALE as f64) as i32);
169-
..set_alignment(pango::Alignment::Center);
170-
};
171-
let text_height = layout.pixel_size().1 as f64;
164+
// Draw labels, with line seperators if multiple
165+
let labels = widget.page().get_label(k);
166+
let layouts: Vec<_> = labels
167+
.iter()
168+
.map(|text| {
169+
cascade! {
170+
widget.create_pango_layout(Some(text));
171+
..set_width((w * pango::SCALE as f64) as i32);
172+
..set_alignment(pango::Alignment::Center);
173+
}
174+
})
175+
.collect();
176+
let total_height = layouts
177+
.iter()
178+
.map(|layout| layout.pixel_size().1 as f64)
179+
.sum::<f64>();
172180
cr.new_path();
173-
cr.move_to(x, y + (h - text_height) / 2.);
174181
cr.set_source_rgba(fg.0, fg.1, fg.2, text_alpha);
175-
pangocairo::show_layout(cr, &layout);
182+
cr.set_line_width(1.);
183+
cr.move_to(x, y + (h - total_height) / 2.);
184+
for (i, layout) in layouts.iter().enumerate() {
185+
pangocairo::show_layout(cr, &layout);
186+
if i < layouts.len() - 1 {
187+
let text_height = layout.pixel_size().1 as f64;
188+
cr.rel_move_to(0.0, text_height);
189+
cr.rel_line_to(w, 0.0);
190+
cr.rel_move_to(-w, 1.0);
191+
}
192+
}
193+
cr.stroke().unwrap();
176194
}
177195

178196
Inhibit(false)

0 commit comments

Comments
 (0)