Merge branch 'x11_prepare' into 'master'

Cleanups leading to Xwayland compatibility

See merge request Librem5/squeekboard!389
This commit is contained in:
Guido Gunther
2020-10-12 12:45:13 +00:00
7 changed files with 106 additions and 47 deletions

View File

@ -28,33 +28,24 @@
#include <sys/random.h> // TODO: this is Linux-specific #include <sys/random.h> // TODO: this is Linux-specific
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include "eek-keyboard.h" #include "eek-keyboard.h"
void level_keyboard_free(LevelKeyboard *self) {
xkb_keymap_unref(self->keymap); static void eek_key_map_deinit(struct keymap *self) {
close(self->keymap_fd); if (self->fd < 0) {
squeek_layout_free(self->layout); g_error("Deinit called multiple times on KeyMap");
g_free(self); } else {
close(self->fd);
}
self->fd = -1;
} }
LevelKeyboard* static struct keymap eek_key_map_from_str(const char *keymap_str) {
level_keyboard_new (struct squeek_layout *layout)
{
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
if (!keyboard) {
g_error("Failed to create a keyboard");
}
keyboard->layout = layout;
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!context) { if (!context) {
g_error("No context created"); g_error("No context created");
} }
const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str, struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
@ -62,10 +53,9 @@ level_keyboard_new (struct squeek_layout *layout)
g_error("Bad keymap:\n%s", keymap_str); g_error("Bad keymap:\n%s", keymap_str);
xkb_context_unref(context); xkb_context_unref(context);
keyboard->keymap = keymap;
char *xkb_keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1); char *xkb_keymap_str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
keyboard->keymap_len = strlen(xkb_keymap_str) + 1; size_t keymap_len = strlen(xkb_keymap_str) + 1;
g_autofree char *path = strdup("/eek_keymap-XXXXXX"); g_autofree char *path = strdup("/eek_keymap-XXXXXX");
char *r = &path[strlen(path) - 6]; char *r = &path[strlen(path) - 6];
@ -79,18 +69,42 @@ level_keyboard_new (struct squeek_layout *layout)
if (keymap_fd < 0) { if (keymap_fd < 0) {
g_error("Failed to set up keymap fd"); g_error("Failed to set up keymap fd");
} }
keyboard->keymap_fd = keymap_fd;
shm_unlink(path); shm_unlink(path);
if (ftruncate(keymap_fd, (off_t)keyboard->keymap_len)) { if (ftruncate(keymap_fd, (off_t)keymap_len)) {
g_error("Failed to increase keymap fd size"); g_error("Failed to increase keymap fd size");
} }
char *ptr = mmap(NULL, keyboard->keymap_len, PROT_WRITE, MAP_SHARED, char *ptr = mmap(NULL, keymap_len, PROT_WRITE, MAP_SHARED,
keymap_fd, 0); keymap_fd, 0);
if ((void*)ptr == (void*)-1) { if ((void*)ptr == (void*)-1) {
g_error("Failed to set up mmap"); g_error("Failed to set up mmap");
} }
strncpy(ptr, xkb_keymap_str, keyboard->keymap_len); strncpy(ptr, xkb_keymap_str, keymap_len);
munmap(ptr, keymap_len);
free(xkb_keymap_str); free(xkb_keymap_str);
munmap(ptr, keyboard->keymap_len); xkb_keymap_unref(keymap);
struct keymap km = {
.fd = keymap_fd,
.fd_len = keymap_len,
};
return km;
}
void level_keyboard_free(LevelKeyboard *self) {
eek_key_map_deinit(&self->keymap);
squeek_layout_free(self->layout);
g_free(self);
}
LevelKeyboard*
level_keyboard_new (struct squeek_layout *layout)
{
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
if (!keyboard) {
g_error("Failed to create a keyboard");
}
keyboard->layout = layout;
const gchar *keymap_str = squeek_layout_get_keymap(keyboard->layout);
keyboard->keymap = eek_key_map_from_str(keymap_str);
return keyboard; return keyboard;
} }

View File

@ -32,19 +32,20 @@
G_BEGIN_DECLS G_BEGIN_DECLS
/// Keymap container for Rust interoperability.
struct keymap {
uint32_t fd; // keymap formatted as XKB string
size_t fd_len; // length of the data inside keymap_fd
};
/// Keyboard state holder /// Keyboard state holder
struct _LevelKeyboard { struct _LevelKeyboard {
struct squeek_layout *layout; // owned struct squeek_layout *layout; // owned
struct xkb_keymap *keymap; // owned struct keymap keymap; // owned
int keymap_fd; // keymap formatted as XKB string
size_t keymap_len; // length of the data inside keymap_fd
guint id; // as a key to layout choices
}; };
typedef struct _LevelKeyboard LevelKeyboard; typedef struct _LevelKeyboard LevelKeyboard;
gchar * eek_keyboard_get_keymap gchar *eek_keyboard_get_keymap(LevelKeyboard *keyboard);
(LevelKeyboard *keyboard);
LevelKeyboard* LevelKeyboard*
level_keyboard_new (struct squeek_layout *layout); level_keyboard_new (struct squeek_layout *layout);

View File

@ -5,6 +5,7 @@ use std::env;
fn main() -> () { fn main() -> () {
check_builtin_layout( check_builtin_layout(
env::args().nth(1).expect("No argument given").as_str() env::args().nth(1).expect("No argument given").as_str(),
env::args().nth(2).map(|s| s == "allow_missing_return").unwrap_or(false),
); );
} }

View File

@ -26,17 +26,45 @@ impl CountAndPrint {
} }
} }
pub fn check_builtin_layout(name: &str) { pub fn check_builtin_layout(name: &str, missing_return: bool) {
check_layout(Layout::from_resource(name).expect("Invalid layout data")) check_layout(
Layout::from_resource(name).expect("Invalid layout data"),
missing_return,
)
} }
pub fn check_layout_file(path: &str) { pub fn check_layout_file(path: &str) {
check_layout(Layout::from_file(path.into()).expect("Invalid layout file")) check_layout(
Layout::from_file(path.into()).expect("Invalid layout file"),
false,
)
} }
fn check_layout(layout: Layout) { fn check_sym_presence(
state: &xkb::State,
sym_name: &str,
handler: &mut dyn logging::Handler,
) {
let sym = xkb::keysym_from_name(sym_name, xkb::KEYSYM_NO_FLAGS);
if sym == xkb::KEY_NoSymbol {
panic!(format!("Entered invalid keysym: {}", sym_name));
}
let map = state.get_keymap();
let range = map.min_keycode()..=map.max_keycode();
let found = range.flat_map(|code| state.key_get_syms(code))
.find(|s| **s == sym)
.is_some();
if !found {
handler.handle(
logging::Level::Surprise,
&format!("There's no way to input the keysym {} on this layout", sym_name),
)
}
}
fn check_layout(layout: Layout, allow_missing_return: bool) {
let handler = CountAndPrint::new(); let handler = CountAndPrint::new();
let (layout, handler) = layout.build(handler); let (layout, mut handler) = layout.build(handler);
if handler.0 > 0 { if handler.0 > 0 {
println!("{} problems while parsing layout", handler.0) println!("{} problems while parsing layout", handler.0)
@ -59,6 +87,15 @@ fn check_layout(layout: Layout) {
let state = xkb::State::new(&keymap); let state = xkb::State::new(&keymap);
check_sym_presence(&state, "BackSpace", &mut handler);
let mut printer = logging::Print;
check_sym_presence(
&state,
"Return",
if allow_missing_return { &mut printer }
else { &mut handler },
);
// "Press" each button with keysyms // "Press" each button with keysyms
for (_pos, view) in layout.views.values() { for (_pos, view) in layout.views.values() {
for (_y, row) in view.get_rows() { for (_y, row) in view.get_rows() {

View File

@ -41,7 +41,7 @@ impl VirtualKeyboard {
// TODO: error out if keymap not set // TODO: error out if keymap not set
pub fn switch( pub fn switch(
&self, &self,
keycodes: &Vec<KeyCode>, keycodes: &[KeyCode],
action: PressType, action: PressType,
timestamp: Timestamp, timestamp: Timestamp,
) { ) {

View File

@ -17,7 +17,7 @@ eek_virtual_keyboard_v1_key(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard
void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, const LevelKeyboard *keyboard) { void eek_virtual_keyboard_update_keymap(struct zwp_virtual_keyboard_v1 *zwp_virtual_keyboard_v1, const LevelKeyboard *keyboard) {
zwp_virtual_keyboard_v1_keymap(zwp_virtual_keyboard_v1, zwp_virtual_keyboard_v1_keymap(zwp_virtual_keyboard_v1,
WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
keyboard->keymap_fd, keyboard->keymap_len); keyboard->keymap.fd, keyboard->keymap.fd_len);
} }
void void

View File

@ -69,11 +69,17 @@ foreach layout : [
'emoji', 'emoji',
] ]
extra = []
if layout == 'emoji'
extra += ['allow_missing_return']
endif
test( test(
'test_layout_' + layout, 'test_layout_' + layout,
cargo_script, cargo_script,
args: ['run'] + cargo_build_flags args: ['run'] + cargo_build_flags
+ [ '--example', 'test_layout', '--', layout], + ['--example', 'test_layout', '--', layout]
+ extra,
workdir: meson.build_root(), workdir: meson.build_root(),
) )
endforeach endforeach