feat(wayland): keyboard support

This commit is contained in:
Nova
2022-09-13 06:46:30 -04:00
parent 507ea4a850
commit 9987e5eb08
5 changed files with 145 additions and 65 deletions

View File

@@ -26,6 +26,7 @@ send_wrapper = "0.6.0"
prisma = "0.1.1"
slog = "2.7.0"
slog-stdlog = "4.1.1"
xkbcommon = { version = "0.5.0", default-features = false }
[dependencies.libstardustxr]
path = "../libstardustxr-rs"
@@ -37,4 +38,5 @@ default-features = false
features = ["linux-egl"]
[dependencies.smithay]
git = "https://github.com/Smithay/smithay.git"
# git = "https://github.com/Smithay/smithay.git"
path = "../smithay"

View File

@@ -91,8 +91,7 @@ impl Wayland {
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
GLOBAL_DESTROY_QUEUE.set(global_destroy_queue_in).unwrap();
let join_handle =
Wayland::start_loop(display.clone(), state.clone(), global_destroy_queue)?;
let join_handle = Wayland::start_loop(display.clone(), state, global_destroy_queue)?;
Ok(Wayland {
log,

View File

@@ -1,4 +1,7 @@
use super::{seat::SeatData, surface::CoreSurface};
use super::{
seat::{KeyboardInfo, SeatData},
surface::CoreSurface,
};
use crate::{
core::{
client::{Client, INTERNAL_CLIENT},
@@ -20,18 +23,13 @@ use libstardustxr::{
use nanoid::nanoid;
use smithay::{
reexports::wayland_server::{
protocol::{
wl_keyboard::KeyState,
wl_pointer::{Axis, ButtonState},
},
protocol::wl_pointer::{Axis, ButtonState},
Resource,
},
wayland::{compositor::SurfaceData, shell::xdg::XdgToplevelSurfaceData},
};
use std::{
convert::TryInto,
sync::{Arc, Weak},
};
use std::sync::{Arc, Weak};
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
lazy_static! {
static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
@@ -97,15 +95,16 @@ impl PanelItem {
node.add_local_signal("pointerScroll", PanelItem::pointer_scroll_flex);
node.add_local_signal("pointerButton", PanelItem::pointer_button_flex);
node.add_local_signal("pointerMotion", PanelItem::pointer_motion_flex);
node.add_local_signal("keyboardSetActive", PanelItem::keyboard_set_active_flex);
node.add_local_signal(
"keyboardSetKeyState",
PanelItem::keyboard_set_key_state_flex,
"keyboardActivateString",
PanelItem::keyboard_activate_string_flex,
);
node.add_local_signal(
"keyboardSetModifiers",
PanelItem::keyboard_set_modifiers_flex,
"keyboardActivateNames",
PanelItem::keyboard_activate_names_flex,
);
node.add_local_signal("keyboardDeactivate", PanelItem::keyboard_deactivate_flex);
node.add_local_signal("keyboardKeyState", PanelItem::keyboard_key_state_flex);
node
}
@@ -360,23 +359,83 @@ impl PanelItem {
Ok(())
}
fn keyboard_set_active_flex(
fn keyboard_activate_string_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let keymap_str = flexbuffers::Reader::get_root(data)?.get_str()?;
let context = xkb::Context::new(0);
let keymap = Keymap::new_from_string(
&context,
keymap_str.to_string(),
XKB_KEYMAP_FORMAT_TEXT_V1,
0,
)
.ok_or_else(|| anyhow!("Keymap is not valid"))?;
PanelItem::keyboard_activate_flex(node, &keymap)
}
fn keyboard_activate_names_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let rules = flex_vec.idx(0).as_str();
let model = flex_vec.idx(1).as_str();
let layout = flex_vec.idx(2).as_str();
let variant = flex_vec.idx(3).as_str();
let options = match flex_vec.index(4).ok() {
Some(options) => Some(options.get_str()?.to_string()),
None => None,
};
let context = xkb::Context::new(0);
let keymap = Keymap::new_from_names(
&context,
rules,
model,
layout,
variant,
options,
XKB_KEYMAP_FORMAT_TEXT_V1,
)
.ok_or_else(|| anyhow!("Keymap is not valid"))?;
PanelItem::keyboard_activate_flex(node, &keymap)
}
fn keyboard_activate_flex(node: &Node, keymap: &Keymap) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(keyboard) = panel_item.seat_data.keyboard() {
if let Some(core_surface) = panel_item.core_surface.upgrade() {
let mut keyboard_active = panel_item.seat_data.keyboard_active.lock();
let active = flexbuffers::Reader::get_root(data)?.get_bool()?;
if *keyboard_active != active {
if active {
keyboard.enter(0, &core_surface.wl_surface(), vec![]);
} else {
keyboard.leave(0, &core_surface.wl_surface());
}
*keyboard_active = active;
let mut keyboard_info = panel_item.seat_data.keyboard_info.lock();
if keyboard_info.is_none() {
keyboard.enter(0, &core_surface.wl_surface(), vec![]);
keyboard.repeat_info(0, 0);
}
keyboard_info.replace(KeyboardInfo::new(keymap));
keyboard_info.as_ref().unwrap().keymap.send(keyboard)?;
}
}
}
Ok(())
}
fn keyboard_deactivate_flex(
node: &Node,
_calling_client: Arc<Client>,
_data: &[u8],
) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(keyboard) = panel_item.seat_data.keyboard() {
if let Some(core_surface) = panel_item.core_surface.upgrade() {
let mut keyboard_info = panel_item.seat_data.keyboard_info.lock();
if keyboard_info.is_some() {
keyboard.leave(0, &core_surface.wl_surface());
*keyboard_info = None;
}
}
}
@@ -385,45 +444,19 @@ impl PanelItem {
Ok(())
}
fn keyboard_set_key_state_flex(
fn keyboard_key_state_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(keyboard) = panel_item.seat_data.keyboard() {
let active = *panel_item.seat_data.keyboard_active.lock();
if active {
let mut keyboard_info = panel_item.seat_data.keyboard_info.lock();
if let Some(keyboard_info) = &mut *keyboard_info {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
let key = flex_vec.index(0)?.get_u64()? as u32;
let state: KeyState = (flex_vec.index(1)?.as_u64() as u32)
.try_into()
.map_err(|_| anyhow!("Invalid key state"))?;
keyboard.key(0, 0, key, state);
}
}
}
Ok(())
}
fn keyboard_set_modifiers_flex(
node: &Node,
_calling_client: Arc<Client>,
data: &[u8],
) -> Result<()> {
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
if let Some(keyboard) = panel_item.seat_data.keyboard() {
let active = *panel_item.seat_data.keyboard_active.lock();
if active {
let flex_vec = flexbuffers::Reader::get_root(data)?.get_vector()?;
keyboard.modifiers(
0,
flex_vec.index(0)?.get_u64()? as u32,
flex_vec.index(1)?.get_u64()? as u32,
flex_vec.index(2)?.get_u64()? as u32,
flex_vec.index(3)?.get_u64()? as u32,
);
let state = flex_vec.index(1)?.get_u64()? as u32;
keyboard_info.process(key, state, &keyboard)?;
}
}
}

View File

@@ -1,15 +1,17 @@
use super::{state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE};
use crate::nodes::item::Item;
use anyhow::Result;
use mint::Vector2;
use nanoid::nanoid;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use smithay::{
input::keyboard::{KeymapFile, ModifiersState},
reexports::wayland_server::{
backend::{ClientId, GlobalId},
delegate_dispatch, delegate_global_dispatch,
protocol::{
wl_keyboard::{self, WlKeyboard},
wl_keyboard::{self, KeyState, WlKeyboard},
wl_pointer::{self, WlPointer},
wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE},
wl_touch::{self, WlTouch},
@@ -20,12 +22,54 @@ use smithay::{
};
use std::sync::Arc;
use std::{ops::Deref, sync::Weak};
use xkbcommon::xkb::{self, Keymap};
pub struct Cursor {
pub core_surface: Weak<CoreSurface>,
pub hotspot: Vector2<i32>,
}
pub struct KeyboardInfo {
pub keymap: KeymapFile,
pub state: xkb::State,
pub mods: ModifiersState,
}
impl KeyboardInfo {
pub fn new(keymap: &Keymap) -> Self {
KeyboardInfo {
state: xkb::State::new(keymap),
keymap: KeymapFile::new(keymap, None),
mods: ModifiersState::default(),
}
}
pub fn process(&mut self, key: u32, state: u32, keyboard: &WlKeyboard) -> Result<()> {
let wl_state = match state {
0 => KeyState::Released,
1 => KeyState::Pressed,
_ => anyhow::bail!("Invalid key state!"),
};
let xkb_state = match state {
0 => xkb::KeyDirection::Up,
1 => xkb::KeyDirection::Down,
_ => anyhow::bail!("Invalid key state!"),
};
let state_components = self.state.update_key(key, xkb_state);
if state_components != 0 {
self.mods.update_with(&self.state);
keyboard.modifiers(
0,
self.mods.serialized.depressed,
self.mods.serialized.latched,
self.mods.serialized.locked,
0,
);
}
keyboard.key(0, 0, key, wl_state);
Ok(())
}
}
unsafe impl Send for KeyboardInfo {}
pub struct SeatDelegate;
#[derive(Clone)]
@@ -41,7 +85,7 @@ impl SeatData {
pointer: OnceCell::new(),
pointer_active: Mutex::new(false),
keyboard: OnceCell::new(),
keyboard_active: Mutex::new(false),
keyboard_info: Mutex::new(None),
touch: OnceCell::new(),
}));
@@ -70,7 +114,7 @@ pub struct SeatDataInner {
pointer: OnceCell<WlPointer>,
pub pointer_active: Mutex<bool>,
keyboard: OnceCell<WlKeyboard>,
pub keyboard_active: Mutex<bool>,
pub keyboard_info: Mutex<Option<KeyboardInfo>>,
touch: OnceCell<WlTouch>,
}
impl SeatDataInner {
@@ -130,7 +174,9 @@ impl Dispatch<WlSeat, SeatData, WaylandState> for SeatDelegate {
let _ = data.0.pointer.set(data_init.init(id, data.clone()));
}
wl_seat::Request::GetKeyboard { id } => {
let _ = data.0.keyboard.set(data_init.init(id, data.clone()));
let keyboard = data_init.init(id, data.clone());
keyboard.repeat_info(0, 0);
let _ = data.0.keyboard.set(keyboard);
}
wl_seat::Request::GetTouch { id } => {
let _ = data.0.touch.set(data_init.init(id, data.clone()));

View File

@@ -4,16 +4,16 @@ use parking_lot::Mutex;
use slog::Logger;
use smithay::{
delegate_output, delegate_shm,
output::{Output, Scale, Subpixel},
reexports::wayland_server::{
backend::{ClientData, ClientId, DisconnectReason},
protocol::wl_output::Subpixel,
Display, DisplayHandle,
},
utils::Size,
wayland::{
buffer::BufferHandler,
compositor::CompositorState,
output::{Output, OutputManagerState, Scale},
output::OutputManagerState,
shell::xdg::{decoration::XdgDecorationState, XdgShellState},
shm::{ShmHandler, ShmState},
},
@@ -62,7 +62,7 @@ impl WaylandState {
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
let output = Output::new(
"1x".to_owned(),
smithay::wayland::output::PhysicalProperties {
smithay::output::PhysicalProperties {
size: Size::default(),
subpixel: Subpixel::None,
make: "Virtual XR Display".to_owned(),