Skip to content

Commit 756dc5a

Browse files
committed
fixup
1 parent 754c683 commit 756dc5a

3 files changed

Lines changed: 83 additions & 23 deletions

File tree

warpgate-protocol-rdp/src/server/hold_screen.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use anyhow::{Result, bail};
1010
use tokio::sync::Mutex;
1111
use tokio::sync::mpsc::{Sender, UnboundedReceiver};
1212
use warpgate_common::auth::AuthStateUserInfo;
13-
use warpgate_core::{DesktopInput, Services};
13+
use warpgate_core::{DesktopInput, Scancode, Services};
1414
use warpgate_desktop_auth::{
1515
Deadline, HoldEvent, HoldFrame, HoldInputSource, HoldPainter as HoldPainterExt,
1616
InteractiveAuth, OtpAction, run_hold_screen as run_hold_screen_driver,
@@ -82,7 +82,7 @@ impl HoldInputSource for RdpHoldInput<'_> {
8282
scancode,
8383
down: true,
8484
})) => scancode
85-
.and_then(|s| scancode_otp_action(s.code))
85+
.and_then(scancode_otp_action)
8686
.or_else(|| keysym.and_then(key_otp_action))
8787
.map_or(HoldEvent::Other, HoldEvent::Otp),
8888
Some(ServerEvent::Size { width, height }) => {
@@ -218,7 +218,14 @@ impl HoldPainter {
218218
}
219219

220220
/// Map a PC/AT set-1 scancode (what mstsc/FreeRDP send) to an OTP action.
221-
fn scancode_otp_action(code: u8) -> Option<OtpAction> {
221+
fn scancode_otp_action(scancode: Scancode) -> Option<OtpAction> {
222+
let Scancode { code, extended } = scancode;
223+
// The nav cluster shares its make codes with the keypad and is told apart only by the
224+
// E0 prefix, so without this an arrow key would type a digit. Numpad Enter is the one
225+
// extended key that still means something here.
226+
if extended && code != 0x1c {
227+
return None;
228+
}
222229
Some(match code {
223230
0x02..=0x0a => OtpAction::Digit(char::from(b'1' + (code - 0x02))), // top row 1..9
224231
0x0b | 0x52 => OtpAction::Digit('0'), // keypad 0
@@ -249,7 +256,7 @@ fn key_otp_action(keysym: u32) -> Option<OtpAction> {
249256

250257
#[cfg(test)]
251258
mod otp_input_tests {
252-
use super::{OtpAction, key_otp_action, scancode_otp_action};
259+
use super::{OtpAction, Scancode, key_otp_action, scancode_otp_action};
253260

254261
fn digit(action: Option<OtpAction>) -> Option<char> {
255262
match action {
@@ -258,12 +265,26 @@ mod otp_input_tests {
258265
}
259266
}
260267

268+
fn plain(code: u8) -> Option<OtpAction> {
269+
scancode_otp_action(Scancode {
270+
code,
271+
extended: false,
272+
})
273+
}
274+
275+
fn e0(code: u8) -> Option<OtpAction> {
276+
scancode_otp_action(Scancode {
277+
code,
278+
extended: true,
279+
})
280+
}
281+
261282
#[test]
262283
fn scancode_number_row() {
263284
// 0x02..=0x0a is the '1'..'9' row (computed, so guard the ends), 0x0b is '0'.
264-
assert_eq!(digit(scancode_otp_action(0x02)), Some('1'));
265-
assert_eq!(digit(scancode_otp_action(0x0a)), Some('9'));
266-
assert_eq!(digit(scancode_otp_action(0x0b)), Some('0'));
285+
assert_eq!(digit(plain(0x02)), Some('1'));
286+
assert_eq!(digit(plain(0x0a)), Some('9'));
287+
assert_eq!(digit(plain(0x0b)), Some('0'));
267288
}
268289

269290
#[test]
@@ -280,23 +301,26 @@ mod otp_input_tests {
280301
(0x48, '8'),
281302
(0x49, '9'),
282303
] {
283-
assert_eq!(
284-
digit(scancode_otp_action(code)),
285-
Some(expected),
286-
"scancode {code:#x}"
287-
);
304+
assert_eq!(digit(plain(code)), Some(expected), "scancode {code:#x}");
305+
}
306+
}
307+
308+
/// The nav cluster repeats the keypad's make codes under an E0 prefix; pressing an
309+
/// arrow must not enter a digit.
310+
#[test]
311+
fn scancode_nav_cluster_is_not_a_digit() {
312+
for code in [0x47u8, 0x48, 0x49, 0x4b, 0x4d, 0x4f, 0x50, 0x51, 0x52] {
313+
assert!(e0(code).is_none(), "extended scancode {code:#x}");
288314
}
315+
assert!(matches!(e0(0x1c), Some(OtpAction::Submit))); // numpad Enter
289316
}
290317

291318
#[test]
292319
fn scancode_control_and_unmapped() {
293-
assert!(matches!(
294-
scancode_otp_action(0x0e),
295-
Some(OtpAction::Backspace)
296-
));
297-
assert!(matches!(scancode_otp_action(0x1c), Some(OtpAction::Submit)));
298-
assert!(scancode_otp_action(0x3b).is_none()); // F1 — not an OTP key
299-
assert!(scancode_otp_action(0x00).is_none());
320+
assert!(matches!(plain(0x0e), Some(OtpAction::Backspace)));
321+
assert!(matches!(plain(0x1c), Some(OtpAction::Submit)));
322+
assert!(plain(0x3b).is_none()); // F1 — not an OTP key
323+
assert!(plain(0x00).is_none());
300324
}
301325

302326
#[test]

warpgate-web/src/admin/player/DesktopRecordingPlayer.svelte

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@
5050
type Frame = DesktopFrame & { time: number }
5151
type InputItem =
5252
| { type: 'key_input'; time: number; keysym: number; down: boolean }
53-
| { type: 'scancode_input'; time: number; code: number; down: boolean }
53+
| {
54+
type: 'scancode_input'
55+
time: number
56+
code: number
57+
extended: boolean
58+
down: boolean
59+
}
5460
| {
5561
type: 'pointer_input'
5662
time: number
@@ -243,7 +249,10 @@
243249
if (item.down) {
244250
keyPresses = [
245251
...keyPresses,
246-
{ time: item.time, label: scancodeLabel(item.code) },
252+
{
253+
time: item.time,
254+
label: scancodeLabel(item.code, item.extended),
255+
},
247256
]
248257
}
249258
break

warpgate-web/src/common/desktopInput.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,29 @@ const SCANCODE_NAMES: Record<number, string> = {
152152
88: 'F12',
153153
69: 'NumLock',
154154
70: 'ScrollLock',
155+
71: 'Num 7',
156+
72: 'Num 8',
157+
73: 'Num 9',
158+
74: 'Num -',
159+
75: 'Num 4',
160+
76: 'Num 5',
161+
77: 'Num 6',
162+
78: 'Num +',
163+
79: 'Num 1',
164+
80: 'Num 2',
165+
81: 'Num 3',
166+
82: 'Num 0',
167+
83: 'Num .',
168+
}
169+
170+
// The nav cluster, the right-hand modifiers and the keypad's Enter and `/` repeat make
171+
// codes from the table above and are told apart only by the E0 prefix.
172+
const EXTENDED_SCANCODE_NAMES: Record<number, string> = {
173+
28: 'Enter',
174+
29: 'Ctrl',
175+
53: '/',
176+
55: 'PrintScreen',
177+
56: 'Alt',
155178
71: 'Home',
156179
72: '↑',
157180
73: 'PgUp',
@@ -162,10 +185,14 @@ const SCANCODE_NAMES: Record<number, string> = {
162185
81: 'PgDn',
163186
82: 'Insert',
164187
83: 'Delete',
188+
91: 'Super',
189+
92: 'Super',
190+
93: 'Menu',
165191
}
166192

167-
export function scancodeLabel(code: number): string {
168-
return SCANCODE_NAMES[code] ?? `0x${code.toString(16)}`
193+
export function scancodeLabel(code: number, extended: boolean): string {
194+
const names = extended ? EXTENDED_SCANCODE_NAMES : SCANCODE_NAMES
195+
return names[code] ?? `0x${code.toString(16)}`
169196
}
170197

171198
// `KeyboardEvent.code` -> PC/AT set-1 make code, with the 0xE000 bit standing in for the

0 commit comments

Comments
 (0)