170 lines
3.5 KiB
C
170 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-3.0-only
|
|
/*
|
|
* XKB keymap manager.
|
|
*
|
|
* Copyright (c) 2024, Richard Acayan. All rights reserved.
|
|
*/
|
|
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <xkbcommon/xkbcommon.h>
|
|
#include <xkbcommon/xkbcommon-keysyms.h>
|
|
|
|
#include "keymap.h"
|
|
#include "layout.h"
|
|
#include "ufkbd.h"
|
|
|
|
static int write_keysym(int fd, xkb_keysym_t sym)
|
|
{
|
|
char *name;
|
|
int len, ret;
|
|
|
|
len = xkb_keysym_get_name(sym, NULL, 0);
|
|
if (len == -1)
|
|
return len;
|
|
|
|
name = malloc((size_t) len + 1);
|
|
if (name == NULL)
|
|
return -1;
|
|
|
|
xkb_keysym_get_name(sym, name, (size_t) len + 1);
|
|
|
|
ret = dprintf(fd, "%s", name);
|
|
|
|
free(name);
|
|
return ret;
|
|
}
|
|
|
|
static int maybe_write_modmap(int fd, int keyid, xkb_keysym_t sym)
|
|
{
|
|
if (sym == XKB_KEY_Shift_L || sym == XKB_KEY_Shift_R)
|
|
return dprintf(fd, " modifier_map Shift { <I%03d> };\n",
|
|
keyid);
|
|
else if (sym == XKB_KEY_Control_L || sym == XKB_KEY_Control_R)
|
|
return dprintf(fd, " modifier_map Control { <I%03d> };\n",
|
|
keyid);
|
|
else if (sym == XKB_KEY_Alt_L || sym == XKB_KEY_Alt_R)
|
|
return dprintf(fd, " modifier_map Mod1 { <I%03d> };\n",
|
|
keyid);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ufkbd_keymap_add_key(struct ufkbd_keymap *keymap, xkb_keysym_t keysym)
|
|
{
|
|
xkb_keysym_t upper;
|
|
int len;
|
|
int keyid;
|
|
|
|
keyid = keymap->count;
|
|
if (keyid >= 256)
|
|
return -1;
|
|
|
|
upper = xkb_keysym_to_upper(keysym);
|
|
|
|
len = dprintf(keymap->fd, " key <I%03d> { [ ", keyid);
|
|
if (len == -1)
|
|
return len;
|
|
keymap->size += len;
|
|
|
|
len = write_keysym(keymap->fd, keysym);
|
|
if (len == -1)
|
|
return len;
|
|
keymap->size += len;
|
|
|
|
len = dprintf(keymap->fd, ", ");
|
|
if (len == -1)
|
|
return len;
|
|
keymap->size += len;
|
|
|
|
len = write_keysym(keymap->fd, upper);
|
|
if (len == -1)
|
|
return len;
|
|
keymap->size += len;
|
|
|
|
len = dprintf(keymap->fd, " ] };\n");
|
|
if (len == -1)
|
|
return len;
|
|
keymap->size += len;
|
|
|
|
len = maybe_write_modmap(keymap->fd, keyid, keysym);
|
|
if (len == -1)
|
|
return len;
|
|
keymap->size += len;
|
|
|
|
keymap->count++;
|
|
|
|
return keyid;
|
|
}
|
|
|
|
void ufkbd_keymap_end(struct ufkbd_keymap *keymap)
|
|
{
|
|
int i;
|
|
int fd = keymap->fd;
|
|
size_t written;
|
|
|
|
written = dprintf(fd, " };\n"
|
|
"\n"
|
|
" xkb_keycodes \"ufkbd\" {\n"
|
|
" minimum = 8;\n"
|
|
" maximum = 255;\n");
|
|
|
|
for (i = 8; i < keymap->count; i++)
|
|
written += dprintf(fd, " <I%03d> = %d;\n", i, i);
|
|
|
|
written += dprintf(fd, " indicator 1 = \"Caps Lock\";\n"
|
|
" };\n"
|
|
"\n"
|
|
" xkb_types \"ufkbd\" {\n"
|
|
" type \"TWO_LEVEL\" {\n"
|
|
" modifiers = Shift;\n"
|
|
" map[Shift] = Level2;\n"
|
|
" level_name[Level1] = \"Base\";\n"
|
|
" level_name[Level2] = \"Shift\";\n"
|
|
" };\n"
|
|
" };\n"
|
|
"\n"
|
|
" xkb_compatibility \"ufkbd\" {\n"
|
|
" };\n"
|
|
"};\n");
|
|
|
|
keymap->size += written;
|
|
}
|
|
|
|
struct ufkbd_keymap *ufkbd_keymap_init(void)
|
|
{
|
|
struct ufkbd_keymap *keymap;
|
|
intmax_t pid;
|
|
|
|
keymap = malloc(sizeof(*keymap));
|
|
if (keymap == NULL)
|
|
return NULL;
|
|
|
|
pid = getpid();
|
|
snprintf(keymap->path, 256, "/tmp/ufkbd-keymap-pid%ju", pid);
|
|
|
|
keymap->fd = open(keymap->path, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
|
if (keymap->fd == -1)
|
|
goto err;
|
|
|
|
keymap->count = 8;
|
|
keymap->size = dprintf(keymap->fd, "xkb_keymap {\n"
|
|
" xkb_symbols \"ufkbd\" {\n");
|
|
|
|
return keymap;
|
|
|
|
err:
|
|
free(keymap);
|
|
return NULL;
|
|
}
|
|
|
|
void ufkbd_keymap_uninit(struct ufkbd_keymap *keymap)
|
|
{
|
|
close(keymap->fd);
|
|
unlink(keymap->path);
|
|
free(keymap);
|
|
}
|