Skip to content

Commit 5f3394a

Browse files
skarardclaude
andcommitted
Fix K8850 mouse binding format (native 17-byte mouse_data)
The 8850 uses a different mouse packet format than K884x. Confirmed via Frida capture of mini_keyboard.exe and PR kriomant#154 by yawor: - Position [5] starts mouse_data (not 0x00 padding like keyboard type) - Format: [1, 4, 0, 0, modifier, 0, 0, buttons, 0, 0, dx, 0, 0, dy, 0, 0, wheel] - Mouse modifier uses same firmware IDs (F1=Ctrl, F2=Shift, F3=Alt) - Button bitmap: 1=left, 2=right, 4=middle Hardware tested: clicks, scroll wheel, and mouse move all confirmed working. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent ef9d0e1 commit 5f3394a

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

src/keyboard/k8850.rs

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use anyhow::{ensure, Result};
44
use clap::Parser;
55
use nom::{IResult, branch::alt, bytes::complete::tag, character::complete::alpha1, combinator::{map, map_res, value}, sequence::preceded};
66

7-
use super::{Key, Keyboard, Macro, KeyboardEvent, Modifier, MouseEvent, MouseAction, send_message};
7+
use super::{Key, Keyboard, Macro, KeyboardEvent, Modifier, MouseEvent, MouseAction, MouseModifier, send_message};
88

99

1010
/// LED modes for the K8850 firmware (confirmed via hardware testing).
@@ -213,34 +213,37 @@ impl Keyboard for Keyboard8850 {
213213
msg.push(0x00); // [8]
214214
msg.push(low); // [9] consumer code
215215
}
216-
Macro::Mouse(MouseEvent(MouseAction::Move(dx, dy), modifier)) => {
217-
msg.push(0x00); // [6] binding_mode
218-
msg.push(0x00); // [7]
219-
msg.push(0x00); // [8]
220-
msg.push(0x00); // [9]
221-
msg.extend_from_slice(&[0x05, modifier.map_or(0, |m| m as u8), 0, *dx as u8, *dy as u8]);
222-
}
223-
Macro::Mouse(MouseEvent(MouseAction::Drag(buttons, dx, dy), modifier)) => {
224-
msg.push(0x00); // [6]
225-
msg.push(0x00); // [7]
226-
msg.push(0x00); // [8]
227-
msg.push(0x00); // [9]
228-
msg.extend_from_slice(&[0x05, modifier.map_or(0, |m| m as u8), buttons.as_u8(), *dx as u8, *dy as u8]);
229-
}
230-
Macro::Mouse(MouseEvent(MouseAction::Click(buttons), modifier)) => {
231-
ensure!(!buttons.is_empty(), "buttons must be given for click macro");
232-
msg.push(0x00); // [6]
233-
msg.push(0x00); // [7]
234-
msg.push(0x00); // [8]
235-
msg.push(0x00); // [9]
236-
msg.extend_from_slice(&[0x01, modifier.map_or(0, |m| m as u8), buttons.as_u8()]);
237-
}
238-
Macro::Mouse(MouseEvent(MouseAction::Wheel(delta), modifier)) => {
239-
msg.push(0x00); // [6]
240-
msg.push(0x00); // [7]
241-
msg.push(0x00); // [8]
242-
msg.push(0x00); // [9]
243-
msg.extend_from_slice(&[0x03, modifier.map_or(0, |m| m as u8), 0, 0, 0, *delta as u8]);
216+
Macro::Mouse(MouseEvent(action, modifier)) => {
217+
// 8850 mouse format (confirmed via Frida capture + PR #154 by yawor):
218+
// Position [5] in the full packet is the start of mouse_data (not 0x00 like keyboard).
219+
// Format: [1, 4, 0, 0, modifier, 0, 0, buttons, 0, 0, dx, 0, 0, dy, 0, 0, wheel]
220+
msg.pop(); // Remove the header's 0x00 at [5]; mouse_data provides its own bytes
221+
let mut mouse_data = [0u8; 17];
222+
mouse_data[0] = 1;
223+
mouse_data[1] = 4;
224+
mouse_data[4] = modifier.map_or(0, |m| mouse_modifier_firmware_id(m));
225+
226+
match action {
227+
MouseAction::Move(dx, dy) => {
228+
mouse_data[10] = *dx as u8;
229+
mouse_data[13] = *dy as u8;
230+
}
231+
MouseAction::Drag(buttons, dx, dy) => {
232+
eprintln!("warning: drag may not work correctly on 8850 firmware (button hold + move sent as separate actions)");
233+
mouse_data[7] = buttons.as_u8();
234+
mouse_data[10] = *dx as u8;
235+
mouse_data[13] = *dy as u8;
236+
}
237+
MouseAction::Click(buttons) => {
238+
ensure!(!buttons.is_empty(), "buttons must be given for click macro");
239+
mouse_data[7] = buttons.as_u8();
240+
}
241+
MouseAction::Wheel(delta) => {
242+
mouse_data[16] = *delta as u8;
243+
}
244+
}
245+
246+
msg.extend_from_slice(&mouse_data);
244247
}
245248
};
246249

@@ -311,6 +314,15 @@ fn modifier_firmware_id(m: Modifier) -> u8 {
311314
}
312315
}
313316

317+
/// Map a MouseModifier to the 8850 firmware's modifier ID.
318+
fn mouse_modifier_firmware_id(m: MouseModifier) -> u8 {
319+
match m {
320+
MouseModifier::Ctrl => 0xF1,
321+
MouseModifier::Shift => 0xF2,
322+
MouseModifier::Alt => 0xF3,
323+
}
324+
}
325+
314326
impl Keyboard8850 {
315327
pub fn new(buttons: u8, knobs: u8) -> Result<Self> {
316328
ensure!(buttons <= 16 && knobs <= 3, "8850 supports up to 16 buttons and 3 knobs");

0 commit comments

Comments
 (0)