wayland: keyboard: add input method v1 support

Unfortunately, it is still not possible to emit keys in KDE Plasma.
This commit is contained in:
Richard Acayan 2024-08-07 19:25:48 -04:00
parent 5ac0295e3a
commit cefc4ddc79
3 changed files with 112 additions and 27 deletions

View file

@ -15,6 +15,8 @@ use crate::wayland::wlr_layer_shell_unstable_v1::zwlr_layer_shell_v1;
use crate::wayland::wlr_layer_shell_unstable_v1::zwlr_layer_surface_v1;
use crate::wayland::fractional_scale_v1::wp_fractional_scale_manager_v1;
use crate::wayland::fractional_scale_v1::wp_fractional_scale_v1;
use crate::wayland::input_method_unstable_v1::zwp_input_method_context_v1;
use crate::wayland::input_method_unstable_v1::zwp_input_method_v1;
use crate::wayland::input_method_unstable_v2::zwp_input_method_manager_v2;
use crate::wayland::input_method_unstable_v2::zwp_input_method_v2;
use crate::wayland::viewporter::wp_viewporter;
@ -29,6 +31,7 @@ use wayland_client::Dispatch;
use wayland_client::Proxy;
use wayland_client::QueueHandle;
use wayland_client::WEnum;
use wayland_client::globals::BindError;
use wayland_client::globals::GlobalList;
use wayland_client::globals::GlobalListContents;
use wayland_client::protocol::wl_buffer;
@ -69,6 +72,9 @@ impl Dispatcher {
Err(_) => None,
};
let _: Result<zwp_input_method_v1::ZwpInputMethodV1, BindError>
= globals.bind(&queue, 1..=1, ());
let frac_scale_man = match globals.bind(&queue, 1..=1, ()) {
Ok(g) => Some(g),
Err(_) => None,
@ -422,6 +428,27 @@ impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ()> for Dispatcher {
}
}
impl Dispatch<zwp_input_method_context_v1::ZwpInputMethodContextV1, ()> for Dispatcher {
fn event(ctx: &mut Dispatcher,
_imc: &zwp_input_method_context_v1::ZwpInputMethodContextV1,
evt: zwp_input_method_context_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Dispatcher>)
{
match evt {
zwp_input_method_context_v1::Event::SurroundingText { .. } => (),
zwp_input_method_context_v1::Event::Reset => (),
zwp_input_method_context_v1::Event::ContentType { .. } => (),
zwp_input_method_context_v1::Event::CommitState { serial } => {
ctx.seat.keyboard_mut().set_serial(serial);
},
zwp_input_method_context_v1::Event::PreferredLanguage { .. } => (),
_ => eprintln!("warn: unknown zwp_input_method_context_v1 event emitted"),
}
}
}
impl Dispatch<zwp_input_method_manager_v2::ZwpInputMethodManagerV2, ()> for Dispatcher {
fn event(_ctx: &mut Dispatcher,
_im_man: &zwp_input_method_manager_v2::ZwpInputMethodManagerV2,
@ -434,6 +461,35 @@ impl Dispatch<zwp_input_method_manager_v2::ZwpInputMethodManagerV2, ()> for Disp
}
}
impl Dispatch<zwp_input_method_v1::ZwpInputMethodV1, ()> for Dispatcher {
fn event(ctx: &mut Dispatcher,
_im: &zwp_input_method_v1::ZwpInputMethodV1,
evt: zwp_input_method_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Dispatcher>)
{
match evt {
zwp_input_method_v1::Event::Activate { id } => {
ctx.seat.set_text_supported(true);
ctx.seat.keyboard_mut().set_input_method_context(Some(id));
ctx.show();
},
zwp_input_method_v1::Event::Deactivate { .. } => {
ctx.seat.set_text_supported(false);
ctx.seat.keyboard_mut().set_input_method_context(None);
ctx.hide();
},
_ => eprintln!("warn: unknown zwp_input_method_v1 event emitted"),
}
}
wayland_client::event_created_child!(Dispatcher, zwp_input_method_v1::ZwpInputMethodV1, [
zwp_input_method_v1::EVT_ACTIVATE_OPCODE
=> (zwp_input_method_context_v1::ZwpInputMethodContextV1, ()),
]);
}
impl Dispatch<zwp_input_method_v2::ZwpInputMethodV2, ()> for Dispatcher {
fn event(ctx: &mut Dispatcher,
_im: &zwp_input_method_v2::ZwpInputMethodV2,

View file

@ -6,6 +6,7 @@
use crate::core::Keyboard;
use crate::core::Layout;
use crate::core::Part;
use crate::wayland::input_method_unstable_v1::zwp_input_method_context_v1::ZwpInputMethodContextV1;
use crate::wayland::input_method_unstable_v2::zwp_input_method_manager_v2::ZwpInputMethodManagerV2;
use crate::wayland::input_method_unstable_v2::zwp_input_method_v2::ZwpInputMethodV2;
use crate::wayland::virtual_keyboard_unstable_v1::zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1;
@ -29,6 +30,7 @@ pub struct VirtualKeyboard {
keymap_id: u8,
im: Option<ZwpInputMethodV2>,
im_ctx: Option<ZwpInputMethodContextV1>,
im_serial: u32,
keycodes: HashMap<Keysym, u8>,
@ -46,7 +48,7 @@ impl VirtualKeyboard {
-> VirtualKeyboard
{
let vk = vk_man.as_ref().map(|m| m.create_virtual_keyboard(seat, queue, ()));
let im = im_man.as_ref().map(|m| m.get_input_method(&seat, &queue, ()));
let im = im_man.as_ref().map(|m| m.get_input_method(seat, queue, ()));
let path = format!("/tmp/ufkbd-keymap-pid{}-1", process::id());
let keymap = File::create(path).unwrap();
@ -57,6 +59,7 @@ impl VirtualKeyboard {
keymap_id: 1,
im,
im_ctx: None,
im_serial: 0,
keycodes: HashMap::with_capacity(248),
@ -93,25 +96,33 @@ impl VirtualKeyboard {
{
self.im_serial += 1;
}
pub fn set_serial(&mut self, serial: u32)
{
self.im_serial = serial;
}
pub fn set_input_method_context(&mut self, imc: Option<ZwpInputMethodContextV1>)
{
self.im_ctx = imc;
}
}
impl Keyboard for VirtualKeyboard {
fn key_supported(&self, sym: Keysym) -> bool
{
if self.vk.is_none() {
return false;
}
match sym.name() {
Some(n) => n.starts_with("XK_"),
None => false,
if self.vk.is_some() {
match sym.name() {
Some(n) => n.starts_with("XK_"),
None => false,
}
} else {
self.im_ctx.is_some()
}
}
fn press(&mut self, sym: Keysym)
{
let vk = self.vk.as_ref().unwrap();
if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn {
return;
}
@ -119,28 +130,33 @@ impl Keyboard for VirtualKeyboard {
match sym {
Keysym::Shift_L => {
self.mod_state |= 0x1;
vk.modifiers(self.mod_state, 0, 0, 0);
},
Keysym::Control_L => {
self.mod_state |= 0x4;
vk.modifiers(self.mod_state, 0, 0, 0);
},
Keysym::Alt_L => {
self.mod_state |= 0x8;
vk.modifiers(self.mod_state, 0, 0, 0);
},
_ => (),
}
let keycode = *self.keycodes.get(&sym).unwrap();
self.pressed[keycode as usize] = sym;
vk.key(0, keycode as u32, 1);
if let Some(vk) = &self.vk {
if sym == Keysym::Shift_L
|| sym == Keysym::Control_L
|| sym == Keysym::Alt_L {
vk.modifiers(self.mod_state, 0, 0, 0);
}
let keycode = *self.keycodes.get(&sym).unwrap();
self.pressed[keycode as usize] = sym;
vk.key(0, keycode as u32, 1);
} else if let Some(imc) = &self.im_ctx {
imc.keysym(self.im_serial, 0, sym.raw(), 0, self.mod_state);
}
}
fn release(&mut self, sym: Keysym)
{
let vk = self.vk.as_ref().unwrap();
if sym == Keysym::NoSymbol || sym == Keysym::XF86_Fn {
return;
}
@ -148,29 +164,41 @@ impl Keyboard for VirtualKeyboard {
match sym {
Keysym::Shift_L => {
self.mod_state &= !0x1;
vk.modifiers(self.mod_state, 0, 0, 0);
},
Keysym::Control_L => {
self.mod_state &= !0x4;
vk.modifiers(self.mod_state, 0, 0, 0);
},
Keysym::Alt_L => {
self.mod_state &= !0x8;
vk.modifiers(self.mod_state, 0, 0, 0);
},
_ => (),
}
let keycode = *self.keycodes.get(&sym).unwrap();
self.pressed[keycode as usize] = Keysym::NoSymbol;
vk.key(0, keycode as u32, 0);
if let Some(vk) = &self.vk {
if sym == Keysym::Shift_L
|| sym == Keysym::Control_L
|| sym == Keysym::Alt_L {
vk.modifiers(self.mod_state, 0, 0, 0);
}
let keycode = *self.keycodes.get(&sym).unwrap();
self.pressed[keycode as usize] = Keysym::NoSymbol;
vk.key(0, keycode as u32, 0);
} else if let Some(imc) = &self.im_ctx {
imc.keysym(self.im_serial, 0, sym.raw(), 0, self.mod_state);
}
}
fn text(&mut self, text: &str)
{
let im = self.im.as_ref().unwrap();
im.commit_string(text.to_string());
im.commit(self.im_serial);
if let Some(im) = &self.im {
im.commit_string(text.to_string());
im.commit(self.im_serial);
} else if let Some(imc) = &self.im_ctx {
imc.commit_string(self.im_serial, text.to_string());
} else {
panic!("Text should not be emitted without an input method protocol");
}
}
fn change_layout(&mut self, layout: &Layout)

View file

@ -18,6 +18,7 @@ pub use self::surface::Surface;
pub use wayland_protocols_wlr::layer_shell::v1::client as wlr_layer_shell_unstable_v1;
pub use wayland_protocols::wp::fractional_scale::v1::client as fractional_scale_v1;
pub use wayland_protocols::wp::input_method::zv1::client as input_method_unstable_v1;
pub use wayland_protocols::wp::text_input::zv3::client as text_input_unstable_v3;
pub use wayland_protocols::wp::viewporter::client as viewporter;