commit
5e06fc210b
@ -920,6 +920,7 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
disableClipboard(),
|
disableClipboard(),
|
||||||
lockAfterSessionEnd(),
|
lockAfterSessionEnd(),
|
||||||
privacyMode(),
|
privacyMode(),
|
||||||
|
swapKey(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1528,6 +1529,23 @@ class _DisplayMenuState extends State<_DisplayMenu> {
|
|||||||
ffi: widget.ffi,
|
ffi: widget.ffi,
|
||||||
child: Text(translate('Privacy mode')));
|
child: Text(translate('Privacy mode')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
swapKey() {
|
||||||
|
final visible = perms['keyboard'] != false &&
|
||||||
|
((Platform.isMacOS && pi.platform != kPeerPlatformMacOS) ||
|
||||||
|
(!Platform.isMacOS && pi.platform == kPeerPlatformMacOS));
|
||||||
|
if (!visible) return Offstage();
|
||||||
|
final option = 'allow_swap_key';
|
||||||
|
final value = bind.sessionGetToggleOptionSync(id: widget.id, arg: option);
|
||||||
|
return _CheckboxMenuButton(
|
||||||
|
value: value,
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value == null) return;
|
||||||
|
bind.sessionToggleOption(id: widget.id, value: option);
|
||||||
|
},
|
||||||
|
ffi: widget.ffi,
|
||||||
|
child: Text(translate('Swap control-command key')));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _KeyboardMenu extends StatelessWidget {
|
class _KeyboardMenu extends StatelessWidget {
|
||||||
|
@ -217,6 +217,8 @@ pub struct PeerConfig {
|
|||||||
pub lock_after_session_end: LockAfterSessionEnd,
|
pub lock_after_session_end: LockAfterSessionEnd,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub privacy_mode: PrivacyMode,
|
pub privacy_mode: PrivacyMode,
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub allow_swap_key: AllowSwapKey,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub port_forwards: Vec<(i32, String, i32)>,
|
pub port_forwards: Vec<(i32, String, i32)>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -1060,6 +1062,8 @@ serde_field_bool!(
|
|||||||
);
|
);
|
||||||
serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode);
|
serde_field_bool!(PrivacyMode, "privacy_mode", default_privacy_mode);
|
||||||
|
|
||||||
|
serde_field_bool!(AllowSwapKey, "allow_swap_key", default_swap_key);
|
||||||
|
|
||||||
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct LocalConfig {
|
pub struct LocalConfig {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
@ -1230,6 +1230,8 @@ impl LoginConfigHandler {
|
|||||||
option.block_input = BoolOption::No.into();
|
option.block_input = BoolOption::No.into();
|
||||||
} else if name == "show-quality-monitor" {
|
} else if name == "show-quality-monitor" {
|
||||||
config.show_quality_monitor.v = !config.show_quality_monitor.v;
|
config.show_quality_monitor.v = !config.show_quality_monitor.v;
|
||||||
|
} else if name == "allow_swap_key" {
|
||||||
|
config.allow_swap_key.v = !config.allow_swap_key.v;
|
||||||
} else {
|
} else {
|
||||||
let is_set = self
|
let is_set = self
|
||||||
.options
|
.options
|
||||||
@ -1383,6 +1385,8 @@ impl LoginConfigHandler {
|
|||||||
self.config.disable_clipboard.v
|
self.config.disable_clipboard.v
|
||||||
} else if name == "show-quality-monitor" {
|
} else if name == "show-quality-monitor" {
|
||||||
self.config.show_quality_monitor.v
|
self.config.show_quality_monitor.v
|
||||||
|
} else if name == "allow_swap_key" {
|
||||||
|
self.config.allow_swap_key.v
|
||||||
} else {
|
} else {
|
||||||
!self.get_option(name).is_empty()
|
!self.get_option(name).is_empty()
|
||||||
}
|
}
|
||||||
@ -1807,6 +1811,7 @@ pub fn send_mouse(
|
|||||||
if check_scroll_on_mac(mask, x, y) {
|
if check_scroll_on_mac(mask, x, y) {
|
||||||
mouse_event.modifiers.push(ControlKey::Scroll.into());
|
mouse_event.modifiers.push(ControlKey::Scroll.into());
|
||||||
}
|
}
|
||||||
|
interface.swap_modifier_mouse(&mut mouse_event);
|
||||||
msg_out.set_mouse_event(mouse_event);
|
msg_out.set_mouse_event(mouse_event);
|
||||||
interface.send(Data::Message(msg_out));
|
interface.send(Data::Message(msg_out));
|
||||||
}
|
}
|
||||||
@ -2033,6 +2038,7 @@ pub trait Interface: Send + Clone + 'static + Sized {
|
|||||||
fn is_force_relay(&self) -> bool {
|
fn is_force_relay(&self) -> bool {
|
||||||
self.get_login_config_handler().read().unwrap().force_relay
|
self.get_login_config_handler().read().unwrap().force_relay
|
||||||
}
|
}
|
||||||
|
fn swap_modifier_mouse(&self, _msg : &mut hbb_common::protos::message::MouseEvent) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data used by the client interface.
|
/// Data used by the client interface.
|
||||||
|
@ -198,6 +198,7 @@ class Header: Reactor.Component {
|
|||||||
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
|
{keyboard_enabled && clipboard_enabled ? <li #disable-clipboard .toggle-option><span>{svg_checkmark}</span>{translate('Disable clipboard')}</li> : ""}
|
||||||
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
|
{keyboard_enabled ? <li #lock-after-session-end .toggle-option><span>{svg_checkmark}</span>{translate('Lock after session end')}</li> : ""}
|
||||||
{keyboard_enabled && pi.platform == "Windows" ? <li #privacy-mode><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
|
{keyboard_enabled && pi.platform == "Windows" ? <li #privacy-mode><span>{svg_checkmark}</span>{translate('Privacy mode')}</li> : ""}
|
||||||
|
{keyboard_enabled && ((is_osx && pi.platform != "Mac OS") || (!is_osx && pi.platform == "Mac OS")) ? <li #allow_swap_key .toggle-option><span>{svg_checkmark}</span>{translate('Swap control-command key')}</li> : ""}
|
||||||
</menu>
|
</menu>
|
||||||
</popup>;
|
</popup>;
|
||||||
}
|
}
|
||||||
@ -440,7 +441,7 @@ function toggleMenuState() {
|
|||||||
for (var el in $$(menu#keyboard-options>li)) {
|
for (var el in $$(menu#keyboard-options>li)) {
|
||||||
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
||||||
}
|
}
|
||||||
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end"]) {
|
for (var id in ["show-remote-cursor", "show-quality-monitor", "disable-audio", "enable-file-transfer", "disable-clipboard", "lock-after-session-end", "allow_swap_key"]) {
|
||||||
var el = self.select('#' + id);
|
var el = self.select('#' + id);
|
||||||
if (el) {
|
if (el) {
|
||||||
var value = handler.get_toggle_option(id);
|
var value = handler.get_toggle_option(id);
|
||||||
|
@ -373,10 +373,87 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
return "".to_owned();
|
return "".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn swab_modifier_key(&self, msg: &mut KeyEvent) {
|
||||||
|
|
||||||
|
let allow_swap_key = self.get_toggle_option("allow_swap_key".to_string());
|
||||||
|
if allow_swap_key {
|
||||||
|
if let Some(key_event::Union::ControlKey(ck)) = msg.union {
|
||||||
|
let ck = ck.enum_value_or_default();
|
||||||
|
let ck = match ck {
|
||||||
|
ControlKey::Control => ControlKey::Meta,
|
||||||
|
ControlKey::Meta => ControlKey::Control,
|
||||||
|
ControlKey::RControl => ControlKey::Meta,
|
||||||
|
ControlKey::RWin => ControlKey::Control,
|
||||||
|
_ => ck,
|
||||||
|
};
|
||||||
|
msg.set_control_key(ck);
|
||||||
|
}
|
||||||
|
msg.modifiers = msg.modifiers.iter().map(|ck| {
|
||||||
|
let ck = ck.enum_value_or_default();
|
||||||
|
let ck = match ck {
|
||||||
|
ControlKey::Control => ControlKey::Meta,
|
||||||
|
ControlKey::Meta => ControlKey::Control,
|
||||||
|
ControlKey::RControl => ControlKey::Meta,
|
||||||
|
ControlKey::RWin => ControlKey::Control,
|
||||||
|
_ => ck,
|
||||||
|
};
|
||||||
|
hbb_common::protobuf::EnumOrUnknown::new(ck)
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
|
||||||
|
let code = msg.chr();
|
||||||
|
if code != 0 {
|
||||||
|
let mut peer = self.peer_platform().to_lowercase();
|
||||||
|
peer.retain(|c| !c.is_whitespace());
|
||||||
|
|
||||||
|
let key = match peer.as_str() {
|
||||||
|
"windows" => {
|
||||||
|
let key = rdev::win_key_from_scancode(code);
|
||||||
|
let key = match key {
|
||||||
|
rdev::Key::ControlLeft => rdev::Key::MetaLeft,
|
||||||
|
rdev::Key::MetaLeft => rdev::Key::ControlLeft,
|
||||||
|
rdev::Key::ControlRight => rdev::Key::MetaLeft,
|
||||||
|
rdev::Key::MetaRight => rdev::Key::ControlLeft,
|
||||||
|
_ => key,
|
||||||
|
};
|
||||||
|
rdev::win_scancode_from_key(key).unwrap_or_default()
|
||||||
|
}
|
||||||
|
"macos" => {
|
||||||
|
let key = rdev::macos_key_from_code(code);
|
||||||
|
let key = match key {
|
||||||
|
rdev::Key::ControlLeft => rdev::Key::MetaLeft,
|
||||||
|
rdev::Key::MetaLeft => rdev::Key::ControlLeft,
|
||||||
|
rdev::Key::ControlRight => rdev::Key::MetaLeft,
|
||||||
|
rdev::Key::MetaRight => rdev::Key::ControlLeft,
|
||||||
|
_ => key,
|
||||||
|
};
|
||||||
|
rdev::macos_keycode_from_key(key).unwrap_or_default()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let key = rdev::linux_key_from_code(code);
|
||||||
|
let key = match key {
|
||||||
|
rdev::Key::ControlLeft => rdev::Key::MetaLeft,
|
||||||
|
rdev::Key::MetaLeft => rdev::Key::ControlLeft,
|
||||||
|
rdev::Key::ControlRight => rdev::Key::MetaLeft,
|
||||||
|
rdev::Key::MetaRight => rdev::Key::ControlLeft,
|
||||||
|
_ => key,
|
||||||
|
};
|
||||||
|
rdev::linux_keycode_from_key(key).unwrap_or_default()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
msg.set_chr(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_key_event(&self, evt: &KeyEvent) {
|
pub fn send_key_event(&self, evt: &KeyEvent) {
|
||||||
// mode: legacy(0), map(1), translate(2), auto(3)
|
// mode: legacy(0), map(1), translate(2), auto(3)
|
||||||
|
|
||||||
|
let mut msg = evt.clone();
|
||||||
|
self.swab_modifier_key(&mut msg);
|
||||||
let mut msg_out = Message::new();
|
let mut msg_out = Message::new();
|
||||||
msg_out.set_key_event(evt.clone());
|
msg_out.set_key_event(msg);
|
||||||
self.send(Data::Message(msg_out));
|
self.send(Data::Message(msg_out));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,6 +1011,23 @@ impl<T: InvokeUiSession> Interface for Session<T> {
|
|||||||
handle_test_delay(t, peer).await;
|
handle_test_delay(t, peer).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn swap_modifier_mouse(&self, msg : &mut hbb_common::protos::message::MouseEvent) {
|
||||||
|
let allow_swap_key = self.get_toggle_option("allow_swap_key".to_string());
|
||||||
|
if allow_swap_key {
|
||||||
|
msg.modifiers = msg.modifiers.iter().map(|ck| {
|
||||||
|
let ck = ck.enum_value_or_default();
|
||||||
|
let ck = match ck {
|
||||||
|
ControlKey::Control => ControlKey::Meta,
|
||||||
|
ControlKey::Meta => ControlKey::Control,
|
||||||
|
ControlKey::RControl => ControlKey::Meta,
|
||||||
|
ControlKey::RWin => ControlKey::Control,
|
||||||
|
_ => ck,
|
||||||
|
};
|
||||||
|
hbb_common::protobuf::EnumOrUnknown::new(ck)
|
||||||
|
}).collect();
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: InvokeUiSession> Session<T> {
|
impl<T: InvokeUiSession> Session<T> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user