Skip to content

Commit

Permalink
Merge pull request #147 from pcasotti/feat/tri-layer
Browse files Browse the repository at this point in the history
Tri Layer support
  • Loading branch information
HaoboGu authored Nov 18, 2024
2 parents 52d0855 + 52a6a84 commit f3d2c89
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 6 deletions.
29 changes: 29 additions & 0 deletions docs/src/keyboard_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,30 @@ The key string should follow several rules:

The definitions of those operations are same with QMK, you can found [here](https://docs.qmk.fm/#/feature_layers). If you want other actions, please [fire an issue](https://github.com/HaoboGu/rmk/issues/new).


### `[behavior]`

`[behavior]` section contains configuration for how different keyboard actions should behave:

```toml
[behavior]
tri_layer = { uppper = 1, lower = 2, adjust = 3 }
```

#### Tri Layer

`Tri Layer` works by enabling a layer (called `adjust`) when other two layers (`upper` and `lower`) are both enabled.

You can enable Tri Layer by specifying the `upper`, `lower` and `adjust` layers in the `tri_layer` sub-table:

```toml
[behavior.tri_layer]
uppper = 1
lower = 2
adjust = 3
```
In this example, when both layers 1 (`upper`) and 2 (`lower`) are active, layer 3 (`adjust`) will also be enabled.

### `[light]`

`[light]` section defines lights of the keyboard, aka `capslock`, `scrolllock` and `numslock`. They are actually an input pin, so there are two fields available: `pin` and `low_active`.
Expand Down Expand Up @@ -290,6 +314,11 @@ keymap = [
],
]

# Behavior configuration, if you don't want to customize anything, just ignore this section.
[behavior]
# Tri Layer configuration.
tri_layer = { uppper = 1, lower = 2, adjust = 3 }

# Lighting configuration, if you don't have any light, just ignore this section.
[light]
# LED pins, capslock, scrolllock, numslock. You can safely ignore any of them if you don't have
Expand Down
8 changes: 8 additions & 0 deletions rmk-config/src/keyboard_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct RmkConfig<'a, O: OutputPin> {
pub vial_config: VialConfig<'a>,
pub light_config: LightConfig<O>,
pub storage_config: StorageConfig,
pub behavior_config: BehaviorConfig,
#[cfg(feature = "_nrf_ble")]
pub ble_battery_config: BleBatteryConfig<'a>,
#[cfg(feature = "_esp_ble")]
Expand All @@ -31,12 +32,19 @@ impl<'a, O: OutputPin> Default for RmkConfig<'a, O> {
vial_config: VialConfig::default(),
light_config: LightConfig::default(),
storage_config: StorageConfig::default(),
behavior_config: BehaviorConfig::default(),
#[cfg(any(feature = "_nrf_ble", feature = "_esp_ble"))]
ble_battery_config: BleBatteryConfig::default(),
}
}
}

/// Config for configurable action behavior
#[derive(Default)]
pub struct BehaviorConfig {
pub tri_layer: Option<[u8; 3]>,
}

/// Config for storage
#[derive(Clone, Copy, Debug)]
pub struct StorageConfig {
Expand Down
16 changes: 16 additions & 0 deletions rmk-config/src/toml_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ pub struct KeyboardTomlConfig {
/// Layout config.
/// For split keyboard, the total row/col should be defined in this section
pub layout: LayoutConfig,
/// Behavior config
pub behavior: Option<BehaviorConfig>,
/// Light config
pub light: Option<LightConfig>,
/// Storage config
Expand Down Expand Up @@ -124,6 +126,20 @@ pub struct LayoutConfig {
pub keymap: Vec<Vec<Vec<String>>>,
}

/// Configurations for actions behavior
#[derive(Clone, Debug, Default, Deserialize)]
pub struct BehaviorConfig {
pub tri_layer: Option<TriLayerConfig>,
}

/// Configurations for tri layer
#[derive(Clone, Debug, Deserialize)]
pub struct TriLayerConfig {
pub upper: u8,
pub lower: u8,
pub adjust: u8,
}

/// Configurations for split keyboards
#[derive(Clone, Debug, Default, Deserialize)]
pub struct SplitConfig {
Expand Down
29 changes: 29 additions & 0 deletions rmk-macro/src/behavior.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//! Initialize behavior config boilerplate of RMK
//!
use quote::quote;
use rmk_config::toml_config::TriLayerConfig;

use crate::keyboard_config::KeyboardConfig;

fn expand_tri_layer(tri_layer: &Option<TriLayerConfig>) -> proc_macro2::TokenStream {
match tri_layer {
Some(tri_layer) => {
let upper = tri_layer.upper;
let lower = tri_layer.lower;
let adjust = tri_layer.adjust;
quote! {::core::option::Option::Some([#upper, #lower, #adjust])}
}
None => quote! {::core::option::Option::None::<[u8; 3]>},
}
}

pub(crate) fn expand_behavior_config(keyboard_config: &KeyboardConfig) -> proc_macro2::TokenStream {
let tri_layer = expand_tri_layer(&keyboard_config.behavior.tri_layer);

quote! {
let behavior_config = ::rmk::config::keyboard_config::BehaviorConfig {
tri_layer: #tri_layer,
};
}
}
6 changes: 6 additions & 0 deletions rmk-macro/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use quote::quote;
use syn::ItemMod;

use crate::{
behavior::expand_behavior_config,
bind_interrupt::expand_bind_interrupt,
ble::expand_ble_config,
chip_init::expand_chip_init,
Expand Down Expand Up @@ -115,6 +116,7 @@ fn expand_main(
let usb_init = expand_usb_init(keyboard_config, &item_mod);
let flash_init = expand_flash_init(keyboard_config);
let light_config = expand_light_config(keyboard_config);
let behavior_config = expand_behavior_config(keyboard_config);
let matrix_config = expand_matrix_config(keyboard_config, async_matrix);
let run_rmk = expand_rmk_entry(keyboard_config, &item_mod);
let (ble_config, set_ble_config) = expand_ble_config(keyboard_config);
Expand Down Expand Up @@ -151,6 +153,9 @@ fn expand_main(
// Initialize light config as `light_config`
#light_config

// Initialize behavior config config as `behavior_config`
#behavior_config

// Initialize matrix config as `(input_pins, output_pins)` or `direct_pins`
#matrix_config

Expand All @@ -162,6 +167,7 @@ fn expand_main(
vial_config: VIAL_CONFIG,
light_config,
storage_config,
behavior_config,
#set_ble_config
..Default::default()
};
Expand Down
44 changes: 42 additions & 2 deletions rmk-macro/src/keyboard_config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rmk_config::toml_config::{
BleConfig, DependencyConfig, KeyboardInfo, KeyboardTomlConfig, LayoutConfig, LightConfig,
MatrixConfig, MatrixType, SplitConfig, StorageConfig,
BehaviorConfig, BleConfig, DependencyConfig, KeyboardInfo, KeyboardTomlConfig, LayoutConfig,
LightConfig, MatrixConfig, MatrixType, SplitConfig, StorageConfig,
};
use serde::Deserialize;
use std::fs;
Expand Down Expand Up @@ -71,6 +71,8 @@ pub(crate) struct KeyboardConfig {
pub(crate) board: BoardConfig,
// Layout config
pub(crate) layout: LayoutConfig,
// Begavior Config
pub(crate) behavior: BehaviorConfig,
// Light config
pub(crate) light: LightConfig,
// Storage config
Expand Down Expand Up @@ -164,6 +166,10 @@ impl KeyboardConfig {
// Layout config
config.layout = Self::get_layout_from_toml(toml_config.layout)?;

// Behavior config
config.behavior =
Self::get_behavior_from_toml(config.behavior, toml_config.behavior, &config.layout)?;

// Light config
config.light = Self::get_light_from_toml(config.light, toml_config.light);

Expand Down Expand Up @@ -404,6 +410,40 @@ impl KeyboardConfig {
Ok(layout)
}

fn get_behavior_from_toml(
default: BehaviorConfig,
toml: Option<BehaviorConfig>,
layout: &LayoutConfig,
) -> Result<BehaviorConfig, TokenStream2> {
match toml {
Some(mut behavior) => {
// Use default setting if the corresponding field is not set
behavior.tri_layer = match behavior.tri_layer {
Some(tri_layer) => {
if tri_layer.upper >= layout.layers {
return rmk_compile_error!(
"keyboard.toml: Tri layer upper is larger than [layout.layers]"
);
} else if tri_layer.lower >= layout.layers {
return rmk_compile_error!(
"keyboard.toml: Tri layer lower is larger than [layout.layers]"
);
} else if tri_layer.adjust >= layout.layers {
return rmk_compile_error!(
"keyboard.toml: Tri layer adjust is larger than [layout.layers]"
);
}
Some(tri_layer)
}
None => default.tri_layer,
};

Ok(behavior)
}
None => Ok(default),
}
}

fn get_light_from_toml(default: LightConfig, toml: Option<LightConfig>) -> LightConfig {
match toml {
Some(mut light_config) => {
Expand Down
1 change: 1 addition & 0 deletions rmk-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod behavior;
mod bind_interrupt;
mod ble;
mod chip_init;
Expand Down
6 changes: 6 additions & 0 deletions rmk-macro/src/split/central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rmk_config::toml_config::{SerialConfig, SplitConfig};
use syn::ItemMod;

use crate::{
behavior::expand_behavior_config,
bind_interrupt::expand_bind_interrupt,
ble::expand_ble_config,
chip_init::expand_chip_init,
Expand Down Expand Up @@ -74,6 +75,7 @@ fn expand_split_central(
let usb_init = expand_usb_init(keyboard_config, &item_mod);
let flash_init = expand_flash_init(keyboard_config);
let light_config = expand_light_config(keyboard_config);
let behavior_config = expand_behavior_config(keyboard_config);

let matrix_config = expand_matrix_input_output_pins(
&keyboard_config.chip,
Expand Down Expand Up @@ -118,6 +120,9 @@ fn expand_split_central(
// Initialize light config as `light_config`
#light_config

// Initialize behavior config config as `behavior_config`
#behavior_config

// Initialize matrix config as `(input_pins, output_pins)`
#matrix_config

Expand All @@ -130,6 +135,7 @@ fn expand_split_central(
vial_config: VIAL_CONFIG,
light_config,
storage_config,
behavior_config,
#set_ble_config
..Default::default()
};
Expand Down
6 changes: 5 additions & 1 deletion rmk/src/ble/esp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ pub(crate) async fn initialize_esp_ble_keyboard_with_config_and_run<
let keyboard_report_sender = keyboard_report_channel.sender();
let keyboard_report_receiver = keyboard_report_channel.receiver();

let mut keyboard = Keyboard::new(&keymap, &keyboard_report_sender);
let mut keyboard = Keyboard::new(
&keymap,
&keyboard_report_sender,
keyboard_config.behavior_config,
);
// esp32c3 doesn't have USB device, so there is no usb here
// TODO: add usb service for other chips of esp32 which have USB device

Expand Down
6 changes: 5 additions & 1 deletion rmk/src/ble/nrf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,11 @@ pub(crate) async fn initialize_nrf_ble_keyboard_and_run<
let keyboard_report_receiver = keyboard_report_channel.receiver();

// Keyboard services
let mut keyboard = Keyboard::new(&keymap, &keyboard_report_sender);
let mut keyboard = Keyboard::new(
&keymap,
&keyboard_report_sender,
keyboard_config.behavior_config,
);
#[cfg(not(feature = "_no_usb"))]
let mut usb_device = KeyboardUsbDevice::new(usb_driver, keyboard_config.usb_config);
let mut vial_service = VialService::new(&keymap, keyboard_config.vial_config);
Expand Down
11 changes: 11 additions & 0 deletions rmk/src/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use embassy_sync::{
use embassy_time::{Instant, Timer};
use heapless::{FnvIndexMap, Vec};
use postcard::experimental::max_size::MaxSize;
use rmk_config::BehaviorConfig;
use serde::{Deserialize, Serialize};
use usbd_hid::descriptor::KeyboardReport;

Expand Down Expand Up @@ -131,6 +132,9 @@ pub(crate) struct Keyboard<'a, const ROW: usize, const COL: usize, const NUM_LAY
/// Timer which records the timestamp of key changes
pub(crate) timer: [[Option<Instant>; ROW]; COL],

/// Options for configurable action behavior
behavior: BehaviorConfig,

/// One shot modifier state
osm_state: OneShotState<ModifierCombination>,

Expand Down Expand Up @@ -163,11 +167,13 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
pub(crate) fn new(
keymap: &'a RefCell<KeyMap<'a, ROW, COL, NUM_LAYER>>,
sender: &'a Sender<'a, CriticalSectionRawMutex, KeyboardReportMessage, REPORT_CHANNEL_SIZE>,
behavior: BehaviorConfig,
) -> Self {
Keyboard {
keymap,
sender,
timer: [[None; ROW]; COL],
behavior,
osm_state: OneShotState::default(),
osl_state: OneShotState::default(),
unprocessed_events: Vec::new(),
Expand Down Expand Up @@ -294,6 +300,11 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
.await;
}
}

// Tri Layer
if let Some(ref tri_layer) = self.behavior.tri_layer {
self.keymap.borrow_mut().update_tri_layer(tri_layer);
}
}

async fn update_osm(&mut self, key_event: KeyEvent) {
Expand Down
6 changes: 6 additions & 0 deletions rmk/src/keymap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ impl<'a, const ROW: usize, const COL: usize, const NUM_LAYER: usize>
self.layer_cache[row][col] = layer_num;
}

/// Update given Tri Layer state
pub(crate) fn update_tri_layer(&mut self, tri_layer: &[u8; 3]) {
self.layer_state[tri_layer[2] as usize] =
self.layer_state[tri_layer[0] as usize] && self.layer_state[tri_layer[1] as usize];
}

/// Activate given layer
pub(crate) fn activate_layer(&mut self, layer_num: u8) {
if layer_num as usize >= NUM_LAYER {
Expand Down
6 changes: 5 additions & 1 deletion rmk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ pub(crate) async fn initialize_usb_keyboard_and_run<

// Create keyboard services and devices
let (mut keyboard, mut usb_device, mut vial_service, mut light_service) = (
Keyboard::new(&keymap, &keyboard_report_sender),
Keyboard::new(
&keymap,
&keyboard_report_sender,
keyboard_config.behavior_config,
),
KeyboardUsbDevice::new(usb_driver, keyboard_config.usb_config),
VialService::new(&keymap, keyboard_config.vial_config),
LightService::from_config(keyboard_config.light_config),
Expand Down
6 changes: 5 additions & 1 deletion rmk/src/split/central.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,11 @@ pub(crate) async fn initialize_usb_split_central_and_run<

// Create keyboard services and devices
let (mut keyboard, mut usb_device, mut vial_service, mut light_service) = (
Keyboard::new(&keymap, &keyboard_report_sender),
Keyboard::new(
&keymap,
&keyboard_report_sender,
keyboard_config.behavior_config,
),
KeyboardUsbDevice::new(usb_driver, keyboard_config.usb_config),
VialService::new(&keymap, keyboard_config.vial_config),
LightService::from_config(keyboard_config.light_config),
Expand Down

0 comments on commit f3d2c89

Please sign in to comment.