use crate::context::AppContext; use crate::protocol::{self as protocol, keycode}; use crate::models; use crate::{ AdvancedBridge, AppState, KeySelectorBridge, KeymapBridge, MainWindow, }; use slint::{ComponentHandle, Model, SharedString}; use std::rc::Rc; pub fn setup(window: &MainWindow, ctx: &AppContext) { setup_filter(window); let apply_keycode = build_apply_keycode(window, ctx); let refresh_macro_display = crate::macros::make_refresh_display(window, ctx); let dispatch_keycode = build_dispatch_keycode(window, ctx, apply_keycode, refresh_macro_display); setup_callbacks(window, dispatch_keycode); } fn setup_filter(window: &MainWindow) { let all_keys = models::build_key_entries(); let window_weak = window.as_weak(); window.global::().on_apply_filter(move |search| { if let Some(w) = window_weak.upgrade() { models::populate_key_categories(&w, &all_keys, &search); } }); } fn build_apply_keycode(window: &MainWindow, ctx: &AppContext) -> Rc { let serial = ctx.serial.clone(); let keys_arc = ctx.keys.clone(); let current_keymap = ctx.current_keymap.clone(); let current_layer = ctx.current_layer.clone(); let keyboard_layout = ctx.keyboard_layout.clone(); let window_weak = window.as_weak(); Rc::new(move |code: u16| { let Some(w) = window_weak.upgrade() else { return }; let key_idx = w.global::().get_selected_key_index(); if key_idx < 0 { return; } let key_idx = key_idx as usize; let keys = keys_arc.borrow(); if key_idx >= keys.len() { return; } let kp = &keys[key_idx]; let row = kp.row; let col = kp.col; drop(keys); let layer = current_layer.get() as u8; { let mut km = current_keymap.borrow_mut(); if row < km.len() && col < km[row].len() { km[row][col] = code; } } let layout = *keyboard_layout.borrow(); let km = current_keymap.borrow().clone(); let keys = keys_arc.borrow().clone(); let keycaps = w.global::().get_keycaps(); models::update_keycap_labels(&keycaps, &keys, &km, &layout); let payload = protocol::binary::setkey_payload(layer, row as u8, col as u8, code); let serial = serial.clone(); std::thread::spawn(move || { let mut ser = serial.lock().unwrap_or_else(|e| e.into_inner()); let _ = ser.send_binary(protocol::binary::cmd::SETKEY, &payload); }); w.global::().set_status_text( SharedString::from(format!("[{},{}] = 0x{:04X}", row, col, code)) ); }) } fn build_dispatch_keycode( window: &MainWindow, ctx: &AppContext, apply_keycode: Rc, refresh_macro_display: Rc, ) -> Rc { let keys_arc = ctx.keys.clone(); let serial = ctx.serial.clone(); let macro_steps = ctx.macro_steps.clone(); let window_weak = window.as_weak(); Rc::new(move |code: u16| { let Some(w) = window_weak.upgrade() else { return }; let target = w.global::().get_selector_target(); let name = SharedString::from(keycode::decode_keycode(code)); match target.as_str() { "keymap" => { apply_keycode(code); } "combo-result" => { let adv = w.global::(); adv.set_new_combo_result_code(code as i32); adv.set_new_combo_result_name(name); } "ko-trigger" => { let adv = w.global::(); adv.set_new_ko_trigger_code(code as i32); adv.set_new_ko_trigger_name(name); } "ko-result" => { let adv = w.global::(); adv.set_new_ko_result_code(code as i32); adv.set_new_ko_result_name(name); } "leader-result" => { let adv = w.global::(); adv.set_new_leader_result_code(code as i32); adv.set_new_leader_result_name(name); } "combo-key1" | "combo-key2" => { let keys = keys_arc.borrow(); let idx = code as usize; if idx < keys.len() { let kp = &keys[idx]; let adv = w.global::(); let label = SharedString::from(format!("R{}C{}", kp.row, kp.col)); if target.as_str() == "combo-key1" { adv.set_new_combo_r1(kp.row as i32); adv.set_new_combo_c1(kp.col as i32); adv.set_new_combo_key1_name(label); } else { adv.set_new_combo_r2(kp.row as i32); adv.set_new_combo_c2(kp.col as i32); adv.set_new_combo_key2_name(label); } } } "leader-seq" => { let adv = w.global::(); let count = adv.get_new_leader_seq_count(); match count { 0 => { adv.set_new_leader_seq0_code(code as i32); adv.set_new_leader_seq0_name(name); } 1 => { adv.set_new_leader_seq1_code(code as i32); adv.set_new_leader_seq1_name(name); } 2 => { adv.set_new_leader_seq2_code(code as i32); adv.set_new_leader_seq2_name(name); } 3 => { adv.set_new_leader_seq3_code(code as i32); adv.set_new_leader_seq3_name(name); } _ => {} } if count < 4 { adv.set_new_leader_seq_count(count + 1); } } "td-action" => { let adv = w.global::(); let td_idx = adv.get_editing_td_index(); let slot = adv.get_editing_td_slot() as usize; if td_idx >= 0 && slot < 4 { let tds = adv.get_tap_dances(); for i in 0..tds.row_count() { let td = tds.row_data(i).unwrap(); if td.index == td_idx { let actions = td.actions; let mut a = actions.row_data(slot).unwrap(); a.name = name.clone(); a.code = code as i32; actions.set_row_data(slot, a); let mut codes = [0u16; 4]; for (j, code) in codes.iter_mut().enumerate().take(4.min(actions.row_count())) { *code = actions.row_data(j).unwrap().code as u16; } let payload = protocol::binary::td_set_payload(td_idx as u8, &codes); let serial = serial.clone(); std::thread::spawn(move || { let mut ser = serial.lock().unwrap_or_else(|e| e.into_inner()); let _ = ser.send_binary(protocol::binary::cmd::TD_SET, &payload); }); w.global::().set_status_text( SharedString::from(format!("TD{} slot {} = {}", td_idx, slot, name)) ); break; } } } } "macro-step" => { let mut steps = macro_steps.borrow_mut(); steps.push((code as u8, 0x00)); drop(steps); refresh_macro_display(); } _ => { apply_keycode(code); } } }) } fn setup_callbacks(window: &MainWindow, dispatch_keycode: Rc) { { let dispatch = dispatch_keycode.clone(); window.global::().on_select_keycode(move |code| { dispatch(code as u16); }); } { let dispatch = dispatch_keycode.clone(); window.global::().on_apply_hex(move |hex_str| { if let Ok(code) = u16::from_str_radix(hex_str.trim(), 16) { dispatch(code); } }); } { let window_weak = window.as_weak(); window.global::().on_preview_hex(move |hex_str| { let preview = u16::from_str_radix(hex_str.trim(), 16) .map(keycode::decode_keycode) .unwrap_or_default(); if let Some(w) = window_weak.upgrade() { w.global::().set_hex_preview(SharedString::from(preview)); } }); } { let dispatch = dispatch_keycode.clone(); window.global::().on_apply_mt(move |mod_idx, key_idx| { let mod_nibble: u16 = match mod_idx { 0 => 0x01, 1 => 0x02, 2 => 0x04, 3 => 0x08, 4 => 0x10, 5 => 0x20, 6 => 0x40, 7 => 0x80, _ => 0x02, }; let hid: u16 = match key_idx { 0..=25 => 0x04 + key_idx as u16, 26..=35 => 0x1E + (key_idx - 26) as u16, 36 => 0x2C, 37 => 0x28, 38 => 0x29, 39 => 0x2B, 40 => 0x2A, _ => 0x04, }; let code = 0x5000 | (mod_nibble << 8) | hid; dispatch(code); }); } { let dispatch = dispatch_keycode.clone(); window.global::().on_apply_lt(move |layer_idx, key_idx| { let layer = (layer_idx as u16) & 0x0F; let hid: u16 = match key_idx { 0 => 0x2C, 1 => 0x28, 2 => 0x29, 3 => 0x2A, 4 => 0x2B, 5..=9 => 0x04 + (key_idx - 5) as u16, _ => 0x2C, }; let code = 0x4000 | (layer << 8) | hid; dispatch(code); }); } }