Skip to content

Commit a8a0034

Browse files
Expand keysym values sufficiently to represent an AT keyboard. (#8)
Expand keysym values sufficiently to represent an AT keyboard.
1 parent 68ee9f3 commit a8a0034

File tree

6 files changed

+243
-66
lines changed

6 files changed

+243
-66
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ path = "examples/server.rs"
2020

2121
[dependencies]
2222
anyhow = "1.0"
23+
ascii = { version = "1.0", default-features = false }
2324
async-trait = "0.1.53"
2425
bitflags = "1.3.2"
2526
env_logger = "0.9.0"

examples/server.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55
// Copyright 2022 Oxide Computer Company
66

7-
use anyhow::{anyhow, bail, Result};
7+
use anyhow::{bail, Result};
88
use async_trait::async_trait;
99
use clap::{Parser, ValueEnum};
1010
use env_logger;
@@ -13,7 +13,7 @@ use image::GenericImageView;
1313
use log::info;
1414
use rfb::encodings::RawEncoding;
1515
use rfb::rfb::{
16-
FramebufferUpdate, PixelFormat, ProtoVersion, Rectangle, SecurityType, SecurityTypes,
16+
FramebufferUpdate, KeyEvent, PixelFormat, ProtoVersion, Rectangle, SecurityType, SecurityTypes,
1717
};
1818
use rfb::{
1919
pixel_formats::rgb_888,
@@ -220,8 +220,18 @@ fn generate_pixels(img: Image, big_endian: bool, rgb_order: (u8, u8, u8)) -> Vec
220220
#[async_trait]
221221
impl Server for ExampleServer {
222222
async fn get_framebuffer_update(&self) -> FramebufferUpdate {
223+
let pixels_width = 1024;
224+
let pixels_height = 768;
223225
let pixels = generate_pixels(self.display, self.big_endian, self.rgb_order);
224-
let r = Rectangle::new(0, 0, 1024, 768, Box::new(RawEncoding::new(pixels)));
226+
let r = Rectangle::new(
227+
0,
228+
0,
229+
pixels_width,
230+
pixels_height,
231+
Box::new(RawEncoding::new(pixels)),
232+
);
225233
FramebufferUpdate::new(vec![r])
226234
}
235+
236+
async fn key_event(&self, _ke: KeyEvent) {}
227237
}

src/keysym.rs

Lines changed: 190 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,81 @@
44
//
55
// Copyright 2022 Oxide Computer Company
66

7-
use Keysym::*;
7+
use anyhow::anyhow;
8+
pub use ascii::AsciiChar;
9+
use ascii::ToAsciiChar;
10+
use KeySym::*;
811

9-
#[derive(Debug)]
10-
pub enum Keysym {
11-
Unknown(u32),
12-
Utf32(char),
12+
// ascii characters have the same values as their keysym
13+
const ASCII_MAX: u32 = 0x7f;
14+
15+
const KEYSYM_BACKSPACE: u32 = 0xff08;
16+
const KEYSYM_TAB: u32 = 0xff09;
17+
const KEYSYM_RETURN_ENTER: u32 = 0xff0d;
18+
const KEYSYM_ESCAPE: u32 = 0xff1b;
19+
const KEYSYM_INSERT: u32 = 0xff63;
20+
const KEYSYM_DELETE: u32 = 0xffff;
21+
const KEYSYM_HOME: u32 = 0xff50;
22+
const KEYSYM_END: u32 = 0xff57;
23+
const KEYSYM_PAGE_UP: u32 = 0xff55;
24+
const KEYSYM_PAGE_DOWN: u32 = 0xff56;
25+
const KEYSYM_PRINT: u32 = 0xff61;
26+
const KEYSYM_PAUSE: u32 = 0xff13;
27+
const KEYSYM_CAPS_LOCK: u32 = 0xffe5;
28+
const KEYSYM_SUPER_LEFT: u32 = 0xffeb;
29+
const KEYSYM_SUPER_RIGHT: u32 = 0xffec;
30+
const KEYSYM_MENU: u32 = 0xff67;
31+
32+
const KEYSYM_LEFT: u32 = 0xff51;
33+
const KEYSYM_UP: u32 = 0xff52;
34+
const KEYSYM_RIGHT: u32 = 0xff53;
35+
const KEYSYM_DOWN: u32 = 0xff54;
36+
// function keys are in the range: 0xffbe to 0xffc9, in order
37+
const KEYSYM_F1: u32 = 0xffbe;
38+
const KEYSYM_F12: u32 = 0xffc9;
39+
const KEYSYM_SHIFT_LEFT: u32 = 0xffe1;
40+
const KEYSYM_SHIFT_RIGHT: u32 = 0xffe2;
41+
const KEYSYM_CTRL_LEFT: u32 = 0xffe3;
42+
const KEYSYM_CTRL_RIGHT: u32 = 0xffe4;
43+
44+
// XXX(JPH): do we need to support meta keys?
45+
46+
const KEYSYM_ALT_LEFT: u32 = 0xffe9;
47+
const KEYSYM_ALT_RIGHT: u32 = 0xffea;
48+
const KEYSYM_SCROLL_LOCK: u32 = 0xff14;
49+
const KEYSYM_NUM_LOCK: u32 = 0xff7f;
50+
51+
const KEYSYM_KP_ENTER: u32 = 0xff8d;
52+
const KEYSYM_KP_SLASH: u32 = 0xffaf;
53+
const KEYSYM_KP_ASTERISK: u32 = 0xffaa;
54+
const KEYSYM_KP_MINUS: u32 = 0xffad;
55+
const KEYSYM_KP_PLUS: u32 = 0xffab;
56+
const KEYSYM_KP_7: u32 = 0xffb7;
57+
const KEYSYM_KP_HOME: u32 = 0xff95;
58+
const KEYSYM_KP_8: u32 = 0xffb8;
59+
const KEYSYM_KP_UP: u32 = 0xff97;
60+
const KEYSYM_KP_9: u32 = 0xffb9;
61+
const KEYSYM_KP_PGUP: u32 = 0xff9a;
62+
const KEYSYM_KP_4: u32 = 0xffb4;
63+
const KEYSYM_KP_LEFT: u32 = 0xff96;
64+
const KEYSYM_KP_5: u32 = 0xffb5;
65+
const KEYSYM_KP_EMPTY: u32 = 0xff9d;
66+
const KEYSYM_KP_6: u32 = 0xffb6;
67+
const KEYSYM_KP_RIGHT: u32 = 0xff98;
68+
const KEYSYM_KP_1: u32 = 0xffb1;
69+
const KEYSYM_KP_END: u32 = 0xff9c;
70+
const KEYSYM_KP_2: u32 = 0xffb2;
71+
const KEYSYM_KP_DOWN: u32 = 0xff99;
72+
const KEYSYM_KP_3: u32 = 0xffb3;
73+
const KEYSYM_KP_PGDOWN: u32 = 0xff9b;
74+
const KEYSYM_KP_0: u32 = 0xffb0;
75+
const KEYSYM_KP_INSERT: u32 = 0xff9e;
76+
const KEYSYM_KP_PERIOD: u32 = 0xffae;
77+
const KEYSYM_KP_DELETE: u32 = 0xff9f;
78+
79+
#[derive(Debug, Copy, Clone)]
80+
pub enum KeySym {
81+
Ascii(ascii::AsciiChar),
1382
Backspace,
1483
Tab,
1584
ReturnOrEnter,
@@ -20,66 +89,142 @@ pub enum Keysym {
2089
End,
2190
PageUp,
2291
PageDown,
92+
Print,
93+
Pause,
94+
CapsLock,
95+
96+
// "super" = windows/command key
97+
SuperLeft,
98+
SuperRight,
99+
100+
// usb-only
101+
Menu,
102+
23103
Left,
24104
Up,
25105
Right,
26106
Down,
107+
27108
FunctionKey(u8),
109+
28110
ShiftLeft,
29111
ShiftRight,
30112
ControlLeft,
31113
ControlRight,
32-
MetaLeft,
33-
MetaRight,
34114
AltLeft,
35115
AltRight,
116+
ScrollLock,
117+
118+
// Number Keypad
119+
NumLock,
120+
KeypadSlash,
121+
KeypadAsterisk,
122+
KeypadMinus,
123+
KeypadPlus,
124+
KeypadEnter,
125+
KeypadPeriod,
126+
KeypadDelete,
127+
Keypad0,
128+
KeypadInsert,
129+
Keypad1,
130+
KeypadEnd,
131+
Keypad2,
132+
KeypadDown,
133+
Keypad3,
134+
KeypadPgDown,
135+
Keypad4,
136+
KeypadLeft,
137+
Keypad5,
138+
KeypadEmpty,
139+
Keypad6,
140+
KeypadRight,
141+
Keypad7,
142+
KeypadHome,
143+
Keypad8,
144+
KeypadUp,
145+
Keypad9,
146+
KeypadPgUp,
36147
}
37148

38-
impl TryFrom<u32> for Keysym {
149+
impl TryFrom<u32> for KeySym {
39150
type Error = anyhow::Error;
40151

41152
fn try_from(value: u32) -> Result<Self, Self::Error> {
42-
const XK_F1: u32 = 0xffbe;
43-
const XK_F12: u32 = 0xffc9;
44-
45153
match value {
46-
0xff08 => Ok(Backspace),
47-
0xff09 => Ok(Tab),
48-
0xff0d => Ok(ReturnOrEnter),
49-
0xff1b => Ok(Escape),
50-
0xff63 => Ok(Insert),
51-
0xffff => Ok(Delete),
52-
0xff50 => Ok(Home),
53-
0xff57 => Ok(End),
54-
0xff55 => Ok(PageUp),
55-
0xff56 => Ok(PageDown),
56-
0xff51 => Ok(Left),
57-
0xff52 => Ok(Up),
58-
0xff53 => Ok(Right),
59-
0xff54 => Ok(Down),
60-
f if (f >= XK_F1 && f <= XK_F12) => {
61-
let n = f - XK_F1 + 1;
154+
v if v <= ASCII_MAX => {
155+
let ac_res = v.to_ascii_char();
156+
match ac_res {
157+
Ok(ac) => Ok(Ascii(ac)),
158+
Err(e) => Err(anyhow!("invalid keysym=0x{:x} ({:?})", value, e)),
159+
}
160+
}
161+
KEYSYM_BACKSPACE => Ok(Backspace),
162+
KEYSYM_TAB => Ok(Tab),
163+
KEYSYM_RETURN_ENTER => Ok(ReturnOrEnter),
164+
KEYSYM_ESCAPE => Ok(Escape),
165+
KEYSYM_INSERT => Ok(Insert),
166+
KEYSYM_DELETE => Ok(Delete),
167+
KEYSYM_HOME => Ok(Home),
168+
KEYSYM_END => Ok(End),
169+
KEYSYM_PAGE_UP => Ok(PageUp),
170+
KEYSYM_PRINT => Ok(Print),
171+
KEYSYM_PAUSE => Ok(Pause),
172+
KEYSYM_CAPS_LOCK => Ok(CapsLock),
173+
KEYSYM_SUPER_LEFT => Ok(SuperLeft),
174+
KEYSYM_SUPER_RIGHT => Ok(SuperRight),
175+
KEYSYM_MENU => Ok(Menu),
176+
177+
KEYSYM_PAGE_DOWN => Ok(PageDown),
178+
KEYSYM_LEFT => Ok(Left),
179+
KEYSYM_UP => Ok(Up),
180+
KEYSYM_RIGHT => Ok(Right),
181+
KEYSYM_DOWN => Ok(Down),
182+
183+
f if (f >= KEYSYM_F1 && f <= KEYSYM_F12) => {
184+
let n = f - KEYSYM_F1 + 1;
62185
// TODO: handle cast
63186
Ok(FunctionKey(n as u8))
64187
}
65-
0xffe1 => Ok(ShiftLeft),
66-
0xffe2 => Ok(ShiftRight),
67-
0xffe3 => Ok(ControlLeft),
68-
0xffe4 => Ok(ControlRight),
69-
0xffe7 => Ok(MetaLeft),
70-
0xffe8 => Ok(MetaRight),
71-
0xffe9 => Ok(AltLeft),
72-
0xffea => Ok(AltRight),
73-
74-
// TODO: figure out if there's a better way to map codes
75-
other => {
76-
let c = char::from_u32(other);
77-
match c {
78-
// TODO: figure out what to do with these
79-
None => Ok(Unknown(other)),
80-
Some(v) => Ok(Utf32(v)),
81-
}
82-
}
188+
189+
KEYSYM_SHIFT_LEFT => Ok(ShiftLeft),
190+
KEYSYM_SHIFT_RIGHT => Ok(ShiftRight),
191+
KEYSYM_CTRL_LEFT => Ok(ControlLeft),
192+
KEYSYM_CTRL_RIGHT => Ok(ControlRight),
193+
KEYSYM_ALT_LEFT => Ok(AltLeft),
194+
KEYSYM_ALT_RIGHT => Ok(AltRight),
195+
196+
KEYSYM_SCROLL_LOCK => Ok(ScrollLock),
197+
KEYSYM_NUM_LOCK => Ok(NumLock),
198+
199+
KEYSYM_KP_ENTER => Ok(KeypadEnter),
200+
KEYSYM_KP_SLASH => Ok(KeypadSlash),
201+
KEYSYM_KP_ASTERISK => Ok(KeypadAsterisk),
202+
KEYSYM_KP_MINUS => Ok(KeypadMinus),
203+
KEYSYM_KP_PLUS => Ok(KeypadPlus),
204+
KEYSYM_KP_7 => Ok(Keypad7),
205+
KEYSYM_KP_HOME => Ok(KeypadHome),
206+
KEYSYM_KP_8 => Ok(Keypad8),
207+
KEYSYM_KP_UP => Ok(KeypadUp),
208+
KEYSYM_KP_9 => Ok(Keypad9),
209+
KEYSYM_KP_PGUP => Ok(KeypadPgUp),
210+
KEYSYM_KP_4 => Ok(Keypad4),
211+
KEYSYM_KP_LEFT => Ok(KeypadLeft),
212+
KEYSYM_KP_5 => Ok(Keypad5),
213+
KEYSYM_KP_EMPTY => Ok(KeypadEmpty),
214+
KEYSYM_KP_6 => Ok(Keypad6),
215+
KEYSYM_KP_RIGHT => Ok(KeypadRight),
216+
KEYSYM_KP_1 => Ok(Keypad1),
217+
KEYSYM_KP_END => Ok(KeypadEnd),
218+
KEYSYM_KP_2 => Ok(Keypad2),
219+
KEYSYM_KP_DOWN => Ok(KeypadDown),
220+
KEYSYM_KP_3 => Ok(Keypad3),
221+
KEYSYM_KP_PGDOWN => Ok(KeypadPgDown),
222+
KEYSYM_KP_0 => Ok(Keypad0),
223+
KEYSYM_KP_INSERT => Ok(KeypadInsert),
224+
KEYSYM_KP_PERIOD => Ok(KeypadPeriod),
225+
KEYSYM_KP_DELETE => Ok(KeypadDelete),
226+
227+
_ => Err(anyhow!("unknown keysym=0x{:x}", value)),
83228
}
84229
}
85230
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Copyright 2022 Oxide Computer Company
66

77
pub mod encodings;
8-
mod keysym;
8+
pub mod keysym;
99
pub mod pixel_formats;
1010
pub mod rfb;
1111
pub mod server;

src/rfb.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
1212
use tokio::net::TcpStream;
1313

1414
use crate::encodings::{Encoding, EncodingType};
15-
use crate::keysym::Keysym;
15+
use crate::keysym::KeySym;
1616
use crate::pixel_formats::rgb_888;
1717

1818
pub trait ReadMessage {
@@ -605,9 +605,14 @@ impl ReadMessage for ClientMessage {
605605
// 2 bytes of padding
606606
stream.read_u16().await?;
607607

608-
let key = Keysym::try_from(stream.read_u32().await?)?;
608+
let keysym_raw = stream.read_u32().await?;
609+
let keysym = KeySym::try_from(keysym_raw)?;
609610

610-
let key_event = KeyEvent { is_pressed, key };
611+
let key_event = KeyEvent {
612+
is_pressed,
613+
keysym,
614+
keysym_raw,
615+
};
611616

612617
Ok(ClientMessage::KeyEvent(key_event))
613618
}
@@ -650,11 +655,25 @@ pub struct FramebufferUpdateRequest {
650655
resolution: Resolution,
651656
}
652657

653-
#[derive(Debug)]
654-
#[allow(dead_code)]
658+
#[derive(Debug, Copy, Clone)]
655659
pub struct KeyEvent {
656660
is_pressed: bool,
657-
key: Keysym,
661+
keysym: KeySym,
662+
keysym_raw: u32,
663+
}
664+
665+
impl KeyEvent {
666+
pub fn keysym_raw(&self) -> u32 {
667+
self.keysym_raw
668+
}
669+
670+
pub fn keysym(&self) -> KeySym {
671+
self.keysym
672+
}
673+
674+
pub fn is_pressed(&self) -> bool {
675+
self.is_pressed
676+
}
658677
}
659678

660679
bitflags! {

0 commit comments

Comments
 (0)