1use crate::remote_viewing::vnc::server::VncServerSession;
23use crate::remote_viewing::vnc::{
24 ExtendedDesktopSizeStatus, IVncFramebufferSource, KeyChangedEventArgs, KeySym, VncFramebuffer,
25 VncPixelFormat,
26};
27use ferroui_base::input::{Key, MouseButton, PhysicalKey, RawInputModifiers};
28use ferroui_base::threading::{Dispatcher, DispatcherPriority};
29use ferroui_base::utilities::{NumberFormatInfo, ThreadBound};
30use ferroui_base::{PixelRect, Point, Ref, Vector};
31use ferroui_controls::Window;
32use ferroui_headless::HeadlessWindowExtensions;
33use std::cell::{Cell, RefCell};
34use std::collections::VecDeque;
35use std::sync::{Arc, Mutex, MutexGuard, PoisonError, Weak};
36
37bitflags::bitflags! {
38 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
40 struct VncButton: i32 {
41 const LEFT = 1;
42 const MIDDLE = 2;
43 const RIGHT = 4;
44 const SCROLL_UP = 8;
45 const SCROLL_DOWN = 16;
46 }
47}
48
49const CHECKED_BUTTONS: [VncButton; 3] = [VncButton::LEFT, VncButton::MIDDLE, VncButton::RIGHT];
51
52fn lock<T>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
53 mutex.lock().unwrap_or_else(PoisonError::into_inner)
54}
55
56type PendingInput = Box<dyn FnOnce(&HeadlessVncFramebufferSource) + Send>;
58
59pub struct HeadlessVncFramebufferSource {
62 this: Weak<HeadlessVncFramebufferSource>,
63 window: ThreadBound<RefCell<Option<Ref<Window>>>>,
65 framebuffer: Mutex<Arc<VncFramebuffer>>,
67 previous_buttons: Mutex<VncButton>,
68 key_state: Mutex<RawInputModifiers>,
69 pending_input: Mutex<VecDeque<PendingInput>>,
72 delivering_input: ThreadBound<Cell<bool>>,
74}
75
76impl HeadlessVncFramebufferSource {
77 pub fn new(
82 session: &VncServerSession,
83 window: Ref<Window>,
84 ) -> Arc<HeadlessVncFramebufferSource> {
85 let source = Arc::new_cyclic(|this| HeadlessVncFramebufferSource {
86 this: this.clone(),
87 window: ThreadBound::new(RefCell::new(Some(window))),
88 framebuffer: Mutex::new(VncFramebuffer::new("FerroUI", 1, 1, VncPixelFormat::RGB32)),
89 previous_buttons: Mutex::new(VncButton::empty()),
90 key_state: Mutex::new(RawInputModifiers::NONE),
91 pending_input: Mutex::new(VecDeque::new()),
92 delivering_input: ThreadBound::new(Cell::new(false)),
93 });
94
95 let weak = Arc::downgrade(&source);
96 session.pointer_changed().add(move |_, args| {
97 let Some(this) = weak.upgrade() else {
98 return;
99 };
100 let pt = Point::new(f64::from(args.x()), f64::from(args.y()));
101
102 let buttons = VncButton::from_bits_retain(args.pressed_buttons());
103
104 fn translate_button(vnc_button: VncButton) -> MouseButton {
105 if vnc_button == VncButton::LEFT {
106 MouseButton::Left
107 } else if vnc_button == VncButton::MIDDLE {
108 MouseButton::Middle
109 } else if vnc_button == VncButton::RIGHT {
110 MouseButton::Right
111 } else {
112 MouseButton::None
113 }
114 }
115
116 let modifiers = RawInputModifiers::from_bits_retain((buttons.bits() & 7) << 4);
117
118 this.post_input(move |this| {
119 let window = this.window();
120 let Some(window) = window else {
121 *lock(&this.previous_buttons) = buttons;
122 return;
123 };
124 let previous_buttons = *lock(&this.previous_buttons);
125 window.mouse_move(pt, RawInputModifiers::NONE);
126 for btn in CHECKED_BUTTONS {
127 if previous_buttons.contains(btn) && !buttons.contains(btn) {
128 window.mouse_up(pt, translate_button(btn), modifiers);
129 }
130 }
131
132 for btn in CHECKED_BUTTONS {
133 if !previous_buttons.contains(btn) && buttons.contains(btn) {
134 window.mouse_down(pt, translate_button(btn), modifiers);
135 }
136 }
137
138 if buttons == VncButton::SCROLL_UP {
139 window.mouse_wheel(pt, Vector::ONE, modifiers);
140 } else if buttons == VncButton::SCROLL_DOWN {
141 window.mouse_wheel(pt, Vector::ONE.negate(), modifiers);
142 }
143
144 *lock(&this.previous_buttons) = buttons;
145 });
146 });
147
148 let weak = Arc::downgrade(&source);
149 session.key_changed().add(move |_, args| {
150 let Some(this) = weak.upgrade() else {
151 return;
152 };
153 let is_modifier_key = this.check_key_is_input_modifier(args);
154 if is_modifier_key {
155 return;
156 }
157
158 let (key, key_symbol) = Self::translate_key(args.keysym());
159 if key == Key::None {
160 return;
161 }
162
163 let key_state = *lock(&this.key_state);
165 let input_text = if args.pressed()
166 || key_state.contains(RawInputModifiers::CONTROL)
167 || key_state.contains(RawInputModifiers::ALT)
168 {
169 None
170 } else {
171 key_symbol.clone()
172 };
173
174 let pressed = args.pressed();
175 this.post_input(move |this| {
176 let Some(window) = this.window() else {
177 return;
178 };
179 let key_state = *lock(&this.key_state);
180 if pressed {
181 window.key_press(key, key_state, PhysicalKey::None, key_symbol.as_deref());
182 } else {
183 window.key_release(key, key_state, PhysicalKey::None, key_symbol.as_deref());
184 }
185
186 if let Some(input_text) = &input_text {
187 window.key_text_input(input_text);
188 }
189 });
190 });
191
192 source
193 }
194
195 fn post_input(&self, input: impl FnOnce(&HeadlessVncFramebufferSource) + Send + 'static) {
198 lock(&self.pending_input).push_back(Box::new(input));
199 let this = self.arc();
200 Dispatcher::ui_thread().post(move || this.deliver_input(), DispatcherPriority::INPUT);
201 }
202
203 fn deliver_input(&self) {
207 struct Delivering<'a>(&'a Cell<bool>);
208 impl Drop for Delivering<'_> {
209 fn drop(&mut self) {
210 self.0.set(false);
211 }
212 }
213
214 let delivering = self.delivering_input.get();
215 if delivering.replace(true) {
216 return;
217 }
218 let _delivering = Delivering(delivering);
219
220 loop {
221 let input = lock(&self.pending_input).pop_front();
222 let Some(input) = input else {
223 return;
224 };
225 input(self);
226 }
227 }
228
229 fn arc(&self) -> Arc<HeadlessVncFramebufferSource> {
230 self.this
231 .upgrade()
232 .expect("the source is alive while it is used")
233 }
234
235 pub fn window(&self) -> Option<Ref<Window>> {
240 self.window.get().borrow().clone()
241 }
242
243 pub fn set_window(&self, value: Option<Ref<Window>>) {
248 let old = self.window.get().replace(value);
249 drop(old);
250 }
251
252 pub fn framebuffer(&self) -> Arc<VncFramebuffer> {
254 lock(&self.framebuffer).clone()
255 }
256
257 fn check_key_is_input_modifier(&self, args: &KeyChangedEventArgs) -> bool {
260 let toggle_modifier = match args.keysym() {
261 KeySym::ShiftLeft | KeySym::ShiftRight => Some(RawInputModifiers::SHIFT),
262 KeySym::ControlLeft | KeySym::ControlRight => Some(RawInputModifiers::CONTROL),
263 KeySym::AltLeft | KeySym::AltRight => Some(RawInputModifiers::ALT),
264 _ => None,
265 };
266
267 let Some(toggle_modifier) = toggle_modifier else {
268 return false;
269 };
270
271 let mut key_state = lock(&self.key_state);
272 if args.pressed() {
273 *key_state |= toggle_modifier;
274 } else {
275 *key_state &= !toggle_modifier;
276 }
277
278 true
279 }
280
281 fn translate_key(key: KeySym) -> (Key, Option<String>) {
283 let (key, symbol): (Key, Option<&str>) = match key {
284 KeySym::Backspace => (Key::Back, Some("\u{8}")),
285 KeySym::Tab => (Key::Tab, Some("\t")),
286 KeySym::LineFeed => (Key::LineFeed, None),
287 KeySym::Clear => (Key::Clear, None),
288 KeySym::Return => (Key::Return, Some("\r")),
289 KeySym::Pause => (Key::Pause, None),
290 KeySym::Escape => (Key::Escape, Some("\u{1B}")),
291 KeySym::Delete => (Key::Delete, None),
292 KeySym::Home => (Key::Home, None),
293 KeySym::Left => (Key::Left, None),
294 KeySym::Up => (Key::Up, None),
295 KeySym::Right => (Key::Right, None),
296 KeySym::Down => (Key::Down, None),
297 KeySym::PageUp => (Key::PageUp, None),
298 KeySym::PageDown => (Key::PageDown, None),
299 KeySym::End => (Key::End, None),
300 KeySym::Begin => (Key::Home, None),
301 KeySym::Select => (Key::Select, None),
302 KeySym::Print => (Key::Print, None),
303 KeySym::Execute => (Key::Execute, None),
304 KeySym::Insert => (Key::Insert, None),
305 KeySym::Cancel => (Key::Cancel, None),
306 KeySym::Help => (Key::Help, None),
307 KeySym::Break => (Key::Pause, None),
308 KeySym::Num_Lock => (Key::NumLock, None),
309 KeySym::NumPadSpace => (Key::Space, None),
310 KeySym::NumPadTab => (Key::Tab, None),
311 KeySym::NumPadEnter => (Key::Enter, None),
312 KeySym::NumPadF1 => (Key::F1, None),
313 KeySym::NumPadF2 => (Key::F2, None),
314 KeySym::NumPadF3 => (Key::F3, None),
315 KeySym::NumPadF4 => (Key::F4, None),
316 KeySym::NumPadHome => (Key::Home, None),
317 KeySym::NumPadLeft => (Key::Left, None),
318 KeySym::NumPadUp => (Key::Up, None),
319 KeySym::NumPadRight => (Key::Right, None),
320 KeySym::NumPadDown => (Key::Down, None),
321 KeySym::NumPadPageUp => (Key::PageUp, None),
322 KeySym::NumPadPageDown => (Key::PageDown, None),
323 KeySym::NumPadEnd => (Key::End, None),
324 KeySym::NumPadBegin => (Key::Home, None),
325 KeySym::NumPadInsert => (Key::Insert, None),
326 KeySym::NumPadDelete => (Key::Delete, None),
327 KeySym::NumPadEqual => (Key::Enter, Some("=")),
328 KeySym::NumPadMultiply => (Key::Multiply, Some("*")),
329 KeySym::NumPadAdd => (Key::Add, Some("+")),
330 KeySym::NumPadSeparator => {
331 return (
332 Key::Separator,
333 Some(
334 NumberFormatInfo::current_info()
335 .number_group_separator()
336 .to_owned(),
337 ),
338 )
339 }
340 KeySym::NumPadSubtract => (Key::Subtract, Some("-")),
341 KeySym::NumPadDecimal => {
342 return (
343 Key::Decimal,
344 Some(
345 NumberFormatInfo::current_info()
346 .number_decimal_separator()
347 .to_owned(),
348 ),
349 )
350 }
351 KeySym::NumPadDivide => (Key::Divide, Some("/")),
352 KeySym::NumPad0 => (Key::NumPad0, Some("0")),
353 KeySym::NumPad1 => (Key::NumPad1, Some("1")),
354 KeySym::NumPad2 => (Key::NumPad2, Some("2")),
355 KeySym::NumPad3 => (Key::NumPad3, Some("3")),
356 KeySym::NumPad4 => (Key::NumPad4, Some("4")),
357 KeySym::NumPad5 => (Key::NumPad5, Some("5")),
358 KeySym::NumPad6 => (Key::NumPad6, Some("6")),
359 KeySym::NumPad7 => (Key::NumPad7, Some("7")),
360 KeySym::NumPad8 => (Key::NumPad8, Some("8")),
361 KeySym::NumPad9 => (Key::NumPad9, Some("9")),
362 KeySym::F1 => (Key::F1, None),
363 KeySym::F2 => (Key::F2, None),
364 KeySym::F3 => (Key::F3, None),
365 KeySym::F4 => (Key::F4, None),
366 KeySym::F5 => (Key::F5, None),
367 KeySym::F6 => (Key::F6, None),
368 KeySym::F7 => (Key::F7, None),
369 KeySym::F8 => (Key::F8, None),
370 KeySym::F9 => (Key::F9, None),
371 KeySym::F10 => (Key::F10, None),
372 KeySym::F11 => (Key::F11, None),
373 KeySym::F12 => (Key::F12, None),
374 KeySym::F13 => (Key::F13, None),
375 KeySym::F14 => (Key::F14, None),
376 KeySym::F15 => (Key::F15, None),
377 KeySym::F16 => (Key::F16, None),
378 KeySym::F17 => (Key::F17, None),
379 KeySym::F18 => (Key::F18, None),
380 KeySym::F19 => (Key::F19, None),
381 KeySym::F20 => (Key::F20, None),
382 KeySym::F21 => (Key::F21, None),
383 KeySym::F22 => (Key::F22, None),
384 KeySym::F23 => (Key::F23, None),
385 KeySym::F24 => (Key::F24, None),
386 KeySym::ShiftLeft => (Key::LeftShift, None),
387 KeySym::ShiftRight => (Key::RightShift, None),
388 KeySym::ControlLeft => (Key::LeftCtrl, None),
389 KeySym::ControlRight => (Key::RightCtrl, None),
390 KeySym::CapsLock => (Key::CapsLock, None),
391 KeySym::AltLeft => (Key::LeftAlt, None),
392 KeySym::AltRight => (Key::RightAlt, None),
393 KeySym::Space => (Key::Space, Some(" ")),
394 KeySym::Exclamation => (Key::D1, Some("!")),
395 KeySym::Quote => (Key::D2, Some("\"")),
396 KeySym::NumberSign => (Key::D3, Some("#")),
397 KeySym::Dollar => (Key::D4, Some("$")),
398 KeySym::Percent => (Key::D5, Some("%")),
399 KeySym::Ampersand => (Key::D7, Some("&")),
400 KeySym::Apostrophe => (Key::Oem3, Some("'")),
401 KeySym::ParenthesisLeft => (Key::D9, Some("(")),
402 KeySym::ParenthesisRight => (Key::D0, Some(")")),
403 KeySym::Asterisk => (Key::D8, Some("*")),
404 KeySym::Plus => (Key::OemPlus, Some("+")),
405 KeySym::Comma => (Key::OemComma, Some(",")),
406 KeySym::Minus => (Key::OemMinus, Some("-")),
407 KeySym::Period => (Key::OemPeriod, Some(".")),
408 KeySym::Slash => (Key::OemQuestion, Some("/")),
409 KeySym::D0 => (Key::D0, Some("0")),
410 KeySym::D1 => (Key::D1, Some("1")),
411 KeySym::D2 => (Key::D2, Some("2")),
412 KeySym::D3 => (Key::D3, Some("3")),
413 KeySym::D4 => (Key::D4, Some("4")),
414 KeySym::D5 => (Key::D5, Some("5")),
415 KeySym::D6 => (Key::D6, Some("6")),
416 KeySym::D7 => (Key::D7, Some("7")),
417 KeySym::D8 => (Key::D8, Some("8")),
418 KeySym::D9 => (Key::D9, Some("9")),
419 KeySym::Colon => (Key::OemSemicolon, Some(":")),
420 KeySym::Semicolon => (Key::OemSemicolon, Some(";")),
421 KeySym::Less => (Key::OemComma, Some("<")),
422 KeySym::Equal => (Key::OemPlus, Some("=")),
423 KeySym::Greater => (Key::OemPeriod, Some(">")),
424 KeySym::Question => (Key::OemQuestion, Some("?")),
425 KeySym::At => (Key::Oem3, Some("@")),
426 KeySym::A => (Key::A, Some("A")),
427 KeySym::B => (Key::B, Some("B")),
428 KeySym::C => (Key::C, Some("C")),
429 KeySym::D => (Key::D, Some("D")),
430 KeySym::E => (Key::E, Some("E")),
431 KeySym::F => (Key::F, Some("F")),
432 KeySym::G => (Key::G, Some("G")),
433 KeySym::H => (Key::H, Some("H")),
434 KeySym::I => (Key::I, Some("I")),
435 KeySym::J => (Key::J, Some("J")),
436 KeySym::K => (Key::K, Some("K")),
437 KeySym::L => (Key::L, Some("L")),
438 KeySym::M => (Key::M, Some("M")),
439 KeySym::N => (Key::N, Some("N")),
440 KeySym::O => (Key::O, Some("O")),
441 KeySym::P => (Key::P, Some("P")),
442 KeySym::Q => (Key::Q, Some("Q")),
443 KeySym::R => (Key::R, Some("R")),
444 KeySym::S => (Key::S, Some("S")),
445 KeySym::T => (Key::T, Some("T")),
446 KeySym::U => (Key::U, Some("U")),
447 KeySym::V => (Key::V, Some("V")),
448 KeySym::W => (Key::W, Some("W")),
449 KeySym::X => (Key::X, Some("X")),
450 KeySym::Y => (Key::Y, Some("Y")),
451 KeySym::Z => (Key::Z, Some("Z")),
452 KeySym::BracketLeft => (Key::OemOpenBrackets, Some("[")),
453 KeySym::Backslash => (Key::OemPipe, Some("\\")),
454 KeySym::Bracketright => (Key::OemCloseBrackets, Some("]")),
455 KeySym::Underscore => (Key::OemMinus, Some("_")),
456 KeySym::Grave => (Key::Oem8, Some("`")),
457 KeySym::a => (Key::A, Some("a")),
458 KeySym::b => (Key::B, Some("b")),
459 KeySym::c => (Key::C, Some("c")),
460 KeySym::d => (Key::D, Some("d")),
461 KeySym::e => (Key::E, Some("e")),
462 KeySym::f => (Key::F, Some("f")),
463 KeySym::g => (Key::G, Some("g")),
464 KeySym::h => (Key::H, Some("h")),
465 KeySym::i => (Key::I, Some("i")),
466 KeySym::j => (Key::J, Some("j")),
467 KeySym::k => (Key::K, Some("k")),
468 KeySym::l => (Key::L, Some("l")),
469 KeySym::m => (Key::M, Some("m")),
470 KeySym::n => (Key::M, Some("n")),
471 KeySym::o => (Key::O, Some("o")),
472 KeySym::p => (Key::P, Some("p")),
473 KeySym::q => (Key::Q, Some("q")),
474 KeySym::r => (Key::R, Some("r")),
475 KeySym::s => (Key::S, Some("s")),
476 KeySym::t => (Key::T, Some("t")),
477 KeySym::u => (Key::U, Some("u")),
478 KeySym::v => (Key::V, Some("v")),
479 KeySym::w => (Key::W, Some("w")),
480 KeySym::x => (Key::X, Some("x")),
481 KeySym::y => (Key::Y, Some("y")),
482 KeySym::z => (Key::Z, Some("z")),
483 KeySym::BraceLeft => (Key::OemOpenBrackets, Some("{")),
484 KeySym::Bar => (Key::OemPipe, Some("|")),
485 KeySym::BraceRight => (Key::OemCloseBrackets, Some("}")),
486 KeySym::AsciiTilde => (Key::OemTilde, Some("~")),
487 _ => (Key::None, None),
488 };
489
490 (key, symbol.map(str::to_owned))
491 }
492
493 fn capture_on_ui_thread(&self) -> Arc<VncFramebuffer> {
497 let mut framebuffer = lock(&self.framebuffer);
498 let Some(bmp) = self
499 .window()
500 .and_then(|window| window.get_last_rendered_frame())
501 else {
502 return framebuffer.clone();
503 };
504
505 let pixel_size = bmp.pixel_size();
506 if pixel_size.width != framebuffer.width() || pixel_size.height != framebuffer.height() {
507 *framebuffer = VncFramebuffer::new(
508 "FerroUI",
509 pixel_size.width,
510 pixel_size.height,
511 VncPixelFormat::RGB32,
512 );
513 }
514
515 {
516 let mut buffer = framebuffer.get_buffer();
517 bmp.copy_pixels(
518 PixelRect::from_size(pixel_size),
519 &mut buffer[..],
520 framebuffer.stride(),
521 );
522 }
523 bmp.dispose();
524
525 framebuffer.clone()
526 }
527}
528
529impl IVncFramebufferSource for HeadlessVncFramebufferSource {
530 fn supports_resizing(&self) -> bool {
531 true
532 }
533
534 fn capture(&self) -> Option<Arc<VncFramebuffer>> {
535 let this = self.arc();
536 match Dispatcher::ui_thread().invoke(move || this.capture_on_ui_thread()) {
537 Ok(framebuffer) => Some(framebuffer),
538 Err(_) => Some(self.framebuffer()),
540 }
541 }
542
543 fn set_desktop_size(&self, width: i32, height: i32) -> ExtendedDesktopSizeStatus {
544 let this = self.arc();
545 Dispatcher::ui_thread().post(
546 move || {
547 if let Some(window) = this.window() {
548 window.set_width(f64::from(width));
549 window.set_height(f64::from(height));
550 }
551 },
552 DispatcherPriority::NORMAL,
553 );
554 ExtendedDesktopSizeStatus::Success
555 }
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
562
563 #[test]
564 fn letters_digits_and_control_keys_translate_to_keys_and_text() {
565 assert_eq!(
566 (Key::A, Some("a".to_owned())),
567 HeadlessVncFramebufferSource::translate_key(KeySym::a)
568 );
569 assert_eq!(
570 (Key::A, Some("A".to_owned())),
571 HeadlessVncFramebufferSource::translate_key(KeySym::A)
572 );
573 assert_eq!(
574 (Key::D7, Some("7".to_owned())),
575 HeadlessVncFramebufferSource::translate_key(KeySym::D7)
576 );
577 assert_eq!(
578 (Key::Return, Some("\r".to_owned())),
579 HeadlessVncFramebufferSource::translate_key(KeySym::Return)
580 );
581 assert_eq!(
582 (Key::Left, None),
583 HeadlessVncFramebufferSource::translate_key(KeySym::Left)
584 );
585 assert_eq!(
586 (Key::Decimal, Some(".".to_owned())),
587 HeadlessVncFramebufferSource::translate_key(KeySym::NumPadDecimal)
588 );
589 assert_eq!(
590 (Key::None, None),
591 HeadlessVncFramebufferSource::translate_key(KeySym::VoidSymbol)
592 );
593 assert_eq!(
595 (Key::M, Some("n".to_owned())),
596 HeadlessVncFramebufferSource::translate_key(KeySym::n)
597 );
598 }
599}