-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathx11-ffi.ts
More file actions
83 lines (78 loc) · 3.22 KB
/
Copy pathx11-ffi.ts
File metadata and controls
83 lines (78 loc) · 3.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { FFIType } from 'bun:ffi';
import { dlopen } from '../dlopen';
import { UnsupportedPlatformError } from '../../../common/errors';
import { currentPlatform } from '../../../common/platform';
/**
* Xlib FFI for the Linux `globalShortcut` backend (`XGrabKey`).
*
* Loaded only on Linux. On X11 we open a DEDICATED display connection, grab each
* accelerator's keycode+modifier combo on the root window with `XGrabKey`, and
* poll that connection for `KeyPress` events from the cooperative pump. Wayland
* is NOT supported in v1 — global shortcuts there require the
* `org.freedesktop.portal.GlobalShortcuts` desktop portal, which is deferred.
*
* `XEvent` is a ~192-byte union; we never marshal it as a struct — we allocate a
* byte buffer, let `XNextEvent` fill it, and read the `type` (int at offset 0)
* and, for `XKeyEvent`, the `keycode` field by offset.
*/
const LIBX11_PATH = 'libX11.so.6';
/** The Xlib symbol descriptor table. */
export const X11_FFI_SYMBOLS = {
// (const char *display_name) -> Display* (NULL = $DISPLAY)
XOpenDisplay: { args: [FFIType.cstring], returns: FFIType.pointer },
// (Display*) -> int
XCloseDisplay: { args: [FFIType.pointer], returns: FFIType.i32 },
// (Display*) -> Window (XID, unsigned long)
XDefaultRootWindow: { args: [FFIType.pointer], returns: FFIType.u64 },
// (Display*, KeySym) -> KeyCode (unsigned char)
XKeysymToKeycode: { args: [FFIType.pointer, FFIType.u64], returns: FFIType.u8 },
// (const char *string) -> KeySym (unsigned long)
XStringToKeysym: { args: [FFIType.cstring], returns: FFIType.u64 },
// (Display*, int keycode, unsigned int modifiers, Window grab_window,
// Bool owner_events, int pointer_mode, int keyboard_mode) -> int
XGrabKey: {
args: [
FFIType.pointer,
FFIType.i32,
FFIType.u32,
FFIType.u64,
FFIType.i32,
FFIType.i32,
FFIType.i32,
],
returns: FFIType.i32,
},
// (Display*, int keycode, unsigned int modifiers, Window grab_window) -> int
XUngrabKey: {
args: [FFIType.pointer, FFIType.i32, FFIType.u32, FFIType.u64],
returns: FFIType.i32,
},
// (Display*, Window, long event_mask) -> int
XSelectInput: { args: [FFIType.pointer, FFIType.u64, FFIType.i64], returns: FFIType.i32 },
// (Display*) -> int
XPending: { args: [FFIType.pointer], returns: FFIType.i32 },
// (Display*, XEvent *event_return) -> int
XNextEvent: { args: [FFIType.pointer, FFIType.pointer], returns: FFIType.i32 },
// (Display*) -> int
XFlush: { args: [FFIType.pointer], returns: FFIType.i32 },
// (int (*handler)(Display*, XErrorEvent*)) -> previous handler (we pass a no-op)
XSetErrorHandler: { args: [FFIType.pointer], returns: FFIType.pointer },
} as const;
const cache: { ffi: ReturnType<typeof dlopen<typeof X11_FFI_SYMBOLS>> | undefined } = {
ffi: undefined,
};
/** Open `libX11.so.6` and return the Xlib symbol table. Memoised. */
export const loadX11FFI = () => {
const platform = currentPlatform();
if (platform !== 'linux') {
throw new UnsupportedPlatformError(
`loadX11FFI() is only supported on Linux; current platform is ${platform}`,
);
}
if (cache.ffi) {
return cache.ffi;
}
const ffi = dlopen(LIBX11_PATH, X11_FFI_SYMBOLS);
cache.ffi = ffi;
return ffi;
};