mirror of
https://github.com/rustdesk/rustdesk
synced 2026-04-21 13:27:19 +00:00
Merge 8d610d267e into e8a1b7fe21
This commit is contained in:
commit
5a763dbbfe
7 changed files with 282 additions and 79 deletions
|
|
@ -852,6 +852,22 @@ List<TToggleMenu> toolbarKeyboardToggles(FFI ffi) {
|
|||
child: Text(translate('Swap control-command key'))));
|
||||
}
|
||||
|
||||
if (ffiModel.keyboard && isMacOS && pi.platform != kPeerPlatformMacOS) {
|
||||
final option = 'allow_swap_option_command_key';
|
||||
final value =
|
||||
bind.sessionGetToggleOptionSync(sessionId: sessionId, arg: option);
|
||||
onChanged(bool? value) {
|
||||
if (value == null) return;
|
||||
bind.sessionToggleOption(sessionId: sessionId, value: option);
|
||||
}
|
||||
|
||||
final enabled = !ffi.ffiModel.viewOnly;
|
||||
v.add(TToggleMenu(
|
||||
value: value,
|
||||
onChanged: enabled ? onChanged : null,
|
||||
child: Text(translate('Swap option-command key'))));
|
||||
}
|
||||
|
||||
// Relative mouse mode (gaming mode).
|
||||
// Only show when server supports MOUSE_TYPE_MOVE_RELATIVE (version >= 1.4.5)
|
||||
// Note: This feature is only available in Flutter client. Sciter client does not support this.
|
||||
|
|
|
|||
104
src/client.rs
104
src/client.rs
|
|
@ -121,11 +121,9 @@ pub const LOGIN_SCREEN_WAYLAND: &str = "Wayland login screen is not supported";
|
|||
#[cfg(target_os = "linux")]
|
||||
pub const SCRAP_UBUNTU_HIGHER_REQUIRED: &str = "ubuntu-21-04-required";
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str =
|
||||
"wayland-requires-higher-linux-version";
|
||||
pub const SCRAP_OTHER_VERSION_OR_X11_REQUIRED: &str = "wayland-requires-higher-linux-version";
|
||||
#[cfg(target_os = "linux")]
|
||||
pub const SCRAP_XDP_PORTAL_UNAVAILABLE: &str =
|
||||
"xdp-portal-unavailable";
|
||||
pub const SCRAP_XDP_PORTAL_UNAVAILABLE: &str = "xdp-portal-unavailable";
|
||||
pub const SCRAP_X11_REQUIRED: &str = "x11 expected";
|
||||
pub const SCRAP_X11_REF_URL: &str = "https://rustdesk.com/docs/en/manual/linux/#x11-required";
|
||||
|
||||
|
|
@ -1760,6 +1758,43 @@ pub struct LoginConfigHandler {
|
|||
pub record_permission: bool,
|
||||
}
|
||||
|
||||
const OPTION_SWAP_OPTION_COMMAND_KEY: &str = "allow_swap_option_command_key";
|
||||
|
||||
fn get_option_command_swap_enabled(config: &PeerConfig) -> bool {
|
||||
config::option2bool(
|
||||
OPTION_SWAP_OPTION_COMMAND_KEY,
|
||||
config
|
||||
.options
|
||||
.get(OPTION_SWAP_OPTION_COMMAND_KEY)
|
||||
.map(String::as_str)
|
||||
.unwrap_or(""),
|
||||
)
|
||||
}
|
||||
|
||||
fn set_option_command_swap_toggle(config: &mut PeerConfig, enabled: bool) {
|
||||
if enabled {
|
||||
config
|
||||
.options
|
||||
.insert(OPTION_SWAP_OPTION_COMMAND_KEY.to_owned(), "Y".to_owned());
|
||||
} else {
|
||||
config.options.remove(OPTION_SWAP_OPTION_COMMAND_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_control_command_swap_enabled(config: &mut PeerConfig, enabled: bool) {
|
||||
config.allow_swap_key.v = enabled;
|
||||
if enabled {
|
||||
set_option_command_swap_toggle(config, false);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_option_command_swap_enabled(config: &mut PeerConfig, enabled: bool) {
|
||||
set_option_command_swap_toggle(config, enabled);
|
||||
if enabled {
|
||||
config.allow_swap_key.v = false;
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for LoginConfigHandler {
|
||||
type Target = PeerConfig;
|
||||
|
||||
|
|
@ -2124,7 +2159,11 @@ impl LoginConfigHandler {
|
|||
} else if name == "show-quality-monitor" {
|
||||
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;
|
||||
let enabled = !config.allow_swap_key.v;
|
||||
set_control_command_swap_enabled(&mut config, enabled);
|
||||
} else if name == "allow_swap_option_command_key" {
|
||||
let enabled = !get_option_command_swap_enabled(&config);
|
||||
set_option_command_swap_enabled(&mut config, enabled);
|
||||
} else if name == "view-only" {
|
||||
config.view_only.v = !config.view_only.v;
|
||||
let f = |b: bool| {
|
||||
|
|
@ -2336,6 +2375,8 @@ impl LoginConfigHandler {
|
|||
self.config.show_quality_monitor.v
|
||||
} else if name == "allow_swap_key" {
|
||||
self.config.allow_swap_key.v
|
||||
} else if name == "allow_swap_option_command_key" {
|
||||
get_option_command_swap_enabled(&self.config)
|
||||
} else if name == "view-only" {
|
||||
self.config.view_only.v
|
||||
} else if name == "show-my-cursor" {
|
||||
|
|
@ -2630,16 +2671,15 @@ impl LoginConfigHandler {
|
|||
};
|
||||
let mut avatar = get_builtin_option(keys::OPTION_AVATAR);
|
||||
if avatar.is_empty() {
|
||||
avatar = serde_json::from_str::<serde_json::Value>(&LocalConfig::get_option(
|
||||
"user_info",
|
||||
))
|
||||
.ok()
|
||||
.and_then(|x| {
|
||||
x.get("avatar")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|x| x.trim().to_owned())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
avatar =
|
||||
serde_json::from_str::<serde_json::Value>(&LocalConfig::get_option("user_info"))
|
||||
.ok()
|
||||
.and_then(|x| {
|
||||
x.get("avatar")
|
||||
.and_then(|x| x.as_str())
|
||||
.map(|x| x.trim().to_owned())
|
||||
})
|
||||
.unwrap_or_default();
|
||||
}
|
||||
avatar = resolve_avatar_url(avatar);
|
||||
let mut display_name = get_builtin_option(keys::OPTION_DISPLAY_NAME);
|
||||
|
|
@ -4055,8 +4095,42 @@ pub mod peer_online {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::client::{set_control_command_swap_enabled, set_option_command_swap_enabled};
|
||||
use hbb_common::config::PeerConfig;
|
||||
use hbb_common::tokio;
|
||||
|
||||
#[test]
|
||||
fn enable_option_command_swap_stores_option_and_disables_control_command_swap() {
|
||||
let mut config = PeerConfig {
|
||||
allow_swap_key: hbb_common::config::AllowSwapKey { v: true },
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
set_option_command_swap_enabled(&mut config, true);
|
||||
|
||||
assert_eq!(
|
||||
config
|
||||
.options
|
||||
.get("allow_swap_option_command_key")
|
||||
.map(String::as_str),
|
||||
Some("Y")
|
||||
);
|
||||
assert!(!config.allow_swap_key.v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enable_control_command_swap_disables_option_command_swap() {
|
||||
let mut config = PeerConfig::default();
|
||||
config
|
||||
.options
|
||||
.insert("allow_swap_option_command_key".to_owned(), "Y".to_owned());
|
||||
|
||||
set_control_command_swap_enabled(&mut config, true);
|
||||
|
||||
assert!(config.allow_swap_key.v);
|
||||
assert!(!config.options.contains_key("allow_swap_option_command_key"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_query_onlines() {
|
||||
super::query_online_states(
|
||||
|
|
|
|||
|
|
@ -568,6 +568,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("input_source_1_tip", "输入源 1"),
|
||||
("input_source_2_tip", "输入源 2"),
|
||||
("Swap control-command key", "交换 Control 键和 Command 键"),
|
||||
("Swap option-command key", "交换 Option 键和 Command 键"),
|
||||
("swap-left-right-mouse", "交换鼠标左右键"),
|
||||
("2FA code", "双重认证代码"),
|
||||
("More", "更多"),
|
||||
|
|
|
|||
|
|
@ -568,6 +568,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("input_source_1_tip", ""),
|
||||
("input_source_2_tip", ""),
|
||||
("Swap control-command key", ""),
|
||||
("Swap option-command key", ""),
|
||||
("swap-left-right-mouse", ""),
|
||||
("2FA code", ""),
|
||||
("More", ""),
|
||||
|
|
|
|||
|
|
@ -568,6 +568,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||
("input_source_1_tip", "輸入源 1"),
|
||||
("input_source_2_tip", "輸入源 2"),
|
||||
("Swap control-command key", "交換 Control 和 Command 按鍵"),
|
||||
("Swap option-command key", "交換 Option 和 Command 按鍵"),
|
||||
("swap-left-right-mouse", "交換滑鼠左右鍵"),
|
||||
("2FA code", "二步驟驗證碼"),
|
||||
("More", "更多"),
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ class Header: Reactor.Component {
|
|||
{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 && ((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> : ""}
|
||||
{keyboard_enabled && is_osx && pi.platform != "Mac OS" ? <li #allow_swap_option_command_key .toggle-option><span>{svg_checkmark}</span>{translate('Swap option-command key')}</li> : ""}
|
||||
{handler.version_cmp(pi.version, '1.2.4') >= 0 ? <li #i444><span>{svg_checkmark}</span>{translate('True color (4:4:4)')}</li> : ""}
|
||||
</menu>
|
||||
</popup>;
|
||||
|
|
@ -489,7 +490,7 @@ function toggleMenuState() {
|
|||
for (var el in $$(menu#keyboard-options>li)) {
|
||||
el.attributes.toggleClass("selected", values.indexOf(el.id) >= 0);
|
||||
}
|
||||
for (var id in ["show-remote-cursor", "follow-remote-cursor", "follow-remote-window", "show-quality-monitor", "disable-audio", "enable-file-copy-paste", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "i444"]) {
|
||||
for (var id in ["show-remote-cursor", "follow-remote-cursor", "follow-remote-window", "show-quality-monitor", "disable-audio", "enable-file-copy-paste", "disable-clipboard", "lock-after-session-end", "allow_swap_key", "allow_swap_option_command_key", "i444"]) {
|
||||
var el = self.select('#' + id);
|
||||
if (el) {
|
||||
var value = handler.get_toggle_option(id);
|
||||
|
|
|
|||
|
|
@ -169,6 +169,82 @@ impl ChangeDisplayRecord {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum ModifierSwapMode {
|
||||
None,
|
||||
ControlCommand,
|
||||
OptionCommand,
|
||||
}
|
||||
|
||||
fn modifier_swap_mode(
|
||||
control_command_enabled: bool,
|
||||
option_command_enabled: bool,
|
||||
) -> ModifierSwapMode {
|
||||
if option_command_enabled {
|
||||
ModifierSwapMode::OptionCommand
|
||||
} else if control_command_enabled {
|
||||
ModifierSwapMode::ControlCommand
|
||||
} else {
|
||||
ModifierSwapMode::None
|
||||
}
|
||||
}
|
||||
|
||||
fn swap_control_command_control_key(ck: ControlKey) -> ControlKey {
|
||||
match ck {
|
||||
ControlKey::Control => ControlKey::Meta,
|
||||
ControlKey::Meta => ControlKey::Control,
|
||||
ControlKey::RControl => ControlKey::Meta,
|
||||
ControlKey::RWin => ControlKey::Control,
|
||||
_ => ck,
|
||||
}
|
||||
}
|
||||
|
||||
fn swap_option_command_control_key(ck: ControlKey) -> ControlKey {
|
||||
match ck {
|
||||
ControlKey::Alt => ControlKey::Meta,
|
||||
ControlKey::Meta => ControlKey::Alt,
|
||||
ControlKey::RAlt => ControlKey::Meta,
|
||||
ControlKey::RWin => ControlKey::Alt,
|
||||
_ => ck,
|
||||
}
|
||||
}
|
||||
|
||||
fn remap_control_key_for_mode(mode: ModifierSwapMode, ck: ControlKey) -> ControlKey {
|
||||
match mode {
|
||||
ModifierSwapMode::None => ck,
|
||||
ModifierSwapMode::ControlCommand => swap_control_command_control_key(ck),
|
||||
ModifierSwapMode::OptionCommand => swap_option_command_control_key(ck),
|
||||
}
|
||||
}
|
||||
|
||||
fn swap_control_command_rdev_key(key: rdev::Key) -> rdev::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,
|
||||
}
|
||||
}
|
||||
|
||||
fn swap_option_command_rdev_key(key: rdev::Key) -> rdev::Key {
|
||||
match key {
|
||||
rdev::Key::Alt => rdev::Key::MetaLeft,
|
||||
rdev::Key::MetaLeft => rdev::Key::Alt,
|
||||
rdev::Key::AltGr => rdev::Key::MetaLeft,
|
||||
rdev::Key::MetaRight => rdev::Key::Alt,
|
||||
_ => key,
|
||||
}
|
||||
}
|
||||
|
||||
fn remap_rdev_key_for_mode(mode: ModifierSwapMode, key: rdev::Key) -> rdev::Key {
|
||||
match mode {
|
||||
ModifierSwapMode::None => key,
|
||||
ModifierSwapMode::ControlCommand => swap_control_command_rdev_key(key),
|
||||
ModifierSwapMode::OptionCommand => swap_option_command_rdev_key(key),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
impl SessionPermissionConfig {
|
||||
pub fn is_text_clipboard_required(&self) -> bool {
|
||||
|
|
@ -186,6 +262,13 @@ impl SessionPermissionConfig {
|
|||
}
|
||||
|
||||
impl<T: InvokeUiSession> Session<T> {
|
||||
fn modifier_swap_mode(&self) -> ModifierSwapMode {
|
||||
modifier_swap_mode(
|
||||
self.get_toggle_option("allow_swap_key".to_string()),
|
||||
self.get_toggle_option("allow_swap_option_command_key".to_string()),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
pub fn get_permission_config(&self) -> SessionPermissionConfig {
|
||||
SessionPermissionConfig {
|
||||
|
|
@ -688,32 +771,20 @@ impl<T: InvokeUiSession> Session<T> {
|
|||
}
|
||||
|
||||
pub fn swap_modifier_key(&self, msg: &mut KeyEvent) {
|
||||
let allow_swap_key = self.get_toggle_option("allow_swap_key".to_string());
|
||||
if allow_swap_key {
|
||||
let mode = self.modifier_swap_mode();
|
||||
if mode != ModifierSwapMode::None {
|
||||
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,
|
||||
};
|
||||
let ck = remap_control_key_for_mode(mode, ck.enum_value_or_default());
|
||||
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)
|
||||
hbb_common::protobuf::EnumOrUnknown::new(remap_control_key_for_mode(
|
||||
mode,
|
||||
ck.enum_value_or_default(),
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
@ -723,39 +794,21 @@ impl<T: InvokeUiSession> Session<T> {
|
|||
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 as _);
|
||||
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() as _
|
||||
}
|
||||
_ => {
|
||||
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()
|
||||
}
|
||||
"windows" => rdev::win_scancode_from_key(remap_rdev_key_for_mode(
|
||||
mode,
|
||||
rdev::win_key_from_scancode(code),
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
"macos" => rdev::macos_keycode_from_key(remap_rdev_key_for_mode(
|
||||
mode,
|
||||
rdev::macos_key_from_code(code as _),
|
||||
))
|
||||
.unwrap_or_default() as _,
|
||||
_ => rdev::linux_keycode_from_key(remap_rdev_key_for_mode(
|
||||
mode,
|
||||
rdev::linux_key_from_code(code),
|
||||
))
|
||||
.unwrap_or_default(),
|
||||
};
|
||||
msg.set_chr(key);
|
||||
}
|
||||
|
|
@ -1889,21 +1942,16 @@ impl<T: InvokeUiSession> Interface for Session<T> {
|
|||
}
|
||||
|
||||
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 {
|
||||
let mode = self.modifier_swap_mode();
|
||||
if mode != ModifierSwapMode::None {
|
||||
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)
|
||||
hbb_common::protobuf::EnumOrUnknown::new(remap_control_key_for_mode(
|
||||
mode,
|
||||
ck.enum_value_or_default(),
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
};
|
||||
|
|
@ -2053,3 +2101,64 @@ async fn send_note(url: String, id: String, sid: u64, note: String) {
|
|||
let body = serde_json::json!({ "id": id, "session_id": sid, "note": note });
|
||||
allow_err!(crate::post_request(url, body.to_string(), "").await);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn modifier_swap_mode_prefers_option_command_when_both_enabled() {
|
||||
assert_eq!(
|
||||
modifier_swap_mode(true, true),
|
||||
ModifierSwapMode::OptionCommand
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_option_command_maps_alt_to_meta() {
|
||||
assert_eq!(
|
||||
swap_option_command_control_key(ControlKey::Alt),
|
||||
ControlKey::Meta
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_option_command_maps_meta_to_alt() {
|
||||
assert_eq!(
|
||||
swap_option_command_control_key(ControlKey::Meta),
|
||||
ControlKey::Alt
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_option_command_maps_ralt_to_meta() {
|
||||
assert_eq!(
|
||||
swap_option_command_control_key(ControlKey::RAlt),
|
||||
ControlKey::Meta
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_option_command_maps_rwin_to_alt() {
|
||||
assert_eq!(
|
||||
swap_option_command_control_key(ControlKey::RWin),
|
||||
ControlKey::Alt
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_option_command_maps_alt_rdev_to_meta_left() {
|
||||
assert_eq!(
|
||||
swap_option_command_rdev_key(rdev::Key::Alt),
|
||||
rdev::Key::MetaLeft
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn swap_option_command_maps_meta_right_rdev_to_alt() {
|
||||
assert_eq!(
|
||||
swap_option_command_rdev_key(rdev::Key::MetaRight),
|
||||
rdev::Key::Alt
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue