Skip to content

Commit 45ad56c

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 45ad56c

File tree

1 file changed

+40
-29
lines changed

1 file changed

+40
-29
lines changed

src/keyboard/k8850.rs

Lines changed: 40 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,36 @@ 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+
mouse_data[7] = buttons.as_u8();
233+
mouse_data[10] = *dx as u8;
234+
mouse_data[13] = *dy as u8;
235+
}
236+
MouseAction::Click(buttons) => {
237+
ensure!(!buttons.is_empty(), "buttons must be given for click macro");
238+
mouse_data[7] = buttons.as_u8();
239+
}
240+
MouseAction::Wheel(delta) => {
241+
mouse_data[16] = *delta as u8;
242+
}
243+
}
244+
245+
msg.extend_from_slice(&mouse_data);
244246
}
245247
};
246248

@@ -311,6 +313,15 @@ fn modifier_firmware_id(m: Modifier) -> u8 {
311313
}
312314
}
313315

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

0 commit comments

Comments
 (0)