I'm currently working on a PR to minifb to fix this issue, and my research says that I need to use the function Xutf8LookupString
to properly read key press events as characters. This requires that an XIC instance is created, but I'm having a problem with creating that instance. I found an example C program (and I compiled and tested it and it works fine) that does everything that is needed to get these key presses correctly, but when I try to do the exact same thing in Rust, XCreateIC returns a null pointer.
The relevant C code looks like this:
setlocale(LC_ALL, "");
Display* dpy = XOpenDisplay(NULL);
Window win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 0, 0, 100, 100, 0, 0, 0);
XMapRaised(dpy, win);
XSync(dpy, False);
// X input method setup, only strictly necessary for intl key text
// loads the XMODIFIERS environment variable to see what IME to use
XSetLocaleModifiers("");
XIM xim = XOpenIM(dpy, 0, 0, 0);
if(!xim){
// fallback to internal input method
XSetLocaleModifiers("@im=none");
xim = XOpenIM(dpy, 0, 0, 0);
}
// X input context, you can have multiple for text boxes etc, but having a
// single one is the easiest.
XIC xic = XCreateIC(xim,
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, win,
XNFocusWindow, win,
NULL);
and the equivalent Rust code looks like this (some setup is removed since minifb has much more initialization code than that example):
let handle = (d.lib.XCreateWindow)(
d.display,
root,
x as i32,
y as i32,
width as u32,
height as u32,
0, /* border_width */
d.depth,
xlib::InputOutput as u32, /* class */
d.visual,
xlib::CWColormap | xlib::CWBackingStore | xlib::CWBackPixel | xlib::CWBorderPixel,
&mut attributes,
);
let empty_string = CString::new("").unwrap();
(d.lib.XSetLocaleModifiers)(empty_string.as_ptr());
(d.lib.XSetErrorHandler)(Some(x11_error_handler));
let xim = (d.lib.XOpenIM)(d.display, 0 as XrmDatabase, 0 as *mut c_char, 0 as *mut c_char);
if(xim as usize) == 0{
panic!("Failed to setup X IM via XOpenIM.");
}
let xn_input_style = CString::new(XNInputStyle).unwrap();
let xn_client_window = CString::new(XNClientWindow).unwrap();
let xic = (d.lib.XCreateIC)(xim, xn_input_style.as_ptr(), XIMPreeditNothing | XIMStatusNothing, xn_client_window.as_ptr(), handle as c_ulong, XNFocusWindow.as_ptr(), handle as c_ulong, std::ptr::null_mut::<c_void>());
if (xic as usize) == 0{
panic!("Failed to setup X IC via XCreateIC."); //panics here
}
In this code, the panic at the end always runs (I'll do proper error handling once I have it working). Yet, as far as I can tell, I am doing this call in the exact same way as in the C program so I don't understand why it is doing this. Furthermore, this being a C library there's no panic error message or error return type that I can inspect. I tried to add an error callback to Xlib via
(d.lib.XSetErrorHandler)(Some(x11_error_handler));
but this error handler is not being called. Additionally, I can't step into the library usefully because it's all disassembly.
How can I debug this?