basic_example/
basic_example.rs1use std::error::Error;
2use std::io::{Read, Write};
3use std::process::ExitCode;
4
5#[cfg(feature = "ble")]
6use zmk_studio_api::transport::ble::BleTransport;
7#[cfg(feature = "serial")]
8use zmk_studio_api::transport::serial::SerialTransport;
9use zmk_studio_api::{Behavior, ClientError, HidUsage, Keycode, StudioClient};
10
11fn main() -> ExitCode {
12 match run() {
13 Ok(()) => ExitCode::SUCCESS,
14 Err(err) => {
15 eprintln!("error: {err}");
16 ExitCode::from(1)
17 }
18 }
19}
20
21fn run() -> Result<(), Box<dyn Error>> {
22 let mut args = std::env::args().skip(1);
23 let Some(mode) = args.next() else {
24 print_usage();
25 return Ok(());
26 };
27
28 match mode.as_str() {
29 "serial" => {
30 #[cfg(feature = "serial")]
31 {
32 let Some(port) = args.next() else {
33 print_usage();
34 return Ok(());
35 };
36 let client = StudioClient::new(SerialTransport::open(&port)?);
37 run_example(client)
38 }
39 #[cfg(not(feature = "serial"))]
40 {
41 Err("built without `serial` feature".into())
42 }
43 }
44 "ble" => {
45 #[cfg(feature = "ble")]
46 {
47 let Some(device_id) = args.next() else {
48 print_usage();
49 return Ok(());
50 };
51 let client = StudioClient::new(BleTransport::connect_device(&device_id)?);
52 run_example(client)
53 }
54 #[cfg(not(feature = "ble"))]
55 {
56 Err("built without `ble` feature".into())
57 }
58 }
59 _ => {
60 print_usage();
61 Ok(())
62 }
63 }
64}
65
66fn run_example<T: Read + Write>(mut client: StudioClient<T>) -> Result<(), Box<dyn Error>> {
67 let info = client.get_device_info()?;
68 println!("Device: {}", info.name);
69 println!("Lock: {:?}", client.get_lock_state()?);
70
71 let behavior_ids = client.list_all_behaviors()?;
72 println!("Behavior count: {}", behavior_ids.len());
73 if let Some(first_behavior_id) = behavior_ids.first().copied() {
74 let details = client.get_behavior_details(first_behavior_id)?;
75 println!("First behavior: {} ({})", details.id, details.display_name);
76 }
77
78 let keymap = match client.get_keymap() {
79 Ok(keymap) => keymap,
80 Err(ClientError::Meta(_)) => {
81 println!("Keymap request denied (likely locked); press `&studio_unlock` then rerun.");
82 return Ok(());
83 }
84 Err(err) => return Err(Box::new(err)),
85 };
86 println!("Layers: {}", keymap.layers.len());
87
88 let layouts = client.get_physical_layouts()?;
89 println!(
90 "Physical layouts: {} (active index: {})",
91 layouts.layouts.len(),
92 layouts.active_layout_index
93 );
94
95 let Some(first_layer) = keymap.layers.first() else {
96 return Ok(());
97 };
98 if first_layer.bindings.is_empty() {
99 return Ok(());
100 }
101
102 let layer_id = first_layer.id;
103 let key_position = 0;
104
105 let before = client.get_key_at(layer_id, key_position)?;
106 println!("Before: {before:?}");
107
108 client.set_key_at(
109 layer_id,
110 key_position,
111 Behavior::KeyPress(HidUsage::from_encoded(Keycode::A.to_hid_usage())),
112 )?;
113 let after = client.get_key_at(layer_id, key_position)?;
114 println!("After: {after:?}");
115
116 let has_changes = client.check_unsaved_changes()?;
118 println!("Unsaved changes: {has_changes}");
119 if has_changes {
120 client.discard_changes()?;
121 }
122
123 Ok(())
124}
125
126fn print_usage() {
127 println!("Usage:");
128 println!(" cargo run --example basic_example -- serial <PORT>");
129 println!(" cargo run --example basic_example --features ble -- ble <DEVICE_ID>");
130}