qemu-rdp: fix compilation with current IronRDP

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau 2024-04-09 19:34:45 +04:00
parent 8c3b5e7cba
commit e03f2d80a6
4 changed files with 124 additions and 71 deletions

View File

@ -3,6 +3,7 @@ use qemu_display::zbus;
mod args;
mod server;
mod util;
#[tokio::main]
async fn main() -> Result<(), anyhow::Error> {

View File

@ -1,23 +1,45 @@
use anyhow::Result;
use ironrdp::connector::DesktopSize;
use ironrdp::{connector::DesktopSize, server::RdpServerDisplayUpdates};
use qemu_display::{zbus, Console, ConsoleListenerHandler, Cursor, MouseSet, Scanout, Update};
use ironrdp::server::{BitmapUpdate, DisplayUpdate, PixelFormat, PixelOrder, RdpServerDisplay};
use crate::cast;
pub struct DisplayHandler {
console: Console,
}
struct DisplayUpdates {
receiver: tokio::sync::mpsc::Receiver<DisplayUpdate>,
}
impl DisplayHandler {
pub async fn connect(dbus: zbus::Connection) -> Result<Self> {
let (sender, receiver) = tokio::sync::mpsc::channel::<DisplayUpdate>(32);
let listener = Listener::new(sender);
let console = Console::new(&dbus, 0).await?;
console.register_listener(listener).await?;
Ok(Self { console, receiver })
Ok(Self { console })
}
async fn listen(&self) -> Result<DisplayUpdates> {
let (sender, receiver) = tokio::sync::mpsc::channel::<DisplayUpdate>(32);
let (width, height) = (
self.console.width().await? as _,
self.console.height().await? as _,
);
let desktop_size = DesktopSize { width, height };
let listener = Listener::new(sender, desktop_size);
self.console.unregister_listener();
self.console.register_listener(listener).await?;
Ok(DisplayUpdates { receiver })
}
}
#[async_trait::async_trait]
impl RdpServerDisplayUpdates for DisplayUpdates {
async fn next_update(&mut self) -> Option<DisplayUpdate> {
self.receiver.recv().await
}
}
@ -29,8 +51,8 @@ impl RdpServerDisplay for DisplayHandler {
DesktopSize { height, width }
}
async fn get_update(&mut self) -> Option<DisplayUpdate> {
self.receiver.recv().await
async fn updates(&mut self) -> Result<Box<dyn RdpServerDisplayUpdates>> {
Ok(Box::new(self.listen().await?))
}
}
@ -39,7 +61,7 @@ struct Listener {
}
impl Listener {
fn new(sender: tokio::sync::mpsc::Sender<DisplayUpdate>) -> Self {
fn new(sender: tokio::sync::mpsc::Sender<DisplayUpdate>, _desktop_size: DesktopSize) -> Self {
Self { sender }
}
@ -58,11 +80,13 @@ impl ConsoleListenerHandler for Listener {
_ => PixelFormat::RgbA32,
};
let width: u16 = cast!(scanout.width);
let height: u16 = cast!(scanout.height);
let bitmap = DisplayUpdate::Bitmap(BitmapUpdate {
top: 0,
left: 0,
width: scanout.width,
height: scanout.height,
width: width.try_into().unwrap(),
height: height.try_into().unwrap(),
format,
order: PixelOrder::TopToBottom,
data: scanout.data,
@ -77,12 +101,14 @@ impl ConsoleListenerHandler for Listener {
_ => PixelFormat::RgbA32,
};
let width: u16 = cast!(update.w);
let height: u16 = cast!(update.h);
let bitmap = DisplayUpdate::Bitmap(BitmapUpdate {
// TODO: fix scary conversion
top: update.y as u32,
left: update.x as u32,
width: update.w as u32,
height: update.h as u32,
top: cast!(update.y),
left: cast!(update.x),
width: width.try_into().unwrap(),
height: height.try_into().unwrap(),
format,
order: PixelOrder::TopToBottom,
data: update.data,

View File

@ -1,37 +1,59 @@
use qemu_display::{zbus, Console, KeyboardProxy, MouseButton, MouseProxy};
use ironrdp::server::{KeyboardEvent, MouseEvent, RdpServerInputHandler};
use qemu_display::{zbus, Console, MouseButton};
use tokio::{
sync::mpsc::{Receiver, Sender},
task,
};
pub struct InputHandler<'a> {
pos: (u16, u16),
mouse: MouseProxy<'a>,
keyboard: KeyboardProxy<'a>,
use crate::cast;
pub struct InputHandler {
tx: Sender<InputEvent>,
_task: task::JoinHandle<()>,
}
#[async_trait::async_trait]
impl<'a> RdpServerInputHandler for InputHandler<'a> {
async fn keyboard(&mut self, event: KeyboardEvent) {
let result = match event {
KeyboardEvent::Pressed { code, .. } => self.keyboard.press(code as u32).await,
KeyboardEvent::Released { code, .. } => self.keyboard.release(code as u32).await,
other => {
eprintln!("unhandled keyboard event: {:?}", other);
Ok(())
}
};
#[derive(Debug)]
enum InputEvent {
Keyboard(KeyboardEvent),
Mouse(MouseEvent),
}
if let Err(e) = result {
impl RdpServerInputHandler for InputHandler {
fn keyboard(&mut self, event: KeyboardEvent) {
tracing::debug!(?event);
if let Err(e) = self.tx.try_send(InputEvent::Keyboard(event)) {
eprintln!("keyboard error: {:?}", e);
}
}
async fn mouse(&mut self, event: MouseEvent) {
let result = match event {
MouseEvent::Move { x, y } => self.mouse_move(x, y).await,
MouseEvent::RightPressed => self.mouse.press(MouseButton::Right).await,
MouseEvent::RightReleased => self.mouse.release(MouseButton::Right).await,
MouseEvent::LeftPressed => self.mouse.press(MouseButton::Left).await,
MouseEvent::LeftReleased => self.mouse.release(MouseButton::Left).await,
fn mouse(&mut self, event: MouseEvent) {
tracing::debug!(?event);
if let Err(e) = self.tx.try_send(InputEvent::Mouse(event)) {
eprintln!("keyboard error: {:?}", e);
}
}
}
async fn input_receive_task(mut rx: Receiver<InputEvent>, console: Console) {
loop {
let res = match rx.recv().await {
Some(InputEvent::Keyboard(ev)) => match ev {
KeyboardEvent::Pressed { code, .. } => console.keyboard.press(code as u32).await,
KeyboardEvent::Released { code, .. } => console.keyboard.release(code as u32).await,
other => {
eprintln!("unhandled keyboard event: {:?}", other);
Ok(())
}
},
Some(InputEvent::Mouse(ev)) => match ev {
MouseEvent::Move { x, y } => {
tracing::debug!(?x, ?y);
console.mouse.set_abs_position(cast!(x), cast!(y)).await
}
MouseEvent::RightPressed => console.mouse.press(MouseButton::Right).await,
MouseEvent::RightReleased => console.mouse.release(MouseButton::Right).await,
MouseEvent::LeftPressed => console.mouse.press(MouseButton::Left).await,
MouseEvent::LeftReleased => console.mouse.release(MouseButton::Left).await,
MouseEvent::VerticalScroll { value } => {
let motion = if value > 0 {
MouseButton::WheelUp
@ -39,36 +61,28 @@ impl<'a> RdpServerInputHandler for InputHandler<'a> {
MouseButton::WheelDown
};
self.mouse.press(motion).await
console.mouse.press(motion).await
}
other => {
eprintln!("unhandled input event: {:?}", other);
Ok(())
}
},
None => break,
};
if let Err(e) = result {
eprintln!("keyboard error: {:?}", e);
if let Err(e) = res {
eprintln!("input handling error: {:?}", e);
}
}
}
impl<'a> InputHandler<'a> {
pub async fn connect(dbus: zbus::Connection) -> anyhow::Result<InputHandler<'a>> {
impl InputHandler {
pub async fn connect(dbus: zbus::Connection) -> anyhow::Result<InputHandler> {
let console = Console::new(&dbus, 0).await?;
let (tx, rx) = tokio::sync::mpsc::channel(30);
let _task = task::spawn(async move { input_receive_task(rx, console).await });
Ok(Self {
pos: (0, 0),
mouse: console.mouse,
keyboard: console.keyboard,
})
}
pub async fn mouse_move(&mut self, x: u16, y: u16) -> Result<(), zbus::Error> {
if self.mouse.is_absolute().await.unwrap_or(true) {
self.mouse.set_abs_position(x.into(), y.into()).await
} else {
let (dx, dy) = (x as i32 - self.pos.0 as i32, y as i32 - self.pos.1 as i32);
let res = self.mouse.rel_motion(dx, dy).await;
self.pos = (x, y);
res
}
Ok(Self { _task, tx })
}
}

12
qemu-rdp/src/util.rs Normal file
View File

@ -0,0 +1,12 @@
#[macro_export]
macro_rules! cast {
($value:expr) => {
match $value.try_into() {
Ok(val) => val,
Err(err) => {
eprintln!("Error casting value: {}", err);
return;
}
}
};
}