mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-23 02:16:33 +11:00
On X11, fix IME not working
The change to xinput2 completely disabled IME support, thus we've got a dead keys reporting, because nothing was eating the key events anymore, however that's not what we really need, given that not working IME makes it impossible for some users to type. The proper solution is to not use Xlib at all for that and rely on xcb and its tooling around the XIM and text compose stuff, so we'll have full control over what is getting sent to the XIM/IC or not. Fixes #2888.
This commit is contained in:
parent
b0106898f7
commit
a320702a71
4 changed files with 57 additions and 59 deletions
|
@ -31,6 +31,8 @@ pub(super) struct EventProcessor<T: 'static> {
|
||||||
pub(super) kb_state: KbdState,
|
pub(super) kb_state: KbdState,
|
||||||
// Number of touch events currently in progress
|
// Number of touch events currently in progress
|
||||||
pub(super) num_touch: u32,
|
pub(super) num_touch: u32,
|
||||||
|
// Whether we've got a key release for the key press.
|
||||||
|
pub(super) got_key_release: bool,
|
||||||
pub(super) first_touch: Option<u64>,
|
pub(super) first_touch: Option<u64>,
|
||||||
// Currently focused window belonging to this process
|
// Currently focused window belonging to this process
|
||||||
pub(super) active_window: Option<ffi::Window>,
|
pub(super) active_window: Option<ffi::Window>,
|
||||||
|
@ -535,34 +537,54 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that in compose/pre-edit sequences, we'll always receive KeyRelease events
|
// Note that in compose/pre-edit sequences, we'll always receive KeyRelease events
|
||||||
ffi::KeyPress => {
|
ty @ ffi::KeyPress | ty @ ffi::KeyRelease => {
|
||||||
let xkev: &mut ffi::XKeyEvent = xev.as_mut();
|
let xkev: &mut ffi::XKeyEvent = xev.as_mut();
|
||||||
|
let window = match self.active_window {
|
||||||
let window = xkev.window;
|
Some(window) => window,
|
||||||
let window_id = mkwid(window);
|
None => return,
|
||||||
|
|
||||||
let written = if let Some(ic) = wt.ime.borrow().get_context(window) {
|
|
||||||
wt.xconn.lookup_utf8(ic, xkev)
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we're composing right now, send the string we've got from X11 via
|
let window_id = mkwid(window);
|
||||||
// Ime::Commit.
|
let device_id = mkdid(util::VIRTUAL_CORE_KEYBOARD);
|
||||||
if self.is_composing && xkev.keycode == 0 && !written.is_empty() {
|
|
||||||
let event = Event::WindowEvent {
|
|
||||||
window_id,
|
|
||||||
event: WindowEvent::Ime(Ime::Preedit(String::new(), None)),
|
|
||||||
};
|
|
||||||
callback(event);
|
|
||||||
|
|
||||||
let event = Event::WindowEvent {
|
let keycode = xkev.keycode as _;
|
||||||
window_id,
|
let repeat = ty == ffi::KeyPress && !self.got_key_release;
|
||||||
event: WindowEvent::Ime(Ime::Commit(written)),
|
// Update state after the repeat setting.
|
||||||
};
|
let state = if ty == ffi::KeyPress {
|
||||||
|
self.got_key_release = false;
|
||||||
|
ElementState::Pressed
|
||||||
|
} else {
|
||||||
|
self.got_key_release = true;
|
||||||
|
ElementState::Released
|
||||||
|
};
|
||||||
|
|
||||||
self.is_composing = false;
|
if keycode != 0 && !self.is_composing {
|
||||||
callback(event);
|
let event = self.kb_state.process_key_event(keycode, state, repeat);
|
||||||
|
callback(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::KeyboardInput {
|
||||||
|
device_id,
|
||||||
|
event,
|
||||||
|
is_synthetic: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if let Some(ic) = wt.ime.borrow().get_context(window) {
|
||||||
|
let written = wt.xconn.lookup_utf8(ic, xkev);
|
||||||
|
if !written.is_empty() {
|
||||||
|
let event = Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::Ime(Ime::Preedit(String::new(), None)),
|
||||||
|
};
|
||||||
|
callback(event);
|
||||||
|
|
||||||
|
let event = Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::Ime(Ime::Commit(written)),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.is_composing = false;
|
||||||
|
callback(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1029,40 +1051,6 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The regular KeyPress event has a problem where if you press a dead key, a KeyPress
|
|
||||||
// event won't be emitted. XInput 2 does not have this problem.
|
|
||||||
ffi::XI_KeyPress | ffi::XI_KeyRelease if !self.is_composing => {
|
|
||||||
if let Some(active_window) = self.active_window {
|
|
||||||
let state = if xev.evtype == ffi::XI_KeyPress {
|
|
||||||
Pressed
|
|
||||||
} else {
|
|
||||||
Released
|
|
||||||
};
|
|
||||||
|
|
||||||
let xkev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
|
||||||
|
|
||||||
// We use `self.active_window` here as `xkev.event` has a completely different
|
|
||||||
// value for some reason.
|
|
||||||
let window_id = mkwid(active_window);
|
|
||||||
|
|
||||||
let device_id = mkdid(xkev.deviceid);
|
|
||||||
let keycode = xkev.detail as u32;
|
|
||||||
|
|
||||||
let repeat = xkev.flags & ffi::XIKeyRepeat == ffi::XIKeyRepeat;
|
|
||||||
let event = self.kb_state.process_key_event(keycode, state, repeat);
|
|
||||||
|
|
||||||
callback(Event::WindowEvent {
|
|
||||||
window_id,
|
|
||||||
event: WindowEvent::KeyboardInput {
|
|
||||||
device_id,
|
|
||||||
event,
|
|
||||||
is_synthetic: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
||||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,15 @@ impl<T: 'static> EventLoop<T> {
|
||||||
panic!("X server missing XKB extension");
|
panic!("X server missing XKB extension");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable detectable auto repeat.
|
||||||
|
let mut supported = 0;
|
||||||
|
unsafe {
|
||||||
|
(xconn.xlib.XkbSetDetectableAutoRepeat)(xconn.display, 1, &mut supported);
|
||||||
|
}
|
||||||
|
if supported == 0 {
|
||||||
|
warn!("Detectable auto repeart is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
ext
|
ext
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -283,6 +292,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
first_touch: None,
|
first_touch: None,
|
||||||
active_window: None,
|
active_window: None,
|
||||||
is_composing: false,
|
is_composing: false,
|
||||||
|
got_key_release: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register for device hotplug events
|
// Register for device hotplug events
|
||||||
|
|
|
@ -245,6 +245,7 @@ impl UnownedWindow {
|
||||||
| ffi::StructureNotifyMask
|
| ffi::StructureNotifyMask
|
||||||
| ffi::VisibilityChangeMask
|
| ffi::VisibilityChangeMask
|
||||||
| ffi::KeyPressMask
|
| ffi::KeyPressMask
|
||||||
|
| ffi::KeyReleaseMask
|
||||||
| ffi::KeymapStateMask
|
| ffi::KeymapStateMask
|
||||||
| ffi::ButtonPressMask
|
| ffi::ButtonPressMask
|
||||||
| ffi::ButtonReleaseMask
|
| ffi::ButtonReleaseMask
|
||||||
|
@ -446,8 +447,6 @@ impl UnownedWindow {
|
||||||
let mask = ffi::XI_MotionMask
|
let mask = ffi::XI_MotionMask
|
||||||
| ffi::XI_ButtonPressMask
|
| ffi::XI_ButtonPressMask
|
||||||
| ffi::XI_ButtonReleaseMask
|
| ffi::XI_ButtonReleaseMask
|
||||||
| ffi::XI_KeyPressMask
|
|
||||||
| ffi::XI_KeyReleaseMask
|
|
||||||
| ffi::XI_EnterMask
|
| ffi::XI_EnterMask
|
||||||
| ffi::XI_LeaveMask
|
| ffi::XI_LeaveMask
|
||||||
| ffi::XI_FocusInMask
|
| ffi::XI_FocusInMask
|
||||||
|
|
|
@ -1074,6 +1074,7 @@ impl Window {
|
||||||
///
|
///
|
||||||
/// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are combined.
|
/// - **macOS:** IME must be enabled to receive text-input where dead-key sequences are combined.
|
||||||
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
/// - **iOS / Android / Web / Orbital:** Unsupported.
|
||||||
|
/// - **X11**: Enabling IME will disable dead keys reporting during compose.
|
||||||
///
|
///
|
||||||
/// [`Ime`]: crate::event::WindowEvent::Ime
|
/// [`Ime`]: crate::event::WindowEvent::Ime
|
||||||
/// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
|
/// [`KeyboardInput`]: crate::event::WindowEvent::KeyboardInput
|
||||||
|
|
Loading…
Add table
Reference in a new issue