mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-07 13:01:11 +03:00
fix(keyboard): wayland clipboard input prompt (#14700)
* fix(keyboard): wayland clipboard input prompt Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): Simple refactor Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): clipboard input, remove unused code Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): Simple refactor Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): dialog, better enableAndContinue Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input dialog consent Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): prompt text Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): text input 1. Use `keysym` for the installed version if possible. 2. Use the clipboard if the string cannot be fully handled by `keysym`. Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input prompt dialog Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): translations Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): dialog, title type Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): better decode_utf8_prefix() Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): better process_chr() Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): unit tests Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input prompt dialog, no icon Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input dialog, Toast show the result Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input dialog, showToast() on persist failed Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input prompt, better dialog Signed-off-by: fufesou <linlong1266@gmail.com> * fix(wayland): input prompt dialog, translations Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): better wayland clipboard input prompt Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): wayland clipboard, link external app Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): trivial changes Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): wayland clipboard input, dialog content Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): tranlsations Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): translations Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): translations Signed-off-by: fufesou <linlong1266@gmail.com> * fix(input): translations Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use arboard::{ClipboardData, ClipboardFormat};
|
||||
#[cfg(target_os = "linux")]
|
||||
use arboard::{LinuxClipboardKind, SetExtLinux};
|
||||
use hbb_common::{bail, log, message_proto::*, ResultType};
|
||||
use std::{
|
||||
sync::{Arc, Mutex},
|
||||
@@ -54,6 +56,27 @@ pub fn check_clipboard(
|
||||
side: ClipboardSide,
|
||||
force: bool,
|
||||
) -> Option<Message> {
|
||||
let (msg, clipboards) = read_clipboard_message(ctx, side, force)?;
|
||||
*LAST_MULTI_CLIPBOARDS.lock().unwrap() = clipboards;
|
||||
Some(msg)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn peek_clipboard(
|
||||
ctx: &mut Option<ClipboardContext>,
|
||||
side: ClipboardSide,
|
||||
force: bool,
|
||||
) -> Option<Message> {
|
||||
let (msg, _) = read_clipboard_message(ctx, side, force)?;
|
||||
Some(msg)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn read_clipboard_message(
|
||||
ctx: &mut Option<ClipboardContext>,
|
||||
side: ClipboardSide,
|
||||
force: bool,
|
||||
) -> Option<(Message, MultiClipboards)> {
|
||||
if ctx.is_none() {
|
||||
*ctx = ClipboardContext::new().ok();
|
||||
}
|
||||
@@ -64,8 +87,7 @@ pub fn check_clipboard(
|
||||
let mut msg = Message::new();
|
||||
let clipboards = proto::create_multi_clipboards(content);
|
||||
msg.set_multi_clipboards(clipboards.clone());
|
||||
*LAST_MULTI_CLIPBOARDS.lock().unwrap() = clipboards;
|
||||
return Some(msg);
|
||||
return Some((msg, clipboards));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -219,10 +241,7 @@ fn do_update_clipboard_(mut to_update_data: Vec<ClipboardData>, side: ClipboardS
|
||||
}
|
||||
}
|
||||
if let Some(ctx) = ctx.as_mut() {
|
||||
to_update_data.push(ClipboardData::Special((
|
||||
RUSTDESK_CLIPBOARD_OWNER_FORMAT.to_owned(),
|
||||
side.get_owner_data(),
|
||||
)));
|
||||
to_update_data = append_owner_marker(to_update_data, side);
|
||||
if let Err(e) = ctx.set(&to_update_data) {
|
||||
log::debug!("Failed to set clipboard: {}", e);
|
||||
} else {
|
||||
@@ -231,6 +250,29 @@ fn do_update_clipboard_(mut to_update_data: Vec<ClipboardData>, side: ClipboardS
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
fn append_owner_marker(mut data: Vec<ClipboardData>, side: ClipboardSide) -> Vec<ClipboardData> {
|
||||
data.push(ClipboardData::Special((
|
||||
RUSTDESK_CLIPBOARD_OWNER_FORMAT.to_owned(),
|
||||
side.get_owner_data(),
|
||||
)));
|
||||
data
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn set_text_clipboard_with_owner_sync(text: &str, side: ClipboardSide) -> ResultType<()> {
|
||||
let mut ctx = CLIPBOARD_CTX.lock().unwrap();
|
||||
if ctx.is_none() {
|
||||
*ctx = Some(ClipboardContext::new()?);
|
||||
}
|
||||
let clipboard_ctx = match ctx.as_mut() {
|
||||
Some(ctx) => ctx,
|
||||
None => bail!("Failed to create clipboard context"),
|
||||
};
|
||||
let data = append_owner_marker(vec![ClipboardData::Text(text.to_owned())], side);
|
||||
clipboard_ctx.set_with_owner_marker_for_linux(&data)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub fn update_clipboard(multi_clipboards: Vec<Clipboard>, side: ClipboardSide) {
|
||||
std::thread::spawn(move || {
|
||||
@@ -382,6 +424,24 @@ impl ClipboardContext {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn set_with_owner_marker_for_linux(&mut self, data: &[ClipboardData]) -> ResultType<()> {
|
||||
let _lock = ARBOARD_MTX.lock().unwrap();
|
||||
self.inner
|
||||
.set()
|
||||
.clipboard(LinuxClipboardKind::Clipboard)
|
||||
.formats(data)?;
|
||||
if let Err(e) = self
|
||||
.inner
|
||||
.set()
|
||||
.clipboard(LinuxClipboardKind::Primary)
|
||||
.formats(data)
|
||||
{
|
||||
log::warn!("Failed to set PRIMARY clipboard with owner marker: {}", e);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "unix-file-copy-paste", target_os = "macos"))]
|
||||
fn get_file_urls_set_by_rustdesk(
|
||||
data: Vec<ClipboardData>,
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", "服务器要求显式部署此设备。是否立即部署?"),
|
||||
("The server does not require explicit deployment.", "服务器不需要显式部署。"),
|
||||
("Unknown response.", "未知响应。"),
|
||||
("wayland-keyboard-input-disabled-tip", "允许键盘输入?"),
|
||||
("wayland-keyboard-input-consent-tip", "你在这台远程电脑上输入的内容(包括密码)可能被远程电脑上的其他程序读取。"),
|
||||
("wayland-keyboard-input-applies-to-tip", "此选择适用于:"),
|
||||
("wayland-soft-keyboard-input-label", "软键盘输入"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "重置键盘输入选择"),
|
||||
("remember-wayland-keyboard-choice-tip", "以后对这台远程电脑不再询问"),
|
||||
("Why this happens", "了解原因"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -276,5 +276,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("preset-password-in-use-tip", "Preset password is currently in use."),
|
||||
("allow-remote-toolbar-docking-any-edge", "Allow docking remote toolbar to any window edge"),
|
||||
("server_requires_deployment_tip", "The server requires this device to be deployed explicitly. Deploy now?"),
|
||||
("wayland-keyboard-input-disabled-tip", "Allow keyboard input?"),
|
||||
("wayland-keyboard-input-consent-tip", "What you type on this remote computer (including passwords) could be read by other apps on it."),
|
||||
("wayland-keyboard-input-applies-to-tip", "This choice applies to:"),
|
||||
("wayland-soft-keyboard-input-label", "Soft keyboard input"),
|
||||
("wayland-keyboard-input-reset-choice-tip", "Reset keyboard input choice"),
|
||||
("remember-wayland-keyboard-choice-tip", "Don't ask again for this remote computer"),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", "Il server richiede che questo dispositivo venga distribuito in modo esplicito.\nVuoi distribuirlo?"),
|
||||
("The server does not require explicit deployment.", "Il server non richiede una distribuzione esplicita."),
|
||||
("Unknown response.", "Risposta sconosciuta"),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -751,5 +751,12 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
||||
("server_requires_deployment_tip", ""),
|
||||
("The server does not require explicit deployment.", ""),
|
||||
("Unknown response.", ""),
|
||||
("wayland-keyboard-input-disabled-tip", ""),
|
||||
("wayland-keyboard-input-consent-tip", ""),
|
||||
("wayland-keyboard-input-applies-to-tip", ""),
|
||||
("wayland-soft-keyboard-input-label", ""),
|
||||
("wayland-keyboard-input-reset-choice-tip", ""),
|
||||
("remember-wayland-keyboard-choice-tip", ""),
|
||||
("Why this happens", ""),
|
||||
].iter().cloned().collect();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::*;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use crate::clipboard::clipboard_listener;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
pub use crate::clipboard::{check_clipboard, ClipboardContext, ClipboardSide};
|
||||
pub use crate::clipboard::{ClipboardContext, ClipboardSide};
|
||||
pub use crate::clipboard::{CLIPBOARD_INTERVAL as INTERVAL, CLIPBOARD_NAME as NAME};
|
||||
#[cfg(windows)]
|
||||
use crate::ipc::{self, ClipboardFile, ClipboardNonFile, Data};
|
||||
@@ -109,6 +109,62 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
const WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES: usize =
|
||||
super::input_service::WAYLAND_CLIPBOARD_INPUT_MAX_TEXT_CHARS * 4;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn decode_utf8_prefix(bytes: &[u8]) -> Option<String> {
|
||||
let end = bytes.len().min(WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES);
|
||||
let slice = &bytes[..end];
|
||||
match std::str::from_utf8(slice) {
|
||||
Ok(text) => Some(text.to_owned()),
|
||||
Err(e) => {
|
||||
if e.error_len().is_some() {
|
||||
return None;
|
||||
}
|
||||
let valid_up_to = e.valid_up_to();
|
||||
std::str::from_utf8(&slice[..valid_up_to])
|
||||
.ok()
|
||||
.map(ToOwned::to_owned)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn decode_text_clipboard(clipboard: &Clipboard) -> Option<String> {
|
||||
if clipboard.format.enum_value() != Ok(ClipboardFormat::Text) {
|
||||
return None;
|
||||
}
|
||||
if clipboard.compress {
|
||||
let bytes = hbb_common::compress::decompress(&clipboard.content);
|
||||
return decode_utf8_prefix(&bytes);
|
||||
}
|
||||
decode_utf8_prefix(&clipboard.content)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn should_skip_wayland_clipboard_sync(msg: &Message) -> bool {
|
||||
if crate::platform::linux::is_x11() {
|
||||
return false;
|
||||
}
|
||||
let is_recent_wayland_input = |clipboard: &Clipboard| -> bool {
|
||||
let Some(text) = decode_text_clipboard(clipboard) else {
|
||||
return false;
|
||||
};
|
||||
super::input_service::is_recent_wayland_clipboard_input(&text)
|
||||
};
|
||||
|
||||
match &msg.union {
|
||||
Some(message::Union::Clipboard(clipboard)) => is_recent_wayland_input(clipboard),
|
||||
Some(message::Union::MultiClipboards(multi_clipboards)) => multi_clipboards
|
||||
.clipboards
|
||||
.iter()
|
||||
.any(is_recent_wayland_input),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
impl Handler {
|
||||
#[cfg(feature = "unix-file-copy-paste")]
|
||||
@@ -172,7 +228,19 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
check_clipboard(&mut self.ctx, ClipboardSide::Host, false)
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let msg = crate::clipboard::peek_clipboard(&mut self.ctx, ClipboardSide::Host, false)?;
|
||||
if should_skip_wayland_clipboard_sync(&msg) {
|
||||
log::debug!("Skip clipboard sync for recent Wayland keyboard injection");
|
||||
return None;
|
||||
}
|
||||
return Some(msg);
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
crate::clipboard::check_clipboard(&mut self.ctx, ClipboardSide::Host, false)
|
||||
}
|
||||
}
|
||||
|
||||
// Read clipboard data from cm using ipc.
|
||||
@@ -272,3 +340,46 @@ fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
|
||||
CLIPBOARD_SERVICE_OK.store(false, Ordering::SeqCst);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[cfg(target_os = "linux")]
|
||||
mod tests {
|
||||
use super::{decode_utf8_prefix, WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES};
|
||||
|
||||
#[test]
|
||||
fn decode_utf8_prefix_returns_text_for_valid_utf8() {
|
||||
let text = "hello-مرحبا";
|
||||
assert_eq!(decode_utf8_prefix(text.as_bytes()), Some(text.to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_utf8_prefix_returns_none_for_invalid_utf8_sequence() {
|
||||
let bytes = b"ab\xffcd";
|
||||
assert_eq!(decode_utf8_prefix(bytes), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_utf8_prefix_trims_incomplete_utf8_suffix() {
|
||||
let bytes = vec![b'a', 0xE4, 0xB8];
|
||||
assert_eq!(decode_utf8_prefix(&bytes), Some("a".to_owned()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_utf8_prefix_applies_max_bytes_limit() {
|
||||
let bytes = vec![b'a'; WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES + 8];
|
||||
let result = decode_utf8_prefix(&bytes).expect("expected decoded prefix");
|
||||
assert_eq!(result.len(), WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_utf8_prefix_keeps_utf8_boundary_when_limited() {
|
||||
let mut bytes = vec![b'a'; WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES - 1];
|
||||
bytes.extend_from_slice("ا".as_bytes());
|
||||
let result = decode_utf8_prefix(&bytes).expect("expected decoded prefix");
|
||||
assert_eq!(
|
||||
result.len(),
|
||||
WAYLAND_CLIPBOARD_SKIP_CHECK_MAX_UTF8_BYTES - 1
|
||||
);
|
||||
assert!(result.chars().all(|c| c == 'a'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,6 +457,12 @@ lazy_static::lazy_static! {
|
||||
static ref RELATIVE_MOUSE_CONNS: Arc<Mutex<std::collections::HashSet<i32>>> = Default::default();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
lazy_static::lazy_static! {
|
||||
static ref WAYLAND_CLIPBOARD_INPUT_RECORDS: Arc<Mutex<Vec<(Instant, String)>>> =
|
||||
Default::default();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_relative_mouse_active(conn: i32, active: bool) {
|
||||
let mut lock = RELATIVE_MOUSE_CONNS.lock().unwrap();
|
||||
@@ -1594,15 +1600,28 @@ fn need_to_uppercase(en: &mut Enigo) -> bool {
|
||||
}
|
||||
|
||||
fn process_chr(en: &mut Enigo, chr: u32, down: bool, _hotkey: bool) {
|
||||
// On Wayland with uinput mode, use clipboard for character input
|
||||
// On Wayland with uinput mode:
|
||||
// - ASCII printable: input via key events (custom keyboard path, e.g. portal keysym)
|
||||
// - Non-ASCII: input via clipboard paste
|
||||
#[cfg(target_os = "linux")]
|
||||
if !crate::platform::linux::is_x11() && wayland_use_uinput() {
|
||||
// Skip clipboard for hotkeys (Ctrl/Alt/Meta pressed)
|
||||
if !is_hotkey_modifier_pressed(en) {
|
||||
if down {
|
||||
if let Ok(c) = char::try_from(chr) {
|
||||
if let Ok(c) = char::try_from(chr) {
|
||||
if is_ascii_printable(c) {
|
||||
if down {
|
||||
en.key_down(Key::Layout(c)).ok();
|
||||
} else {
|
||||
en.key_up(Key::Layout(c));
|
||||
}
|
||||
} else if down {
|
||||
input_char_via_clipboard_server(en, c);
|
||||
}
|
||||
} else {
|
||||
log::warn!(
|
||||
"Ignore invalid unicode scalar in Wayland+uinput path: {}",
|
||||
chr
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1637,11 +1656,17 @@ fn process_chr(en: &mut Enigo, chr: u32, down: bool, _hotkey: bool) {
|
||||
}
|
||||
|
||||
fn process_unicode(en: &mut Enigo, chr: u32) {
|
||||
// On Wayland with uinput mode, use clipboard for character input
|
||||
// On Wayland with uinput mode:
|
||||
// - ASCII printable: input via key sequence (custom keyboard path)
|
||||
// - Non-ASCII: input via clipboard paste
|
||||
#[cfg(target_os = "linux")]
|
||||
if !crate::platform::linux::is_x11() && wayland_use_uinput() {
|
||||
if let Ok(c) = char::try_from(chr) {
|
||||
input_char_via_clipboard_server(en, c);
|
||||
if is_ascii_printable(c) {
|
||||
en.key_sequence(&c.to_string());
|
||||
} else {
|
||||
input_char_via_clipboard_server(en, c);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1652,10 +1677,16 @@ fn process_unicode(en: &mut Enigo, chr: u32) {
|
||||
}
|
||||
|
||||
fn process_seq(en: &mut Enigo, sequence: &str) {
|
||||
// On Wayland with uinput mode, use clipboard for text input
|
||||
// On Wayland with uinput mode:
|
||||
// - pure ASCII printable sequence: input via key sequence (custom keyboard path)
|
||||
// - any non-ASCII present: input whole sequence via clipboard to preserve order
|
||||
#[cfg(target_os = "linux")]
|
||||
if !crate::platform::linux::is_x11() && wayland_use_uinput() {
|
||||
input_text_via_clipboard_server(en, sequence);
|
||||
if sequence.chars().all(is_ascii_printable) {
|
||||
en.key_sequence(sequence);
|
||||
} else {
|
||||
input_text_via_clipboard_server(en, sequence);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1668,40 +1699,103 @@ fn process_seq(en: &mut Enigo, sequence: &str) {
|
||||
/// this delay may be insufficient, but there is no reliable alternative mechanism.
|
||||
#[cfg(target_os = "linux")]
|
||||
const CLIPBOARD_SYNC_DELAY_MS: u64 = 50;
|
||||
#[cfg(target_os = "linux")]
|
||||
const WAYLAND_CLIPBOARD_INPUT_FILTER_WINDOW: Duration = Duration::from_secs(1);
|
||||
#[cfg(target_os = "linux")]
|
||||
const WAYLAND_CLIPBOARD_INPUT_MAX_RECORDS: usize = 256;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(super) const WAYLAND_CLIPBOARD_INPUT_MAX_TEXT_CHARS: usize = 1024;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn cleanup_wayland_clipboard_input_records(records: &mut Vec<(Instant, String)>, now: Instant) {
|
||||
records.retain(|(created_at, _)| {
|
||||
now.saturating_duration_since(*created_at) <= WAYLAND_CLIPBOARD_INPUT_FILTER_WINDOW
|
||||
});
|
||||
let len = records.len();
|
||||
if len > WAYLAND_CLIPBOARD_INPUT_MAX_RECORDS {
|
||||
records.drain(0..(len - WAYLAND_CLIPBOARD_INPUT_MAX_RECORDS));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
fn normalize_wayland_clipboard_input_text(text: &str) -> String {
|
||||
text.chars()
|
||||
.take(WAYLAND_CLIPBOARD_INPUT_MAX_TEXT_CHARS)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
fn get_wayland_clipboard_input_normalized_text(text: &str) -> Option<String> {
|
||||
let normalized = normalize_wayland_clipboard_input_text(text);
|
||||
if normalized.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Some(normalized)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
fn record_wayland_clipboard_input_for_sync_filter(text: &str) -> Option<(Instant, String)> {
|
||||
if text.is_empty() || crate::platform::linux::is_x11() {
|
||||
return None;
|
||||
}
|
||||
let normalized = get_wayland_clipboard_input_normalized_text(text)?;
|
||||
let now = Instant::now();
|
||||
let mut records = WAYLAND_CLIPBOARD_INPUT_RECORDS.lock().unwrap();
|
||||
cleanup_wayland_clipboard_input_records(&mut records, now);
|
||||
records.push((now, normalized.clone()));
|
||||
Some((now, normalized))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
fn rollback_wayland_clipboard_input_record(record: (Instant, String)) {
|
||||
let (created_at, normalized) = record;
|
||||
let now = Instant::now();
|
||||
let mut records = WAYLAND_CLIPBOARD_INPUT_RECORDS.lock().unwrap();
|
||||
cleanup_wayland_clipboard_input_records(&mut records, now);
|
||||
if let Some(pos) = records
|
||||
.iter()
|
||||
.rposition(|(record_created_at, record_normalized)| {
|
||||
*record_created_at == created_at && *record_normalized == normalized
|
||||
})
|
||||
{
|
||||
records.remove(pos);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub(super) fn is_recent_wayland_clipboard_input(text: &str) -> bool {
|
||||
if text.is_empty() || crate::platform::linux::is_x11() {
|
||||
return false;
|
||||
}
|
||||
let Some(normalized) = get_wayland_clipboard_input_normalized_text(text) else {
|
||||
return false;
|
||||
};
|
||||
let now = Instant::now();
|
||||
let mut records = WAYLAND_CLIPBOARD_INPUT_RECORDS.lock().unwrap();
|
||||
cleanup_wayland_clipboard_input_records(&mut records, now);
|
||||
records
|
||||
.iter()
|
||||
.any(|(_, record_normalized)| record_normalized == &normalized)
|
||||
}
|
||||
|
||||
/// Internal: Set clipboard content without delay.
|
||||
/// Returns true if clipboard was set successfully.
|
||||
#[cfg(target_os = "linux")]
|
||||
fn set_clipboard_content(text: &str) -> bool {
|
||||
use arboard::{Clipboard, LinuxClipboardKind, SetExtLinux};
|
||||
|
||||
let mut clipboard = match Clipboard::new() {
|
||||
Ok(cb) => cb,
|
||||
Err(e) => {
|
||||
log::error!("set_clipboard_content: failed to create clipboard: {:?}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Set both CLIPBOARD and PRIMARY selections
|
||||
// Terminal uses PRIMARY for Shift+Insert, GUI apps use CLIPBOARD
|
||||
if let Err(e) = clipboard
|
||||
.set()
|
||||
.clipboard(LinuxClipboardKind::Clipboard)
|
||||
.text(text.to_owned())
|
||||
{
|
||||
log::error!("set_clipboard_content: failed to set CLIPBOARD: {:?}", e);
|
||||
if let Err(e) = crate::clipboard::set_text_clipboard_with_owner_sync(
|
||||
text,
|
||||
crate::clipboard::ClipboardSide::Host,
|
||||
) {
|
||||
log::error!(
|
||||
"set_clipboard_content: failed to set clipboard with owner marker: {:?}",
|
||||
e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if let Err(e) = clipboard
|
||||
.set()
|
||||
.clipboard(LinuxClipboardKind::Primary)
|
||||
.text(text.to_owned())
|
||||
{
|
||||
log::warn!("set_clipboard_content: failed to set PRIMARY: {:?}", e);
|
||||
// Continue anyway, CLIPBOARD might work
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1714,7 +1808,11 @@ fn set_clipboard_content(text: &str) -> bool {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[inline]
|
||||
pub(super) fn set_clipboard_for_paste_sync(text: &str) -> bool {
|
||||
let record = record_wayland_clipboard_input_for_sync_filter(text);
|
||||
if !set_clipboard_content(text) {
|
||||
if let Some(record) = record {
|
||||
rollback_wayland_clipboard_input_record(record);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(CLIPBOARD_SYNC_DELAY_MS));
|
||||
@@ -1916,49 +2014,53 @@ fn translate_process_code(code: u32, down: bool) {
|
||||
fn translate_keyboard_mode(evt: &KeyEvent) {
|
||||
match &evt.union {
|
||||
Some(key_event::Union::Seq(seq)) => {
|
||||
// On Wayland, handle character input directly in this (--server) process using clipboard.
|
||||
// This function runs in the --server process (logged-in user session), which has
|
||||
// WAYLAND_DISPLAY and XDG_RUNTIME_DIR — so clipboard operations work here.
|
||||
//
|
||||
// Why not let it go through uinput IPC:
|
||||
// 1. For uinput mode: the uinput service thread runs in the --service (root) process,
|
||||
// which typically lacks user session environment. Clipboard operations there are
|
||||
// unreliable. Handling clipboard here avoids that issue.
|
||||
// 2. For RDP input mode: Portal's notify_keyboard_keysym API interprets keysyms
|
||||
// based on its internal modifier state, which may not match our released state.
|
||||
// Using clipboard bypasses this issue entirely.
|
||||
// On Wayland:
|
||||
// - uinput mode (--service): keep clipboard handling in this process because
|
||||
// clipboard is unreliable in root service context.
|
||||
// - rdp_input mode (--server): forward sequence to custom keyboard handler so
|
||||
// ASCII can use Portal keysym and non-ASCII can use clipboard.
|
||||
#[cfg(target_os = "linux")]
|
||||
if !crate::platform::linux::is_x11() {
|
||||
let mut en = ENIGO.lock().unwrap();
|
||||
|
||||
// Check if this is a hotkey (Ctrl/Alt/Meta pressed)
|
||||
// For hotkeys, we send character-based key events via Enigo instead of
|
||||
// using the clipboard. This relies on the local keyboard layout for
|
||||
// mapping characters to physical keys.
|
||||
// This assumes client and server use the same keyboard layout (common case).
|
||||
// Note: For non-Latin keyboards (e.g., Arabic), hotkeys may not work
|
||||
// correctly if the character cannot be mapped to a key via KEY_MAP_LAYOUT.
|
||||
// This is a known limitation - most common hotkeys (Ctrl+A/C/V/Z) use Latin
|
||||
// characters which are mappable on most keyboard layouts.
|
||||
if is_hotkey_modifier_pressed(&mut en) {
|
||||
// For hotkeys, send character-based key events via Enigo.
|
||||
// This relies on the local keyboard layout mapping (KEY_MAP_LAYOUT).
|
||||
for chr in seq.chars() {
|
||||
if !is_ascii_printable(chr) {
|
||||
log::warn!(
|
||||
"Hotkey with non-ASCII character may not work correctly on non-Latin keyboard layouts"
|
||||
);
|
||||
}
|
||||
en.key_click(Key::Layout(chr));
|
||||
}
|
||||
if wayland_use_rdp_input() {
|
||||
release_shift_for_char_input(&mut en);
|
||||
en.key_sequence(seq);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal text input: release Shift and use clipboard
|
||||
release_shift_for_char_input(&mut en);
|
||||
if wayland_use_uinput() {
|
||||
// Check if this is a hotkey (Ctrl/Alt/Meta pressed)
|
||||
// For hotkeys, we send character-based key events via Enigo instead of
|
||||
// using the clipboard. This relies on the local keyboard layout for
|
||||
// mapping characters to physical keys.
|
||||
// This assumes client and server use the same keyboard layout (common case).
|
||||
// Note: For non-Latin keyboards (e.g., Arabic), hotkeys may not work
|
||||
// correctly if the character cannot be mapped to a key via KEY_MAP_LAYOUT.
|
||||
// This is a known limitation - most common hotkeys (Ctrl+A/C/V/Z) use Latin
|
||||
// characters which are mappable on most keyboard layouts.
|
||||
if is_hotkey_modifier_pressed(&mut en) {
|
||||
// For hotkeys, send character-based key events via Enigo.
|
||||
// This relies on the local keyboard layout mapping (KEY_MAP_LAYOUT).
|
||||
for chr in seq.chars() {
|
||||
if !is_ascii_printable(chr) {
|
||||
log::warn!(
|
||||
"Hotkey with non-ASCII character may not work correctly on non-Latin keyboard layouts"
|
||||
);
|
||||
}
|
||||
en.key_click(Key::Layout(chr));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
input_text_via_clipboard_server(&mut en, seq);
|
||||
return;
|
||||
// Normal text input: release Shift and use clipboard
|
||||
release_shift_for_char_input(&mut en);
|
||||
if seq.chars().all(is_ascii_printable) {
|
||||
en.key_sequence(seq);
|
||||
} else {
|
||||
input_text_via_clipboard_server(&mut en, seq);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fr -> US
|
||||
|
||||
@@ -118,6 +118,23 @@ pub mod client {
|
||||
}
|
||||
|
||||
fn key_sequence(&mut self, s: &str) {
|
||||
if s.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep ordering deterministic:
|
||||
// - pure ASCII printable: send via Portal keysym
|
||||
// - any non-ASCII present (including mixed ASCII/non-ASCII): send whole
|
||||
// sequence via clipboard as one atomic paste
|
||||
let ascii_only = s.chars().all(|c| {
|
||||
let keysym = char_to_keysym(c);
|
||||
can_input_via_keysym(c, keysym)
|
||||
});
|
||||
if !ascii_only {
|
||||
input_text_via_clipboard(s, self.conn.clone(), &self.session);
|
||||
return;
|
||||
}
|
||||
|
||||
for c in s.chars() {
|
||||
let keysym = char_to_keysym(c);
|
||||
// ASCII characters: use keysym
|
||||
@@ -128,9 +145,6 @@ pub mod client {
|
||||
if let Err(e) = send_keysym(keysym, false, self.conn.clone(), &self.session) {
|
||||
log::error!("Failed to send keysym up: {:?}", e);
|
||||
}
|
||||
} else {
|
||||
// Non-ASCII: use clipboard
|
||||
input_text_via_clipboard(&c.to_string(), self.conn.clone(), &self.session);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,8 +181,7 @@ pub mod client {
|
||||
// ASCII characters: send keysym up if we also sent it on key_down
|
||||
let keysym = char_to_keysym(chr);
|
||||
if can_input_via_keysym(chr, keysym) {
|
||||
if let Err(e) = send_keysym(keysym, false, self.conn.clone(), &self.session)
|
||||
{
|
||||
if let Err(e) = send_keysym(keysym, false, self.conn.clone(), &self.session) {
|
||||
log::error!("Failed to send keysym up: {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user