autocommit 2022-01-06 19:08:32 CET
This commit is contained in:
parent
cbbc41a463
commit
4a939477a2
51 changed files with 3438 additions and 207 deletions
43
src/xkbcommon/consts.rs
Normal file
43
src/xkbcommon/consts.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
cenum! {
|
||||
XkbX11SetupXkbExtensionFlags, XKB_X11_SETUP_XKB_EXTENSION_FLAGS;
|
||||
|
||||
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS = 0,
|
||||
}
|
||||
|
||||
bitor!(XkbX11SetupXkbExtensionFlags);
|
||||
|
||||
cenum! {
|
||||
XkbLogLevel, XKB_LOG_LEVEL;
|
||||
|
||||
XKB_LOG_LEVEL_CRITICAL = 10,
|
||||
XKB_LOG_LEVEL_ERROR = 20,
|
||||
XKB_LOG_LEVEL_WARNING = 30,
|
||||
XKB_LOG_LEVEL_INFO = 40,
|
||||
XKB_LOG_LEVEL_DEBUG = 50,
|
||||
}
|
||||
|
||||
cenum! {
|
||||
XkbContextFlags, XKB_CONTEXT_FLAGS;
|
||||
|
||||
XKB_CONTEXT_NO_FLAGS = 0,
|
||||
XKB_CONTEXT_NO_DEFAULT_INCLUDES = 1 << 0,
|
||||
XKB_CONTEXT_NO_ENVIRONMENT_NAMES = 1 << 1,
|
||||
}
|
||||
|
||||
bitor!(XkbContextFlags);
|
||||
|
||||
cenum! {
|
||||
XkbKeymapCompileFlags, XKB_KEYMAP_COMPILE_FLAGS;
|
||||
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS = 0,
|
||||
}
|
||||
|
||||
bitor!(XkbKeymapCompileFlags);
|
||||
|
||||
cenum! {
|
||||
XkbKeymapFormat, XKB_KEYMAP_FORMAT;
|
||||
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1 = 1,
|
||||
}
|
||||
249
src/xkbcommon/mod.rs
Normal file
249
src/xkbcommon/mod.rs
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
|
||||
mod consts;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/xkbcommon_tys.rs"));
|
||||
|
||||
use bstr::{BStr, ByteSlice};
|
||||
pub use consts::*;
|
||||
use std::ffi::{CStr, VaList};
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
|
||||
use crate::utils::ptr_ext::PtrExt;
|
||||
use libloading::Library;
|
||||
use thiserror::Error;
|
||||
use uapi::c;
|
||||
use xcb_dl::ffi::xcb_connection_t;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum XkbCommonError {
|
||||
#[error("xkbcommon-x11 could not be loaded")]
|
||||
LoadXkbCommonX11(#[source] libloading::Error),
|
||||
#[error("One of the xkbcommon-x11 symbols could not be loaded")]
|
||||
LoadXkbCommonX11Sym(#[source] libloading::Error),
|
||||
#[error("Could not create keymap from X11 device")]
|
||||
CreateKeymapFromDevice,
|
||||
#[error("Could not create state from X11 device")]
|
||||
CreateStateFromDevice,
|
||||
#[error("Could not create an xkbcommon context")]
|
||||
CreateContext,
|
||||
#[error("Could not convert the keymap to a string")]
|
||||
AsStr,
|
||||
}
|
||||
|
||||
struct xkb_context;
|
||||
struct xkb_keymap;
|
||||
struct xkb_state;
|
||||
|
||||
#[link(name = "xkbcommon")]
|
||||
extern "C" {
|
||||
fn xkb_context_new(flags: xkb_context_flags) -> *mut xkb_context;
|
||||
fn xkb_context_unref(context: *mut xkb_context);
|
||||
fn xkb_context_set_log_fn(
|
||||
context: *mut xkb_context,
|
||||
log_fn: unsafe extern "C" fn(
|
||||
context: *mut xkb_context,
|
||||
level: xkb_log_level,
|
||||
format: *const c::c_char,
|
||||
args: VaList,
|
||||
),
|
||||
);
|
||||
fn xkb_keymap_get_as_string(
|
||||
keymap: *mut xkb_keymap,
|
||||
format: xkb_keymap_format,
|
||||
) -> *mut c::c_char;
|
||||
fn xkb_keymap_unref(keymap: *mut xkb_keymap);
|
||||
fn xkb_state_unref(state: *mut xkb_state);
|
||||
}
|
||||
|
||||
pub struct XkbContext {
|
||||
context: *mut xkb_context,
|
||||
}
|
||||
|
||||
impl XkbContext {
|
||||
pub fn new() -> Result<Self, XkbCommonError> {
|
||||
let res = unsafe { xkb_context_new(XKB_CONTEXT_NO_FLAGS.raw() as _) };
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::CreateContext);
|
||||
}
|
||||
unsafe {
|
||||
xkb_context_set_log_fn(res, xkbcommon_logger);
|
||||
}
|
||||
Ok(Self { context: res })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for XkbContext {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
xkb_context_unref(self.context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XkbKeymap {
|
||||
keymap: *mut xkb_keymap,
|
||||
}
|
||||
|
||||
impl XkbKeymap {
|
||||
pub fn as_str(&self) -> Result<XkbKeymapStr, XkbCommonError> {
|
||||
let res =
|
||||
unsafe { xkb_keymap_get_as_string(self.keymap, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) };
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::AsStr);
|
||||
}
|
||||
Ok(XkbKeymapStr {
|
||||
s: unsafe { CStr::from_ptr(res).to_bytes().as_bstr() },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for XkbKeymap {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
xkb_keymap_unref(self.keymap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XkbKeymapStr {
|
||||
s: *const BStr,
|
||||
}
|
||||
|
||||
impl Deref for XkbKeymapStr {
|
||||
type Target = BStr;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { self.s.deref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for XkbKeymapStr {
|
||||
fn drop(&mut self) {
|
||||
unsafe { c::free(self.s as _) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XkbState {
|
||||
state: *mut xkb_state,
|
||||
}
|
||||
|
||||
impl Drop for XkbState {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
xkb_state_unref(self.state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct XkbCommonX11 {
|
||||
library: Library,
|
||||
fns: XkbCommonX11Fns,
|
||||
}
|
||||
|
||||
struct XkbCommonX11Fns {
|
||||
xkb_x11_keymap_new_from_device: unsafe fn(
|
||||
context: *mut xkb_context,
|
||||
c: *mut xcb_connection_t,
|
||||
device_id: i32,
|
||||
flags: xkb_x11_setup_xkb_extension_flags,
|
||||
) -> *mut xkb_keymap,
|
||||
xkb_x11_state_new_from_device: unsafe fn(
|
||||
keymap: *mut xkb_keymap,
|
||||
c: *mut xcb_connection_t,
|
||||
device_id: i32,
|
||||
) -> *mut xkb_state,
|
||||
}
|
||||
|
||||
impl XkbCommonX11 {
|
||||
pub fn load() -> Result<Self, XkbCommonError> {
|
||||
let library = unsafe {
|
||||
match Library::new("libxkbcommon-x11.so") {
|
||||
Ok(l) => l,
|
||||
Err(e) => return Err(XkbCommonError::LoadXkbCommonX11(e)),
|
||||
}
|
||||
};
|
||||
let fns = match get_xkbcommon_x11_fns(&library) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(XkbCommonError::LoadXkbCommonX11Sym(e)),
|
||||
};
|
||||
Ok(Self { library, fns })
|
||||
}
|
||||
|
||||
pub unsafe fn keymap_from_device(
|
||||
&self,
|
||||
context: &XkbContext,
|
||||
c: *mut xcb_connection_t,
|
||||
device_id: i32,
|
||||
flags: XkbX11SetupXkbExtensionFlags,
|
||||
) -> Result<XkbKeymap, XkbCommonError> {
|
||||
let res = (self.fns.xkb_x11_keymap_new_from_device)(
|
||||
context.context,
|
||||
c,
|
||||
device_id,
|
||||
flags.raw() as _,
|
||||
);
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::CreateKeymapFromDevice);
|
||||
}
|
||||
Ok(XkbKeymap { keymap: res })
|
||||
}
|
||||
|
||||
pub unsafe fn state_from_device(
|
||||
&self,
|
||||
keymap: &XkbKeymap,
|
||||
c: *mut xcb_connection_t,
|
||||
device_id: i32,
|
||||
) -> Result<XkbState, XkbCommonError> {
|
||||
let res = (self.fns.xkb_x11_state_new_from_device)(keymap.keymap, c, device_id);
|
||||
if res.is_null() {
|
||||
return Err(XkbCommonError::CreateStateFromDevice);
|
||||
}
|
||||
Ok(XkbState { state: res })
|
||||
}
|
||||
}
|
||||
|
||||
fn get_xkbcommon_x11_fns(lib: &Library) -> Result<XkbCommonX11Fns, libloading::Error> {
|
||||
macro_rules! syms {
|
||||
($($sym:ident,)*) => {
|
||||
Ok(XkbCommonX11Fns {
|
||||
$(
|
||||
$sym: std::mem::transmute(lib.get::<usize>(concat!(stringify!($sym), "\0").as_bytes())?.into_raw().into_raw()),
|
||||
)*
|
||||
})
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
syms! {
|
||||
xkb_x11_keymap_new_from_device,
|
||||
xkb_x11_state_new_from_device,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "C" fn xkbcommon_logger(
|
||||
_ctx: *mut xkb_context,
|
||||
level: xkb_log_level,
|
||||
format: *const c::c_char,
|
||||
args: VaList,
|
||||
) {
|
||||
extern "C" {
|
||||
fn vasprintf(buf: *mut *mut c::c_char, fmt: *const c::c_char, args: VaList) -> c::c_int;
|
||||
}
|
||||
let mut buf = ptr::null_mut();
|
||||
let res = vasprintf(&mut buf, format, args);
|
||||
if res < 0 {
|
||||
log::warn!("Could not vasprintf");
|
||||
}
|
||||
let buf = std::slice::from_raw_parts(buf as *const u8, res as usize);
|
||||
let buf = buf.as_bstr();
|
||||
let level = match XkbLogLevel(level) {
|
||||
XKB_LOG_LEVEL_CRITICAL | XKB_LOG_LEVEL_ERROR => log::Level::Error,
|
||||
XKB_LOG_LEVEL_WARNING => log::Level::Warn,
|
||||
XKB_LOG_LEVEL_INFO => log::Level::Info,
|
||||
XKB_LOG_LEVEL_DEBUG => log::Level::Debug,
|
||||
_ => log::Level::Error,
|
||||
};
|
||||
log::log!(level, "xkbcommon: {}", buf);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue