mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-06-14 03:32:00 +08:00
fix: 优化 RustDesk 中继服务器推导策略;修复鼠键输入异常
This commit is contained in:
@@ -27,7 +27,7 @@ use super::bytes_codec::{read_frame, write_frame, write_frame_buffered};
|
|||||||
use super::config::RustDeskConfig;
|
use super::config::RustDeskConfig;
|
||||||
use super::crypto::{self, KeyPair, SigningKeyPair};
|
use super::crypto::{self, KeyPair, SigningKeyPair};
|
||||||
use super::frame_adapters::{AudioFrameAdapter, VideoCodec, VideoFrameAdapter};
|
use super::frame_adapters::{AudioFrameAdapter, VideoCodec, VideoFrameAdapter};
|
||||||
use super::hid_adapter::{convert_key_event, convert_mouse_event, mouse_type};
|
use super::hid_adapter::{convert_key_events, convert_mouse_event, mouse_type};
|
||||||
use super::protocol::{
|
use super::protocol::{
|
||||||
decode_message, login_response, message, misc, Clipboard, ControlKey, DisplayInfo, Hash,
|
decode_message, login_response, message, misc, Clipboard, ControlKey, DisplayInfo, Hash,
|
||||||
HbbMessage, IdPk, KeyEvent, LoginRequest, LoginResponse, Misc, MouseEvent, OptionMessage,
|
HbbMessage, IdPk, KeyEvent, LoginRequest, LoginResponse, Misc, MouseEvent, OptionMessage,
|
||||||
@@ -1331,18 +1331,21 @@ impl Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert RustDesk key event to One-KVM key event
|
// Convert RustDesk key event to One-KVM key events
|
||||||
if let Some(kb_event) = convert_key_event(ke) {
|
let kb_events = convert_key_events(ke);
|
||||||
debug!(
|
if !kb_events.is_empty() {
|
||||||
"Converted to HID: key=0x{:02X}, event_type={:?}, modifiers={:02X}",
|
|
||||||
kb_event.key.to_hid_usage(),
|
|
||||||
kb_event.event_type,
|
|
||||||
kb_event.modifiers.to_hid_byte()
|
|
||||||
);
|
|
||||||
// Send to HID controller if available
|
|
||||||
if let Some(ref hid) = self.hid {
|
if let Some(ref hid) = self.hid {
|
||||||
if let Err(e) = hid.send_keyboard(kb_event).await {
|
for kb_event in kb_events {
|
||||||
warn!("Failed to send keyboard event: {}", e);
|
debug!(
|
||||||
|
"Converted to HID: key=0x{:02X}, event_type={:?}, modifiers={:02X}",
|
||||||
|
kb_event.key.to_hid_usage(),
|
||||||
|
kb_event.event_type,
|
||||||
|
kb_event.modifiers.to_hid_byte()
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Err(e) = hid.send_keyboard(kb_event).await {
|
||||||
|
warn!("Failed to send keyboard event: {}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
debug!("HID controller not available, skipping key event");
|
debug!("HID controller not available, skipping key event");
|
||||||
@@ -1381,12 +1384,7 @@ impl Connection {
|
|||||||
debug!("Mouse event: x={}, y={}, mask={}", me.x, me.y, me.mask);
|
debug!("Mouse event: x={}, y={}, mask={}", me.x, me.y, me.mask);
|
||||||
|
|
||||||
// Convert RustDesk mouse event to One-KVM mouse events
|
// Convert RustDesk mouse event to One-KVM mouse events
|
||||||
let mouse_events = convert_mouse_event(
|
let mouse_events = convert_mouse_event(me, self.screen_width, self.screen_height);
|
||||||
me,
|
|
||||||
self.screen_width,
|
|
||||||
self.screen_height,
|
|
||||||
self.relative_mouse_active,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Send to HID controller if available
|
// Send to HID controller if available
|
||||||
if let Some(ref hid) = self.hid {
|
if let Some(ref hid) = self.hid {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use super::protocol::hbb::message::key_event as ke_union;
|
use super::protocol::hbb::message::key_event as ke_union;
|
||||||
use super::protocol::{ControlKey, KeyEvent, MouseEvent};
|
use super::protocol::{ControlKey, KeyEvent, KeyboardMode, MouseEvent};
|
||||||
use crate::hid::{
|
use crate::hid::{
|
||||||
CanonicalKey, KeyEventType, KeyboardEvent, KeyboardModifiers, MouseButton,
|
CanonicalKey, KeyEventType, KeyboardEvent, KeyboardModifiers, MouseButton,
|
||||||
MouseEvent as OneKvmMouseEvent, MouseEventType,
|
MouseEvent as OneKvmMouseEvent, MouseEventType,
|
||||||
@@ -27,13 +27,11 @@ pub fn convert_mouse_event(
|
|||||||
event: &MouseEvent,
|
event: &MouseEvent,
|
||||||
screen_width: u32,
|
screen_width: u32,
|
||||||
screen_height: u32,
|
screen_height: u32,
|
||||||
relative_mode: bool,
|
|
||||||
) -> Vec<OneKvmMouseEvent> {
|
) -> Vec<OneKvmMouseEvent> {
|
||||||
let mut events = Vec::new();
|
let mut events = Vec::new();
|
||||||
|
|
||||||
let event_type = event.mask & 0x07;
|
let event_type = event.mask & 0x07;
|
||||||
let button_id = event.mask >> 3;
|
let button_id = event.mask >> 3;
|
||||||
let include_abs_move = !relative_mode;
|
|
||||||
|
|
||||||
match event_type {
|
match event_type {
|
||||||
mouse_type::MOVE => {
|
mouse_type::MOVE => {
|
||||||
@@ -61,20 +59,6 @@ pub fn convert_mouse_event(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
mouse_type::DOWN => {
|
mouse_type::DOWN => {
|
||||||
if include_abs_move {
|
|
||||||
let x = event.x.max(0) as u32;
|
|
||||||
let y = event.y.max(0) as u32;
|
|
||||||
let abs_x = ((x as u64 * 32767) / screen_width.max(1) as u64) as i32;
|
|
||||||
let abs_y = ((y as u64 * 32767) / screen_height.max(1) as u64) as i32;
|
|
||||||
events.push(OneKvmMouseEvent {
|
|
||||||
event_type: MouseEventType::MoveAbs,
|
|
||||||
x: abs_x,
|
|
||||||
y: abs_y,
|
|
||||||
button: None,
|
|
||||||
scroll: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(button) = button_id_to_button(button_id) {
|
if let Some(button) = button_id_to_button(button_id) {
|
||||||
events.push(OneKvmMouseEvent {
|
events.push(OneKvmMouseEvent {
|
||||||
event_type: MouseEventType::Down,
|
event_type: MouseEventType::Down,
|
||||||
@@ -86,20 +70,6 @@ pub fn convert_mouse_event(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse_type::UP => {
|
mouse_type::UP => {
|
||||||
if include_abs_move {
|
|
||||||
let x = event.x.max(0) as u32;
|
|
||||||
let y = event.y.max(0) as u32;
|
|
||||||
let abs_x = ((x as u64 * 32767) / screen_width.max(1) as u64) as i32;
|
|
||||||
let abs_y = ((y as u64 * 32767) / screen_height.max(1) as u64) as i32;
|
|
||||||
events.push(OneKvmMouseEvent {
|
|
||||||
event_type: MouseEventType::MoveAbs,
|
|
||||||
x: abs_x,
|
|
||||||
y: abs_y,
|
|
||||||
button: None,
|
|
||||||
scroll: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(button) = button_id_to_button(button_id) {
|
if let Some(button) = button_id_to_button(button_id) {
|
||||||
events.push(OneKvmMouseEvent {
|
events.push(OneKvmMouseEvent {
|
||||||
event_type: MouseEventType::Up,
|
event_type: MouseEventType::Up,
|
||||||
@@ -111,20 +81,6 @@ pub fn convert_mouse_event(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse_type::WHEEL => {
|
mouse_type::WHEEL => {
|
||||||
if include_abs_move {
|
|
||||||
let x = event.x.max(0) as u32;
|
|
||||||
let y = event.y.max(0) as u32;
|
|
||||||
let abs_x = ((x as u64 * 32767) / screen_width.max(1) as u64) as i32;
|
|
||||||
let abs_y = ((y as u64 * 32767) / screen_height.max(1) as u64) as i32;
|
|
||||||
events.push(OneKvmMouseEvent {
|
|
||||||
event_type: MouseEventType::MoveAbs,
|
|
||||||
x: abs_x,
|
|
||||||
y: abs_y,
|
|
||||||
button: None,
|
|
||||||
scroll: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let scroll = if event.y > 0 { 1i8 } else { -1i8 };
|
let scroll = if event.y > 0 { 1i8 } else { -1i8 };
|
||||||
events.push(OneKvmMouseEvent {
|
events.push(OneKvmMouseEvent {
|
||||||
event_type: MouseEventType::Scroll,
|
event_type: MouseEventType::Scroll,
|
||||||
@@ -134,21 +90,7 @@ pub fn convert_mouse_event(
|
|||||||
scroll,
|
scroll,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {}
|
||||||
if include_abs_move {
|
|
||||||
let x = event.x.max(0) as u32;
|
|
||||||
let y = event.y.max(0) as u32;
|
|
||||||
let abs_x = ((x as u64 * 32767) / screen_width.max(1) as u64) as i32;
|
|
||||||
let abs_y = ((y as u64 * 32767) / screen_height.max(1) as u64) as i32;
|
|
||||||
events.push(OneKvmMouseEvent {
|
|
||||||
event_type: MouseEventType::MoveAbs,
|
|
||||||
x: abs_x,
|
|
||||||
y: abs_y,
|
|
||||||
button: None,
|
|
||||||
scroll: 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
events
|
events
|
||||||
@@ -163,42 +105,89 @@ fn button_id_to_button(button_id: i32) -> Option<MouseButton> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_key_event(event: &KeyEvent) -> Option<KeyboardEvent> {
|
pub fn convert_key_events(event: &KeyEvent) -> Vec<KeyboardEvent> {
|
||||||
let event_type = if event.down || event.press {
|
let base_modifiers = if is_modifier_control_key(event) {
|
||||||
KeyEventType::Down
|
|
||||||
} else {
|
|
||||||
KeyEventType::Up
|
|
||||||
};
|
|
||||||
|
|
||||||
let modifiers = if is_modifier_control_key(event) {
|
|
||||||
KeyboardModifiers::default()
|
KeyboardModifiers::default()
|
||||||
} else {
|
} else {
|
||||||
parse_modifiers(event)
|
parse_modifiers(event)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ke_union::Union::ControlKey(ck)) = &event.union {
|
let Some(mapping) = key_event_to_hid(event, base_modifiers) else {
|
||||||
if let Some(key) = control_key_to_hid(ck.value()) {
|
return Vec::new();
|
||||||
let key = CanonicalKey::from_hid_usage(key)?;
|
};
|
||||||
return Some(KeyboardEvent {
|
|
||||||
event_type,
|
if event.press {
|
||||||
|
let up_modifiers = if mapping.added_shift {
|
||||||
|
base_modifiers
|
||||||
|
} else {
|
||||||
|
mapping.modifiers
|
||||||
|
};
|
||||||
|
vec![
|
||||||
|
KeyboardEvent {
|
||||||
|
event_type: KeyEventType::Down,
|
||||||
|
key: mapping.key,
|
||||||
|
modifiers: mapping.modifiers,
|
||||||
|
},
|
||||||
|
KeyboardEvent {
|
||||||
|
event_type: KeyEventType::Up,
|
||||||
|
key: mapping.key,
|
||||||
|
modifiers: up_modifiers,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
let event_type = if event.down {
|
||||||
|
KeyEventType::Down
|
||||||
|
} else {
|
||||||
|
KeyEventType::Up
|
||||||
|
};
|
||||||
|
vec![KeyboardEvent {
|
||||||
|
event_type,
|
||||||
|
key: mapping.key,
|
||||||
|
modifiers: mapping.modifiers,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn convert_key_event(event: &KeyEvent) -> Option<KeyboardEvent> {
|
||||||
|
convert_key_events(event).into_iter().next()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct KeyMapping {
|
||||||
|
key: CanonicalKey,
|
||||||
|
modifiers: KeyboardModifiers,
|
||||||
|
added_shift: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_event_to_hid(event: &KeyEvent, modifiers: KeyboardModifiers) -> Option<KeyMapping> {
|
||||||
|
match &event.union {
|
||||||
|
Some(ke_union::Union::ControlKey(ck)) => {
|
||||||
|
let key = CanonicalKey::from_hid_usage(control_key_to_hid(ck.value())?)?;
|
||||||
|
Some(KeyMapping {
|
||||||
key,
|
key,
|
||||||
modifiers,
|
modifiers,
|
||||||
});
|
added_shift: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
Some(ke_union::Union::Chr(chr)) => {
|
||||||
|
if event.mode.value() != KeyboardMode::Map.value() {
|
||||||
if let Some(ke_union::Union::Chr(chr)) = &event.union {
|
if let Some(mapping) = shifted_printable_char_to_hid(*chr, modifiers) {
|
||||||
if let Some(key) = keycode_to_hid(*chr) {
|
return Some(mapping);
|
||||||
let key = CanonicalKey::from_hid_usage(key)?;
|
}
|
||||||
return Some(KeyboardEvent {
|
}
|
||||||
event_type,
|
let key = CanonicalKey::from_hid_usage(keycode_to_hid(*chr)?)?;
|
||||||
|
Some(KeyMapping {
|
||||||
key,
|
key,
|
||||||
modifiers,
|
modifiers,
|
||||||
});
|
added_shift: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
Some(ke_union::Union::Unicode(unicode)) => {
|
||||||
|
let mapping = printable_char_to_hid(*unicode, modifiers)?;
|
||||||
|
Some(mapping)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_modifier_control_key(event: &KeyEvent) -> bool {
|
fn is_modifier_control_key(event: &KeyEvent) -> bool {
|
||||||
@@ -235,6 +224,96 @@ fn parse_modifiers(event: &KeyEvent) -> KeyboardModifiers {
|
|||||||
modifiers
|
modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_shift(mut modifiers: KeyboardModifiers) -> KeyboardModifiers {
|
||||||
|
modifiers.left_shift = true;
|
||||||
|
modifiers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shifted_mapping(key: CanonicalKey, modifiers: KeyboardModifiers) -> KeyMapping {
|
||||||
|
let added_shift = !modifiers.left_shift && !modifiers.right_shift;
|
||||||
|
KeyMapping {
|
||||||
|
key,
|
||||||
|
modifiers: with_shift(modifiers),
|
||||||
|
added_shift,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plain_mapping(key: CanonicalKey, modifiers: KeyboardModifiers) -> KeyMapping {
|
||||||
|
KeyMapping {
|
||||||
|
key,
|
||||||
|
modifiers,
|
||||||
|
added_shift: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shifted_printable_char_to_hid(ch: u32, modifiers: KeyboardModifiers) -> Option<KeyMapping> {
|
||||||
|
match ch {
|
||||||
|
33 => Some(shifted_mapping(CanonicalKey::Digit1, modifiers)),
|
||||||
|
64 => Some(shifted_mapping(CanonicalKey::Digit2, modifiers)),
|
||||||
|
35 => Some(shifted_mapping(CanonicalKey::Digit3, modifiers)),
|
||||||
|
36 => Some(shifted_mapping(CanonicalKey::Digit4, modifiers)),
|
||||||
|
37 => Some(shifted_mapping(CanonicalKey::Digit5, modifiers)),
|
||||||
|
94 => Some(shifted_mapping(CanonicalKey::Digit6, modifiers)),
|
||||||
|
38 => Some(shifted_mapping(CanonicalKey::Digit7, modifiers)),
|
||||||
|
42 => Some(shifted_mapping(CanonicalKey::Digit8, modifiers)),
|
||||||
|
40 => Some(shifted_mapping(CanonicalKey::Digit9, modifiers)),
|
||||||
|
41 => Some(shifted_mapping(CanonicalKey::Digit0, modifiers)),
|
||||||
|
95 => Some(shifted_mapping(CanonicalKey::Minus, modifiers)),
|
||||||
|
43 => Some(shifted_mapping(CanonicalKey::Equal, modifiers)),
|
||||||
|
123 => Some(shifted_mapping(CanonicalKey::BracketLeft, modifiers)),
|
||||||
|
125 => Some(shifted_mapping(CanonicalKey::BracketRight, modifiers)),
|
||||||
|
124 => Some(shifted_mapping(CanonicalKey::Backslash, modifiers)),
|
||||||
|
58 => Some(shifted_mapping(CanonicalKey::Semicolon, modifiers)),
|
||||||
|
34 => Some(shifted_mapping(CanonicalKey::Quote, modifiers)),
|
||||||
|
126 => Some(shifted_mapping(CanonicalKey::Backquote, modifiers)),
|
||||||
|
60 => Some(shifted_mapping(CanonicalKey::Comma, modifiers)),
|
||||||
|
62 => Some(shifted_mapping(CanonicalKey::Period, modifiers)),
|
||||||
|
63 => Some(shifted_mapping(CanonicalKey::Slash, modifiers)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn printable_char_to_hid(ch: u32, modifiers: KeyboardModifiers) -> Option<KeyMapping> {
|
||||||
|
match ch {
|
||||||
|
65..=90 => Some(shifted_mapping(
|
||||||
|
CanonicalKey::from_hid_usage((ch - 65 + 0x04) as u8)?,
|
||||||
|
modifiers,
|
||||||
|
)),
|
||||||
|
97..=122 => Some(plain_mapping(
|
||||||
|
CanonicalKey::from_hid_usage((ch - 97 + 0x04) as u8)?,
|
||||||
|
modifiers,
|
||||||
|
)),
|
||||||
|
48 => Some(plain_mapping(CanonicalKey::Digit0, modifiers)),
|
||||||
|
49 => Some(plain_mapping(CanonicalKey::Digit1, modifiers)),
|
||||||
|
50 => Some(plain_mapping(CanonicalKey::Digit2, modifiers)),
|
||||||
|
51 => Some(plain_mapping(CanonicalKey::Digit3, modifiers)),
|
||||||
|
52 => Some(plain_mapping(CanonicalKey::Digit4, modifiers)),
|
||||||
|
53 => Some(plain_mapping(CanonicalKey::Digit5, modifiers)),
|
||||||
|
54 => Some(plain_mapping(CanonicalKey::Digit6, modifiers)),
|
||||||
|
55 => Some(plain_mapping(CanonicalKey::Digit7, modifiers)),
|
||||||
|
56 => Some(plain_mapping(CanonicalKey::Digit8, modifiers)),
|
||||||
|
57 => Some(plain_mapping(CanonicalKey::Digit9, modifiers)),
|
||||||
|
32 => Some(plain_mapping(CanonicalKey::Space, modifiers)),
|
||||||
|
13 | 10 => Some(plain_mapping(CanonicalKey::Enter, modifiers)),
|
||||||
|
9 => Some(plain_mapping(CanonicalKey::Tab, modifiers)),
|
||||||
|
27 => Some(plain_mapping(CanonicalKey::Escape, modifiers)),
|
||||||
|
8 => Some(plain_mapping(CanonicalKey::Backspace, modifiers)),
|
||||||
|
127 => Some(plain_mapping(CanonicalKey::Delete, modifiers)),
|
||||||
|
45 => Some(plain_mapping(CanonicalKey::Minus, modifiers)),
|
||||||
|
61 => Some(plain_mapping(CanonicalKey::Equal, modifiers)),
|
||||||
|
91 => Some(plain_mapping(CanonicalKey::BracketLeft, modifiers)),
|
||||||
|
93 => Some(plain_mapping(CanonicalKey::BracketRight, modifiers)),
|
||||||
|
92 => Some(plain_mapping(CanonicalKey::Backslash, modifiers)),
|
||||||
|
59 => Some(plain_mapping(CanonicalKey::Semicolon, modifiers)),
|
||||||
|
39 => Some(plain_mapping(CanonicalKey::Quote, modifiers)),
|
||||||
|
96 => Some(plain_mapping(CanonicalKey::Backquote, modifiers)),
|
||||||
|
44 => Some(plain_mapping(CanonicalKey::Comma, modifiers)),
|
||||||
|
46 => Some(plain_mapping(CanonicalKey::Period, modifiers)),
|
||||||
|
47 => Some(plain_mapping(CanonicalKey::Slash, modifiers)),
|
||||||
|
_ => shifted_printable_char_to_hid(ch, modifiers),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn control_key_to_hid(key: i32) -> Option<u8> {
|
fn control_key_to_hid(key: i32) -> Option<u8> {
|
||||||
match key {
|
match key {
|
||||||
x if x == ControlKey::Alt as i32 => Some(0xE2), // Left Alt
|
x if x == ControlKey::Alt as i32 => Some(0xE2), // Left Alt
|
||||||
@@ -476,7 +555,7 @@ mod tests {
|
|||||||
event.y = 300;
|
event.y = 300;
|
||||||
event.mask = mouse_type::MOVE; // Pure move event
|
event.mask = mouse_type::MOVE; // Pure move event
|
||||||
|
|
||||||
let events = convert_mouse_event(&event, 1920, 1080, false);
|
let events = convert_mouse_event(&event, 1920, 1080);
|
||||||
assert!(!events.is_empty());
|
assert!(!events.is_empty());
|
||||||
assert_eq!(events[0].event_type, MouseEventType::MoveAbs);
|
assert_eq!(events[0].event_type, MouseEventType::MoveAbs);
|
||||||
}
|
}
|
||||||
@@ -488,11 +567,34 @@ mod tests {
|
|||||||
event.y = 300;
|
event.y = 300;
|
||||||
event.mask = (mouse_button::LEFT << 3) | mouse_type::DOWN;
|
event.mask = (mouse_button::LEFT << 3) | mouse_type::DOWN;
|
||||||
|
|
||||||
let events = convert_mouse_event(&event, 1920, 1080, false);
|
let events = convert_mouse_event(&event, 1920, 1080);
|
||||||
assert!(events.len() >= 2);
|
assert_eq!(events.len(), 1);
|
||||||
assert!(events
|
assert_eq!(events[0].event_type, MouseEventType::Down);
|
||||||
.iter()
|
assert_eq!(events[0].button, Some(MouseButton::Left));
|
||||||
.any(|e| e.event_type == MouseEventType::Down && e.button == Some(MouseButton::Left)));
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_convert_mouse_button_down_does_not_move() {
|
||||||
|
let mut event = MouseEvent::new();
|
||||||
|
event.mask = (mouse_button::LEFT << 3) | mouse_type::DOWN;
|
||||||
|
|
||||||
|
let events = convert_mouse_event(&event, 1920, 1080);
|
||||||
|
assert_eq!(events.len(), 1);
|
||||||
|
assert_eq!(events[0].event_type, MouseEventType::Down);
|
||||||
|
assert_eq!(events[0].button, Some(MouseButton::Left));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_convert_mouse_wheel_does_not_move() {
|
||||||
|
let mut event = MouseEvent::new();
|
||||||
|
event.x = 500;
|
||||||
|
event.y = 1;
|
||||||
|
event.mask = mouse_type::WHEEL;
|
||||||
|
|
||||||
|
let events = convert_mouse_event(&event, 1920, 1080);
|
||||||
|
assert_eq!(events.len(), 1);
|
||||||
|
assert_eq!(events[0].event_type, MouseEventType::Scroll);
|
||||||
|
assert_eq!(events[0].scroll, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -502,7 +604,7 @@ mod tests {
|
|||||||
event.y = 8;
|
event.y = 8;
|
||||||
event.mask = mouse_type::MOVE_RELATIVE;
|
event.mask = mouse_type::MOVE_RELATIVE;
|
||||||
|
|
||||||
let events = convert_mouse_event(&event, 1920, 1080, true);
|
let events = convert_mouse_event(&event, 1920, 1080);
|
||||||
assert_eq!(events.len(), 1);
|
assert_eq!(events.len(), 1);
|
||||||
assert_eq!(events[0].event_type, MouseEventType::Move);
|
assert_eq!(events[0].event_type, MouseEventType::Move);
|
||||||
assert_eq!(events[0].x, -12);
|
assert_eq!(events[0].x, -12);
|
||||||
@@ -526,4 +628,65 @@ mod tests {
|
|||||||
assert_eq!(kb_event.event_type, KeyEventType::Down);
|
assert_eq!(kb_event.event_type, KeyEventType::Down);
|
||||||
assert_eq!(kb_event.key, CanonicalKey::Enter);
|
assert_eq!(kb_event.key, CanonicalKey::Enter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_convert_at_press_to_shift_digit2() {
|
||||||
|
let mut key_event = KeyEvent::new();
|
||||||
|
key_event.press = true;
|
||||||
|
key_event.union = Some(ke_union::Union::Unicode('@' as u32));
|
||||||
|
|
||||||
|
let events = convert_key_events(&key_event);
|
||||||
|
assert_eq!(events.len(), 2);
|
||||||
|
assert_eq!(events[0].event_type, KeyEventType::Down);
|
||||||
|
assert_eq!(events[0].key, CanonicalKey::Digit2);
|
||||||
|
assert!(events[0].modifiers.left_shift);
|
||||||
|
assert_eq!(events[1].event_type, KeyEventType::Up);
|
||||||
|
assert_eq!(events[1].key, CanonicalKey::Digit2);
|
||||||
|
assert!(!events[1].modifiers.left_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_convert_shifted_chr_to_shift_digit2() {
|
||||||
|
let mut key_event = KeyEvent::new();
|
||||||
|
key_event.down = true;
|
||||||
|
key_event.union = Some(ke_union::Union::Chr('@' as u32));
|
||||||
|
|
||||||
|
let events = convert_key_events(&key_event);
|
||||||
|
assert_eq!(events.len(), 1);
|
||||||
|
assert_eq!(events[0].event_type, KeyEventType::Down);
|
||||||
|
assert_eq!(events[0].key, CanonicalKey::Digit2);
|
||||||
|
assert!(events[0].modifiers.left_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_convert_map_mode_chr_as_physical_key() {
|
||||||
|
use protobuf::EnumOrUnknown;
|
||||||
|
let mut key_event = KeyEvent::new();
|
||||||
|
key_event.down = true;
|
||||||
|
key_event.mode = EnumOrUnknown::new(KeyboardMode::Map);
|
||||||
|
key_event.union = Some(ke_union::Union::Chr(0x41));
|
||||||
|
|
||||||
|
let events = convert_key_events(&key_event);
|
||||||
|
assert_eq!(events.len(), 1);
|
||||||
|
assert_eq!(events[0].event_type, KeyEventType::Down);
|
||||||
|
assert_eq!(events[0].key, CanonicalKey::KeyA);
|
||||||
|
assert!(!events[0].modifiers.left_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_convert_press_generates_down_and_up() {
|
||||||
|
use protobuf::EnumOrUnknown;
|
||||||
|
let mut key_event = KeyEvent::new();
|
||||||
|
key_event.press = true;
|
||||||
|
key_event.union = Some(ke_union::Union::ControlKey(EnumOrUnknown::new(
|
||||||
|
ControlKey::Return,
|
||||||
|
)));
|
||||||
|
|
||||||
|
let events = convert_key_events(&key_event);
|
||||||
|
assert_eq!(events.len(), 2);
|
||||||
|
assert_eq!(events[0].event_type, KeyEventType::Down);
|
||||||
|
assert_eq!(events[1].event_type, KeyEventType::Up);
|
||||||
|
assert_eq!(events[0].key, CanonicalKey::Enter);
|
||||||
|
assert_eq!(events[1].key, CanonicalKey::Enter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ pub use hbb::rendezvous::{
|
|||||||
pub use hbb::message::{
|
pub use hbb::message::{
|
||||||
key_event, login_response, message, misc, AudioFormat, AudioFrame, Auth2FA, Clipboard,
|
key_event, login_response, message, misc, AudioFormat, AudioFrame, Auth2FA, Clipboard,
|
||||||
ControlKey, CursorData, CursorPosition, DisplayInfo, EncodedVideoFrame, EncodedVideoFrames,
|
ControlKey, CursorData, CursorPosition, DisplayInfo, EncodedVideoFrame, EncodedVideoFrames,
|
||||||
Features, Hash, IdPk, KeyEvent, LoginRequest, LoginResponse, Message as HbbMessage, Misc,
|
Features, Hash, IdPk, KeyEvent, KeyboardMode, LoginRequest, LoginResponse,
|
||||||
MouseEvent, OptionMessage, PeerInfo, PublicKey, SignedId, SupportedDecoding, SupportedEncoding,
|
Message as HbbMessage, Misc, MouseEvent, OptionMessage, PeerInfo, PublicKey, SignedId,
|
||||||
SupportedResolutions, TestDelay, VideoFrame, WindowsSessions,
|
SupportedDecoding, SupportedEncoding, SupportedResolutions, TestDelay, VideoFrame,
|
||||||
|
WindowsSessions,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn make_register_peer(id: &str, serial: i32) -> RendezvousMessage {
|
pub fn make_register_peer(id: &str, serial: i32) -> RendezvousMessage {
|
||||||
|
|||||||
@@ -439,8 +439,11 @@ impl RendezvousMediator {
|
|||||||
}
|
}
|
||||||
Some(rendezvous_message::Union::PunchHole(ph)) => {
|
Some(rendezvous_message::Union::PunchHole(ph)) => {
|
||||||
let config = self.config.read().clone();
|
let config = self.config.read().clone();
|
||||||
let effective_relay_server =
|
let effective_relay_server = select_relay_server(
|
||||||
select_relay_server(config.relay_server.as_deref(), &ph.relay_server);
|
config.relay_server.as_deref(),
|
||||||
|
&ph.relay_server,
|
||||||
|
&config.rendezvous_server,
|
||||||
|
);
|
||||||
|
|
||||||
let peer_addr = if !ph.socket_addr.is_empty() {
|
let peer_addr = if !ph.socket_addr.is_empty() {
|
||||||
AddrMangle::decode(&ph.socket_addr)
|
AddrMangle::decode(&ph.socket_addr)
|
||||||
@@ -514,8 +517,11 @@ impl RendezvousMediator {
|
|||||||
}
|
}
|
||||||
Some(rendezvous_message::Union::RequestRelay(rr)) => {
|
Some(rendezvous_message::Union::RequestRelay(rr)) => {
|
||||||
let config = self.config.read().clone();
|
let config = self.config.read().clone();
|
||||||
let effective_relay_server =
|
let effective_relay_server = select_relay_server(
|
||||||
select_relay_server(config.relay_server.as_deref(), &rr.relay_server);
|
config.relay_server.as_deref(),
|
||||||
|
&rr.relay_server,
|
||||||
|
&config.rendezvous_server,
|
||||||
|
);
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Received RequestRelay: relay_server={}, effective_relay_server={}, uuid={}, secure={}",
|
"Received RequestRelay: relay_server={}, effective_relay_server={}, uuid={}, secure={}",
|
||||||
@@ -542,9 +548,12 @@ impl RendezvousMediator {
|
|||||||
}
|
}
|
||||||
Some(rendezvous_message::Union::FetchLocalAddr(fla)) => {
|
Some(rendezvous_message::Union::FetchLocalAddr(fla)) => {
|
||||||
let config = self.config.read().clone();
|
let config = self.config.read().clone();
|
||||||
let effective_relay_server =
|
let effective_relay_server = select_relay_server(
|
||||||
select_relay_server(config.relay_server.as_deref(), &fla.relay_server)
|
config.relay_server.as_deref(),
|
||||||
.unwrap_or_default();
|
&fla.relay_server,
|
||||||
|
&config.rendezvous_server,
|
||||||
|
)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let peer_addr = AddrMangle::decode(&fla.socket_addr);
|
let peer_addr = AddrMangle::decode(&fla.socket_addr);
|
||||||
info!(
|
info!(
|
||||||
@@ -613,10 +622,18 @@ fn normalize_relay_server(server: &str) -> Option<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_relay_server(local_relay: Option<&str>, server_relay: &str) -> Option<String> {
|
fn select_relay_server(
|
||||||
|
local_relay: Option<&str>,
|
||||||
|
server_relay: &str,
|
||||||
|
rendezvous_server: &str,
|
||||||
|
) -> Option<String> {
|
||||||
local_relay
|
local_relay
|
||||||
.and_then(normalize_relay_server)
|
.and_then(normalize_relay_server)
|
||||||
.or_else(|| normalize_relay_server(server_relay))
|
.or_else(|| normalize_relay_server(server_relay))
|
||||||
|
.or_else(|| {
|
||||||
|
let host = rendezvous_server.trim().split(':').next().unwrap_or("");
|
||||||
|
normalize_relay_server(host)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddrMangle {
|
impl AddrMangle {
|
||||||
@@ -799,25 +816,38 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_select_relay_server_prefers_local() {
|
fn test_select_relay_server_prefers_local() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
select_relay_server(Some("local.example.com:21117"), "server.example.com:21117"),
|
select_relay_server(
|
||||||
|
Some("local.example.com:21117"),
|
||||||
|
"server.example.com:21117",
|
||||||
|
"hbbs.example.com:21116"
|
||||||
|
),
|
||||||
Some("local.example.com:21117".to_string())
|
Some("local.example.com:21117".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
select_relay_server(Some("local.example.com"), "server.example.com:21117"),
|
select_relay_server(
|
||||||
|
Some("local.example.com"),
|
||||||
|
"server.example.com:21117",
|
||||||
|
"hbbs.example.com:21116"
|
||||||
|
),
|
||||||
Some("local.example.com:21117".to_string())
|
Some("local.example.com:21117".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
select_relay_server(Some(" "), "server.example.com"),
|
select_relay_server(Some(" "), "server.example.com", "hbbs.example.com:21116"),
|
||||||
Some("server.example.com:21117".to_string())
|
Some("server.example.com:21117".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
select_relay_server(None, "server.example.com:21117"),
|
select_relay_server(None, "server.example.com:21117", "hbbs.example.com:21116"),
|
||||||
Some("server.example.com:21117".to_string())
|
Some("server.example.com:21117".to_string())
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(select_relay_server(None, ""), None);
|
assert_eq!(
|
||||||
|
select_relay_server(None, "", "hbbs.example.com:21116"),
|
||||||
|
Some("hbbs.example.com:21117".to_string())
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(select_relay_server(None, "", ""), None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user