mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
x11: Don't panic when using dead keys (#432)
This commit is contained in:
parent
be6d2ed3b9
commit
f3ab8af813
|
@ -1,6 +1,7 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
- Added subclass to macos windows so they can be made resizable even with no decorations.
|
- Added subclass to macos windows so they can be made resizable even with no decorations.
|
||||||
|
- Dead keys now work properly on X11, no longer resulting in a panic.
|
||||||
|
|
||||||
# Version 0.11.3 (2018-03-28)
|
# Version 0.11.3 (2018-03-28)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::sync::{Arc, Mutex, Weak};
|
||||||
use std::sync::atomic::{self, AtomicBool};
|
use std::sync::atomic::{self, AtomicBool};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::os::raw::{c_char, c_int, c_long, c_uchar, c_ulong};
|
use std::os::raw::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong};
|
||||||
|
|
||||||
use libc;
|
use libc;
|
||||||
|
|
||||||
|
@ -199,8 +199,14 @@ impl EventsLoop {
|
||||||
{
|
{
|
||||||
let xlib = &self.display.xlib;
|
let xlib = &self.display.xlib;
|
||||||
|
|
||||||
// Handle dead keys and other input method funtimes
|
// XFilterEvent tells us when an event has been discarded by the input method.
|
||||||
if ffi::True == unsafe { (self.display.xlib.XFilterEvent)(xev, { let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window }) } {
|
// Specifically, this involves all of the KeyPress events in compose/pre-edit sequences,
|
||||||
|
// along with an extra copy of the KeyRelease events. This also prevents backspace and
|
||||||
|
// arrow keys from being detected twice.
|
||||||
|
if ffi::True == unsafe { (self.display.xlib.XFilterEvent)(
|
||||||
|
xev,
|
||||||
|
{ let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window }
|
||||||
|
) } {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,16 +420,15 @@ impl EventsLoop {
|
||||||
callback(Event::WindowEvent { window_id, event: WindowEvent::Refresh });
|
callback(Event::WindowEvent { window_id, event: WindowEvent::Refresh });
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Use XInput2 + libxkbcommon for keyboard input!
|
|
||||||
ffi::KeyPress | ffi::KeyRelease => {
|
ffi::KeyPress | ffi::KeyRelease => {
|
||||||
use events::ElementState::{Pressed, Released};
|
use events::ElementState::{Pressed, Released};
|
||||||
|
|
||||||
let state;
|
// Note that in compose/pre-edit sequences, this will always be Released.
|
||||||
if xev.get_type() == ffi::KeyPress {
|
let state = if xev.get_type() == ffi::KeyPress {
|
||||||
state = Pressed;
|
Pressed
|
||||||
} else {
|
} else {
|
||||||
state = Released;
|
Released
|
||||||
}
|
};
|
||||||
|
|
||||||
let xkev: &mut ffi::XKeyEvent = xev.as_mut();
|
let xkev: &mut ffi::XKeyEvent = xev.as_mut();
|
||||||
|
|
||||||
|
@ -439,55 +444,50 @@ impl EventsLoop {
|
||||||
|
|
||||||
let keysym = unsafe {
|
let keysym = unsafe {
|
||||||
let mut keysym = 0;
|
let mut keysym = 0;
|
||||||
(self.display.xlib.XLookupString)(xkev, ptr::null_mut(), 0, &mut keysym, ptr::null_mut());
|
(self.display.xlib.XLookupString)(
|
||||||
|
xkev,
|
||||||
|
ptr::null_mut(),
|
||||||
|
0,
|
||||||
|
&mut keysym,
|
||||||
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
keysym
|
keysym
|
||||||
};
|
};
|
||||||
|
|
||||||
let vkey = events::keysym_to_element(keysym as libc::c_uint);
|
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
||||||
|
|
||||||
callback(Event::WindowEvent { window_id, event: WindowEvent::KeyboardInput {
|
// When a compose sequence or IME pre-edit is finished, it ends in a KeyPress with
|
||||||
// Typical virtual core keyboard ID. xinput2 needs to be used to get a reliable value.
|
// a keycode of 0.
|
||||||
device_id: mkdid(3),
|
if xkev.keycode != 0 {
|
||||||
input: KeyboardInput {
|
callback(Event::WindowEvent { window_id, event: WindowEvent::KeyboardInput {
|
||||||
state: state,
|
// Standard virtual core keyboard ID. XInput2 needs to be used to get a
|
||||||
scancode: xkev.keycode - 8,
|
// reliable value, though this should only be an issue under multiseat
|
||||||
virtual_keycode: vkey,
|
// configurations.
|
||||||
modifiers,
|
device_id: mkdid(3),
|
||||||
},
|
input: KeyboardInput {
|
||||||
}});
|
state,
|
||||||
|
scancode: xkev.keycode - 8,
|
||||||
|
virtual_keycode,
|
||||||
|
modifiers,
|
||||||
|
},
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
if state == Pressed {
|
if state == Pressed {
|
||||||
let written = unsafe {
|
let written = {
|
||||||
use std::str;
|
let windows = self.windows.lock().unwrap();
|
||||||
|
|
||||||
const INIT_BUFF_SIZE: usize = 16;
|
|
||||||
let mut windows = self.windows.lock().unwrap();
|
|
||||||
let window_data = {
|
let window_data = {
|
||||||
if let Some(window_data) = windows.get_mut(&WindowId(window)) {
|
if let Some(window_data) = windows.get(&WindowId(window)) {
|
||||||
window_data
|
window_data
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/* buffer allocated on heap instead of stack, due to the possible
|
|
||||||
* reallocation */
|
|
||||||
let mut buffer: Vec<u8> = vec![mem::uninitialized(); INIT_BUFF_SIZE];
|
|
||||||
let mut keysym: ffi::KeySym = 0;
|
|
||||||
let mut status: ffi::Status = 0;
|
|
||||||
let mut count = (self.display.xlib.Xutf8LookupString)(window_data.ic, xkev,
|
|
||||||
mem::transmute(buffer.as_mut_ptr()),
|
|
||||||
buffer.len() as libc::c_int,
|
|
||||||
&mut keysym, &mut status);
|
|
||||||
/* buffer overflowed, dynamically reallocate */
|
|
||||||
if status == ffi::XBufferOverflow {
|
|
||||||
buffer = vec![mem::uninitialized(); count as usize];
|
|
||||||
count = (self.display.xlib.Xutf8LookupString)(window_data.ic, xkev,
|
|
||||||
mem::transmute(buffer.as_mut_ptr()),
|
|
||||||
buffer.len() as libc::c_int,
|
|
||||||
&mut keysym, &mut status);
|
|
||||||
}
|
|
||||||
|
|
||||||
str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
|
unsafe {
|
||||||
|
util::lookup_utf8(&self.display, window_data.ic, xkev)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for chr in written.chars() {
|
for chr in written.chars() {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::str;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::os::raw::{c_char, c_double, c_int, c_long, c_short, c_uchar, c_uint, c_ulong};
|
use std::os::raw::{c_char, c_double, c_int, c_long, c_short, c_uchar, c_uint, c_ulong};
|
||||||
|
@ -247,3 +248,53 @@ pub unsafe fn query_pointer(
|
||||||
relative_to_window,
|
relative_to_window,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn lookup_utf8_inner(
|
||||||
|
xconn: &Arc<XConnection>,
|
||||||
|
ic: ffi::XIC,
|
||||||
|
key_event: &mut ffi::XKeyEvent,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
) -> (ffi::KeySym, ffi::Status, c_int) {
|
||||||
|
let mut keysym: ffi::KeySym = 0;
|
||||||
|
let mut status: ffi::Status = 0;
|
||||||
|
let count = (xconn.xlib.Xutf8LookupString)(
|
||||||
|
ic,
|
||||||
|
key_event,
|
||||||
|
buffer.as_mut_ptr() as *mut c_char,
|
||||||
|
buffer.len() as c_int,
|
||||||
|
&mut keysym,
|
||||||
|
&mut status,
|
||||||
|
);
|
||||||
|
(keysym, status, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn lookup_utf8(
|
||||||
|
xconn: &Arc<XConnection>,
|
||||||
|
ic: ffi::XIC,
|
||||||
|
key_event: &mut ffi::XKeyEvent,
|
||||||
|
) -> String {
|
||||||
|
const INIT_BUFF_SIZE: usize = 16;
|
||||||
|
|
||||||
|
// Buffer allocated on heap instead of stack, due to the possible reallocation
|
||||||
|
let mut buffer: Vec<u8> = vec![mem::uninitialized(); INIT_BUFF_SIZE];
|
||||||
|
let (_, status, mut count) = lookup_utf8_inner(
|
||||||
|
xconn,
|
||||||
|
ic,
|
||||||
|
key_event,
|
||||||
|
&mut buffer,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Buffer overflowed, dynamically reallocate
|
||||||
|
if status == ffi::XBufferOverflow {
|
||||||
|
buffer = vec![mem::uninitialized(); count as usize];
|
||||||
|
let (_, _, new_count) = lookup_utf8_inner(
|
||||||
|
xconn,
|
||||||
|
ic,
|
||||||
|
key_event,
|
||||||
|
&mut buffer,
|
||||||
|
);
|
||||||
|
count = new_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
str::from_utf8(&buffer[..count as usize]).unwrap_or("").to_string()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue