code wiki / (root) / nx_x11_keyboard.nx

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}