nx_x11_keyboard.nx source
↩ module page · 164 lines · 6953 B
1// nx_x11_keyboard.nx -- bits-up X11 keyboard input for the game platform (F1105).
2//
3// X11 KeyPress events carry server-relative KEYCODES, not meanings; the meaning lives in the
4// server's keysym table. This lib fetches that table (GetKeyboardMapping, opcode 101), folds each
5// keycode's first keysym down to the BROWSER-STYLE virtual-key codes nx_input_abstract already
6// binds (WASD=87/65/83/68, arrows=37-40, space=32, enter=13...), and can inject synthetic key
7// events (SendEvent, opcode 25) so a selftest can drive the REAL server round-trip with no human.
8//
9// GetKeyboardMapping request (8 bytes): [101][pad][len=2 u16][first_keycode][count][pad2]
10// Reply: 32-byte header (byte1 = keysyms_per_keycode, bytes 4-7 = data words) + u32 keysyms.
11//
12// SendEvent request (44 bytes): [25][propagate][len=11 u16][destination u32][event_mask u32]
13// + the 32-byte event. With event_mask=0 the server delivers to the client that CREATED the
14// destination window (us), flagged synthetic: event byte0 |= 0x80 -- dispatchers mask 0x7f.
15//
16// license_tier: ORIGINAL
17// genealogy_id: international-research-sources/x_org/xproto_v11_r0
18// lineage_id: nishi_x11_keyboard_q10
19
20import "nx_syscalls.nx"
21import "nx_x11_connect.nx"
22import "nx_x11_window.nx"
23
24const NX_X11_EVENT_KEY_RELEASE: i64 = 0x00000002
25const NX_X11_KEYMAP_N: i64 = 256
26
27// X11 keysym -> browser-style virtual-key code (what nx_input_abstract binds). 0 = unmapped.
28// Pure function of the published keysym encoding -- gateable with no server.
29func nx_keysym_to_vk(ks: i64) -> i64 {
30 if ks >= 0x61 { if ks <= 0x7A { return ks - 32 } } // a-z -> A-Z vk 65..90
31 if ks >= 0x41 { if ks <= 0x5A { return ks } } // A-Z
32 if ks >= 0x30 { if ks <= 0x39 { return ks } } // 0-9 -> vk 48..57
33 if ks == 0x20 { return 32 } // space
34 if ks == 0xFF51 { return 37 } // Left
35 if ks == 0xFF52 { return 38 } // Up
36 if ks == 0xFF53 { return 39 } // Right
37 if ks == 0xFF54 { return 40 } // Down
38 if ks == 0xFF0D { return 13 } // Return
39 if ks == 0xFF1B { return 27 } // Escape
40 return 0
41}
42
43// encode the 8-byte GetKeyboardMapping request
44func nx_x11_keymap_req(req: *u8, first: i64, count: i64) -> i64 {
45 req[0] = 101
46 req[1] = 0
47 _x11_wr_u16(req, 2, 2)
48 req[4] = first as u8
49 req[5] = count as u8
50 req[6] = 0
51 req[7] = 0
52 return 8
53}
54
55// fetch the server keymap and fill vk_table[256]: keycode -> vk (0 = unmapped).
56// Drains non-Reply packets like nx_x11_get_image (call before the event loop starts).
57// Returns keysyms_per_keycode (>0) or negative.
58func nx_x11_load_keymap(conn: *X11Conn, vk_table: *i64) -> i64 {
59 var i: i64 = 0
60 while i < NX_X11_KEYMAP_N { vk_table[i] = 0; i = i + 1 }
61 let first: i64 = conn.min_keycode
62 var count: i64 = conn.max_keycode - conn.min_keycode + 1
63 if count < 1 { return 0 - 2 }
64 let req: *u8 = sys_mmap(16)
65 nx_x11_keymap_req(req, first, count)
66 if _x11_send(conn, req, 8) < 0 { return 0 - 1 }
67
68 let hdr: *u8 = sys_mmap(64)
69 var saw: i64 = 0
70 var safety: i64 = 0
71 while saw == 0 {
72 if safety >= 64 { return 0 - 3 }
73 var got: i64 = 0
74 while got < 32 {
75 let r: i64 = sys_read(conn.fd, ((hdr as i64) + got) as *u8, 32 - got)
76 if r <= 0 { return 0 - 1 }
77 got = got + r
78 }
79 let kind: i64 = (hdr[0] & 0xff) as i64
80 if kind == 0 { return 0 - 4 }
81 if kind == 1 { saw = 1 }
82 safety = safety + 1
83 }
84 let kpk: i64 = (hdr[1] & 0xff) as i64
85 let words: i64 = _x11_rd_u32(hdr, 4)
86 let data: *u8 = sys_mmap(words*4 + 64)
87 var got2: i64 = 0
88 while got2 < words*4 {
89 let r2: i64 = sys_read(conn.fd, ((data as i64) + got2) as *u8, words*4 - got2)
90 if r2 <= 0 { return 0 - 1 }
91 got2 = got2 + r2
92 }
93 if kpk < 1 { return 0 - 5 }
94 var k: i64 = 0
95 while k < count {
96 let ks: i64 = _x11_rd_u32(data, k*kpk*4)
97 let kc: i64 = first + k
98 if kc >= 0 { if kc < NX_X11_KEYMAP_N { vk_table[kc] = nx_keysym_to_vk(ks) } }
99 k = k + 1
100 }
101 return kpk
102}
103
104// encode the 44-byte SendEvent(KeyPress/KeyRelease) request; returns total bytes (44)
105func nx_x11_send_key_req(req: *u8, root: i64, window: i64, keycode: i64, is_press: i64) -> i64 {
106 var i: i64 = 0
107 while i < 44 { req[i] = 0; i = i + 1 }
108 req[0] = 25
109 req[1] = 0 // propagate = False
110 _x11_wr_u16(req, 2, 11) // 44 bytes = 11 words
111 _x11_wr_u32(req, 4, window) // destination
112 _x11_wr_u32(req, 8, 0) // event_mask 0 => deliver to the creator (us)
113 if is_press != 0 { req[12] = 2 } else { req[12] = 3 }
114 req[13] = keycode as u8
115 _x11_wr_u32(req, 16, 0) // time
116 _x11_wr_u32(req, 20, root)
117 _x11_wr_u32(req, 24, window) // event window
118 req[42] = 1 // same-screen
119 return 44
120}
121
122// inject a synthetic key event at the real server; it comes back on our wire flagged |0x80
123func nx_x11_send_key(conn: *X11Conn, window: i64, keycode: i64, is_press: i64) -> i64 {
124 let req: *u8 = sys_mmap(64)
125 nx_x11_send_key_req(req, conn.root_window, window, keycode, is_press)
126 return _x11_send(conn, req, 44)
127}
128
129// WarpPointer (opcode 41): move the pointer to (x,y) inside dst-window -- the FPS mouselook
130// recenter, so relative deltas never die at the window edge.
131func nx_x11_warp_pointer(conn: *X11Conn, window: i64, x: i64, y: i64) -> i64 {
132 let req: *u8 = sys_mmap(32)
133 var i: i64 = 0
134 while i < 24 { req[i] = 0; i = i + 1 }
135 req[0] = 41
136 _x11_wr_u16(req, 2, 6)
137 _x11_wr_u32(req, 4, 0) // src-window None (unconditional warp)
138 _x11_wr_u32(req, 8, window) // dst-window
139 _x11_wr_u16(req, 20, x) // dst-x
140 _x11_wr_u16(req, 22, y)
141 return _x11_send(conn, req, 24)
142}
143
144// inject a synthetic MotionNotify at (x,y) -- drives the mouselook path in selftests, no human hand
145func nx_x11_send_motion(conn: *X11Conn, window: i64, x: i64, y: i64) -> i64 {
146 let req: *u8 = sys_mmap(64)
147 var i: i64 = 0
148 while i < 44 { req[i] = 0; i = i + 1 }
149 req[0] = 25
150 _x11_wr_u16(req, 2, 11)
151 _x11_wr_u32(req, 4, window)
152 _x11_wr_u32(req, 8, 0)
153 req[12] = 6 // MotionNotify
154 _x11_wr_u32(req, 20, conn.root_window)
155 _x11_wr_u32(req, 24, window)
156 _x11_wr_u16(req, 36, x) // event-x (offset 24 in the event body)
157 _x11_wr_u16(req, 38, y) // event-y
158 req[42] = 1 // same-screen
159 return _x11_send(conn, req, 44)
160}
161
162func main() -> i64 {
163 return 0
164}