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