fix: wayland, rdp input, mouse, scale (#9402)
* fix: wayland, rdp input, mouse, scale Signed-off-by: fufesou <linlong1266@gmail.com> * fix: rdp input, mouse, scale, check 0 Signed-off-by: fufesou <linlong1266@gmail.com> --------- Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
parent
3d5262c36f
commit
21bcfd173d
@ -7,6 +7,9 @@ lazy_static::lazy_static! {
|
|||||||
|
|
||||||
pub const DISPLAY_SERVER_WAYLAND: &str = "wayland";
|
pub const DISPLAY_SERVER_WAYLAND: &str = "wayland";
|
||||||
pub const DISPLAY_SERVER_X11: &str = "x11";
|
pub const DISPLAY_SERVER_X11: &str = "x11";
|
||||||
|
pub const DISPLAY_DESKTOP_KDE: &str = "KDE";
|
||||||
|
|
||||||
|
pub const XDG_CURRENT_DESKTOP: &str = "XDG_CURRENT_DESKTOP";
|
||||||
|
|
||||||
pub struct Distro {
|
pub struct Distro {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
@ -29,6 +32,15 @@ impl Distro {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_kde() -> bool {
|
||||||
|
if let Ok(env) = std::env::var(XDG_CURRENT_DESKTOP) {
|
||||||
|
env == DISPLAY_DESKTOP_KDE
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_gdm_user(username: &str) -> bool {
|
pub fn is_gdm_user(username: &str) -> bool {
|
||||||
username == "gdm"
|
username == "gdm"
|
||||||
|
@ -27,39 +27,40 @@ use super::screencast_portal::OrgFreedesktopPortalScreenCast as screencast_porta
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref RDP_RESPONSE: Mutex<Option<RdpResponse>> = Mutex::new(None);
|
pub static ref RDP_SESSION_INFO: Mutex<Option<RdpSessionInfo>> = Mutex::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn close_session() {
|
pub fn close_session() {
|
||||||
let _ = RDP_RESPONSE.lock().unwrap().take();
|
let _ = RDP_SESSION_INFO.lock().unwrap().take();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_rdp_session_hold() -> bool {
|
pub fn is_rdp_session_hold() -> bool {
|
||||||
RDP_RESPONSE.lock().unwrap().is_some()
|
RDP_SESSION_INFO.lock().unwrap().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn try_close_session() {
|
pub fn try_close_session() {
|
||||||
let mut rdp_res = RDP_RESPONSE.lock().unwrap();
|
let mut rdp_info = RDP_SESSION_INFO.lock().unwrap();
|
||||||
let mut close = false;
|
let mut close = false;
|
||||||
if let Some(rdp_res) = &*rdp_res {
|
if let Some(rdp_info) = &*rdp_info {
|
||||||
// If is server running and restore token is supported, there's no need to keep the session.
|
// If is server running and restore token is supported, there's no need to keep the session.
|
||||||
if is_server_running() && rdp_res.is_support_restore_token {
|
if is_server_running() && rdp_info.is_support_restore_token {
|
||||||
close = true;
|
close = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if close {
|
if close {
|
||||||
*rdp_res = None;
|
*rdp_info = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RdpResponse {
|
pub struct RdpSessionInfo {
|
||||||
pub conn: Arc<SyncConnection>,
|
pub conn: Arc<SyncConnection>,
|
||||||
pub streams: Vec<PwStreamInfo>,
|
pub streams: Vec<PwStreamInfo>,
|
||||||
pub fd: OwnedFd,
|
pub fd: OwnedFd,
|
||||||
pub session: dbus::Path<'static>,
|
pub session: dbus::Path<'static>,
|
||||||
pub is_support_restore_token: bool,
|
pub is_support_restore_token: bool,
|
||||||
|
pub resolution: Arc<Mutex<Option<(usize, usize)>>>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct PwStreamInfo {
|
pub struct PwStreamInfo {
|
||||||
@ -69,6 +70,12 @@ pub struct PwStreamInfo {
|
|||||||
size: (usize, usize),
|
size: (usize, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PwStreamInfo {
|
||||||
|
pub fn get_size(&self) -> (usize, usize) {
|
||||||
|
self.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DBusError(String);
|
pub struct DBusError(String);
|
||||||
|
|
||||||
@ -105,24 +112,31 @@ pub struct PipeWireCapturable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PipeWireCapturable {
|
impl PipeWireCapturable {
|
||||||
fn new(conn: Arc<SyncConnection>, fd: OwnedFd, stream: PwStreamInfo) -> Self {
|
fn new(
|
||||||
|
conn: Arc<SyncConnection>,
|
||||||
|
fd: OwnedFd,
|
||||||
|
resolution: Arc<Mutex<Option<(usize, usize)>>>,
|
||||||
|
stream: PwStreamInfo,
|
||||||
|
) -> Self {
|
||||||
// alternative to get screen resolution as stream.size is not always correct ex: on fractional scaling
|
// alternative to get screen resolution as stream.size is not always correct ex: on fractional scaling
|
||||||
// https://github.com/rustdesk/rustdesk/issues/6116#issuecomment-1817724244
|
// https://github.com/rustdesk/rustdesk/issues/6116#issuecomment-1817724244
|
||||||
let res = get_res(Self {
|
let size = get_res(Self {
|
||||||
dbus_conn: conn.clone(),
|
dbus_conn: conn.clone(),
|
||||||
fd: fd.clone(),
|
fd: fd.clone(),
|
||||||
path: stream.path,
|
path: stream.path,
|
||||||
source_type: stream.source_type,
|
source_type: stream.source_type,
|
||||||
position: stream.position,
|
position: stream.position,
|
||||||
size: stream.size,
|
size: stream.size,
|
||||||
});
|
})
|
||||||
|
.unwrap_or(stream.size);
|
||||||
|
*resolution.lock().unwrap() = Some(size);
|
||||||
Self {
|
Self {
|
||||||
dbus_conn: conn,
|
dbus_conn: conn,
|
||||||
fd,
|
fd,
|
||||||
path: stream.path,
|
path: stream.path,
|
||||||
source_type: stream.source_type,
|
source_type: stream.source_type,
|
||||||
position: stream.position,
|
position: stream.position,
|
||||||
size: res.unwrap_or(stream.size),
|
size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -813,7 +827,7 @@ fn on_start_response(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_capturables() -> Result<Vec<PipeWireCapturable>, Box<dyn Error>> {
|
pub fn get_capturables() -> Result<Vec<PipeWireCapturable>, Box<dyn Error>> {
|
||||||
let mut rdp_connection = match RDP_RESPONSE.lock() {
|
let mut rdp_connection = match RDP_SESSION_INFO.lock() {
|
||||||
Ok(conn) => conn,
|
Ok(conn) => conn,
|
||||||
Err(err) => return Err(Box::new(err)),
|
Err(err) => return Err(Box::new(err)),
|
||||||
};
|
};
|
||||||
@ -822,28 +836,36 @@ pub fn get_capturables() -> Result<Vec<PipeWireCapturable>, Box<dyn Error>> {
|
|||||||
let (conn, fd, streams, session, is_support_restore_token) = request_remote_desktop()?;
|
let (conn, fd, streams, session, is_support_restore_token) = request_remote_desktop()?;
|
||||||
let conn = Arc::new(conn);
|
let conn = Arc::new(conn);
|
||||||
|
|
||||||
let rdp_res = RdpResponse {
|
let rdp_info = RdpSessionInfo {
|
||||||
conn,
|
conn,
|
||||||
streams,
|
streams,
|
||||||
fd,
|
fd,
|
||||||
session,
|
session,
|
||||||
is_support_restore_token,
|
is_support_restore_token,
|
||||||
|
resolution: Arc::new(Mutex::new(None)),
|
||||||
};
|
};
|
||||||
*rdp_connection = Some(rdp_res);
|
*rdp_connection = Some(rdp_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rdp_res = match rdp_connection.as_ref() {
|
let rdp_info = match rdp_connection.as_ref() {
|
||||||
Some(res) => res,
|
Some(res) => res,
|
||||||
None => {
|
None => {
|
||||||
return Err(Box::new(DBusError("RDP response is None.".into())));
|
return Err(Box::new(DBusError("RDP response is None.".into())));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(rdp_res
|
Ok(rdp_info
|
||||||
.streams
|
.streams
|
||||||
.clone()
|
.clone()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|s| PipeWireCapturable::new(rdp_res.conn.clone(), rdp_res.fd.clone(), s))
|
.map(|s| {
|
||||||
|
PipeWireCapturable::new(
|
||||||
|
rdp_info.conn.clone(),
|
||||||
|
rdp_info.fd.clone(),
|
||||||
|
rdp_info.resolution.clone(),
|
||||||
|
s,
|
||||||
|
)
|
||||||
|
})
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ use rdev::{self, EventType, Key as RdevKey, KeyCode, RawKey};
|
|||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use rdev::{CGEventSourceStateID, CGEventTapLocation, VirtualInput};
|
use rdev::{CGEventSourceStateID, CGEventTapLocation, VirtualInput};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use scrap::wayland::pipewire::RDP_RESPONSE;
|
use scrap::wayland::pipewire::RDP_SESSION_INFO;
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
ops::{Deref, DerefMut, Sub},
|
ops::{Deref, DerefMut, Sub},
|
||||||
@ -521,15 +521,25 @@ pub async fn setup_uinput(minx: i32, maxx: i32, miny: i32, maxy: i32) -> ResultT
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub async fn setup_rdp_input() -> ResultType<(), Box<dyn std::error::Error>> {
|
pub async fn setup_rdp_input() -> ResultType<(), Box<dyn std::error::Error>> {
|
||||||
let mut en = ENIGO.lock()?;
|
let mut en = ENIGO.lock()?;
|
||||||
let rdp_res_lock = RDP_RESPONSE.lock()?;
|
let rdp_info_lock = RDP_SESSION_INFO.lock()?;
|
||||||
let rdp_res = rdp_res_lock.as_ref().ok_or("RDP response is None")?;
|
let rdp_info = rdp_info_lock.as_ref().ok_or("RDP session is None")?;
|
||||||
|
|
||||||
let keyboard = RdpInputKeyboard::new(rdp_res.conn.clone(), rdp_res.session.clone())?;
|
let keyboard = RdpInputKeyboard::new(rdp_info.conn.clone(), rdp_info.session.clone())?;
|
||||||
en.set_custom_keyboard(Box::new(keyboard));
|
en.set_custom_keyboard(Box::new(keyboard));
|
||||||
log::info!("RdpInput keyboard created");
|
log::info!("RdpInput keyboard created");
|
||||||
|
|
||||||
if let Some(stream) = rdp_res.streams.clone().into_iter().next() {
|
if let Some(stream) = rdp_info.streams.clone().into_iter().next() {
|
||||||
let mouse = RdpInputMouse::new(rdp_res.conn.clone(), rdp_res.session.clone(), stream)?;
|
let resolution = rdp_info
|
||||||
|
.resolution
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap_or(stream.get_size());
|
||||||
|
let mouse = RdpInputMouse::new(
|
||||||
|
rdp_info.conn.clone(),
|
||||||
|
rdp_info.session.clone(),
|
||||||
|
stream,
|
||||||
|
resolution,
|
||||||
|
)?;
|
||||||
en.set_custom_mouse(Box::new(mouse));
|
en.set_custom_mouse(Box::new(mouse));
|
||||||
log::info!("RdpInput mouse created");
|
log::info!("RdpInput mouse created");
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub mod client {
|
pub mod client {
|
||||||
|
use hbb_common::platform::linux::is_kde;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const EVDEV_MOUSE_LEFT: i32 = 272;
|
const EVDEV_MOUSE_LEFT: i32 = 272;
|
||||||
@ -67,6 +69,8 @@ pub mod client {
|
|||||||
conn: Arc<SyncConnection>,
|
conn: Arc<SyncConnection>,
|
||||||
session: Path<'static>,
|
session: Path<'static>,
|
||||||
stream: PwStreamInfo,
|
stream: PwStreamInfo,
|
||||||
|
resolution: (usize, usize),
|
||||||
|
scale: Option<f64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RdpInputMouse {
|
impl RdpInputMouse {
|
||||||
@ -74,11 +78,32 @@ pub mod client {
|
|||||||
conn: Arc<SyncConnection>,
|
conn: Arc<SyncConnection>,
|
||||||
session: Path<'static>,
|
session: Path<'static>,
|
||||||
stream: PwStreamInfo,
|
stream: PwStreamInfo,
|
||||||
|
resolution: (usize, usize),
|
||||||
) -> ResultType<Self> {
|
) -> ResultType<Self> {
|
||||||
|
// https://github.com/rustdesk/rustdesk/pull/9019#issuecomment-2295252388
|
||||||
|
// There may be a bug in Rdp input on Gnome util Ubuntu 24.04 (Gnome 46)
|
||||||
|
//
|
||||||
|
// eg. Resultion 800x600, Fractional scale: 200% (logic size: 400x300)
|
||||||
|
// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.impl.portal.RemoteDesktop.html#:~:text=new%20pointer%20position-,in%20the%20streams%20logical%20coordinate%20space,-.
|
||||||
|
// Then (x,y) in `mouse_move_to()` and `mouse_move_relative()` should be scaled to the logic size(stream.get_size()), which is from (0,0) to (400,300).
|
||||||
|
// For Ubuntu 24.04(Gnome 46), (x,y) is restricted from (0,0) to (400,300), but the actual range in screen is:
|
||||||
|
// Logic coordinate from (0,0) to (200x150).
|
||||||
|
// Or physical coordinate from (0,0) to (400,300).
|
||||||
|
let scale = if is_kde() {
|
||||||
|
if resolution.0 == 0 || stream.get_size().0 == 0 {
|
||||||
|
Some(1.0f64)
|
||||||
|
} else {
|
||||||
|
Some(resolution.0 as f64 / stream.get_size().0 as f64)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
conn,
|
conn,
|
||||||
session,
|
session,
|
||||||
stream,
|
stream,
|
||||||
|
resolution,
|
||||||
|
scale,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,24 +118,44 @@ pub mod client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_move_to(&mut self, x: i32, y: i32) {
|
fn mouse_move_to(&mut self, x: i32, y: i32) {
|
||||||
|
let x = if let Some(s) = self.scale {
|
||||||
|
x as f64 / s
|
||||||
|
} else {
|
||||||
|
x as f64
|
||||||
|
};
|
||||||
|
let y = if let Some(s) = self.scale {
|
||||||
|
y as f64 / s
|
||||||
|
} else {
|
||||||
|
y as f64
|
||||||
|
};
|
||||||
let portal = get_portal(&self.conn);
|
let portal = get_portal(&self.conn);
|
||||||
let _ = remote_desktop_portal::notify_pointer_motion_absolute(
|
let _ = remote_desktop_portal::notify_pointer_motion_absolute(
|
||||||
&portal,
|
&portal,
|
||||||
&self.session,
|
&self.session,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
self.stream.path as u32,
|
self.stream.path as u32,
|
||||||
x as f64,
|
x,
|
||||||
y as f64,
|
y,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn mouse_move_relative(&mut self, x: i32, y: i32) {
|
fn mouse_move_relative(&mut self, x: i32, y: i32) {
|
||||||
|
let x = if let Some(s) = self.scale {
|
||||||
|
x as f64 / s
|
||||||
|
} else {
|
||||||
|
x as f64
|
||||||
|
};
|
||||||
|
let y = if let Some(s) = self.scale {
|
||||||
|
y as f64 / s
|
||||||
|
} else {
|
||||||
|
y as f64
|
||||||
|
};
|
||||||
let portal = get_portal(&self.conn);
|
let portal = get_portal(&self.conn);
|
||||||
let _ = remote_desktop_portal::notify_pointer_motion(
|
let _ = remote_desktop_portal::notify_pointer_motion(
|
||||||
&portal,
|
&portal,
|
||||||
&self.session,
|
&self.session,
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
x as f64,
|
x,
|
||||||
y as f64,
|
y,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn mouse_down(&mut self, button: MouseButton) -> enigo::ResultType {
|
fn mouse_down(&mut self, button: MouseButton) -> enigo::ResultType {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user