Compare commits

...

81 Commits
0.2 ... master

Author SHA1 Message Date
norayr chilingarian 92795b2a0a fix uppercase in armenian (and perhaps some other) layouts
"This patch fixes uppercase in armenian (and perhaps some other) layouts. svkbd
was previously registering a key in one modification (xorg accepts up to 4
modifications). with this patch svkbd registers 2 modifications - upper and
lower case. function tmp_remap changed in a way that if the key is not found in
a current layout, it is temporary added to it. for cyrillic layout uppercase
(when shift is pressed) letters were showing anyway, because those are somehow
found (modified) by xorg. but for armenian layout that did not work. now works."

Patch by նորայր <norayr@arnet.am>
2023-12-13 19:10:08 +01:00
Hiltjo Posthuma ff704d5d1e update LICENSE 2023-02-05 11:26:58 +01:00
Norayr Chilingarian 7fc78a0b44 dvorak layout 2023-02-05 11:25:58 +01:00
Hiltjo Posthuma 3dfb00ccf8 fix comment style 2023-02-05 11:25:46 +01:00
Norayr Chilingarian c247720ae4 armenian layout 2023-01-29 17:33:13 +01:00
Hiltjo Posthuma 38faf1cc8a bump version to 0.4.1 2022-01-07 12:38:18 +01:00
Justin Torres 5dd14703ed Fix color scheme editing on smiley with Xresources
Fixes a small oversight that was preventing the colors of the smiley on q from changing with Xresources.

Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-10-09 10:29:10 +02:00
Max Schillinger 4061bacc1d create layout-dependent object files
When you build svkbd with different layouts, you get one binary per
layout but all binaries are identical:

    $ make LAYOUT=mobile-plain
    $ make LAYOUT=mobile-simple
    $ diff -s svkbd-mobile-plain svkbd-mobile-simple
    Files svkbd-mobile-plain and svkbd-mobile-simple are identical

The problem is that svkbd.o from the first build is being reused in the
second build.

This commit changes the Makefile to create layout-dependent object files
like svkbd-mobile-plain.o and svkbd-mobile-simple.o (instead of a shared
svkbd.o).
2021-10-01 12:32:38 +02:00
Страхиња Радић 0f07238b53 Add a Serbian layout: layout.sr.h 2021-08-02 18:20:38 +02:00
Hiltjo Posthuma 6ffe71a5f6 bump version to 0.4 2021-07-30 16:50:14 +02:00
Hiltjo Posthuma d9dcf0d113 config.mk: fix version printing for -v 2021-07-30 16:49:57 +02:00
Maarten van Gompel 4a511a6cfb minor update for emoji overlay on Q: simpler glyph
I picked a simpler glyph because the other might be more likely to not be
present in a font.
2021-07-20 11:01:01 +02:00
Hiltjo Posthuma 6a14319331 change comment-style in .c file 2021-07-12 12:51:52 +02:00
Maarten van Gompel 378a1c8b30 made the Q key double as a trigger for the emoji overlay in the default mobile-intl layout
This makes the emoji overlay accessible without sacrificing an extra key.
There are (afaik) no languages with diacritics on the Q anyway and it's
the first letter key.

A small emoji will show as 2nd label on the keycap as a hint, the caveat
being that the hint applies to a long press rather than a shift-press as
with most 2nd labels, but better than no hint at all.
2021-07-12 12:34:10 +02:00
Maarten van Gompel 3cff4547c5 code cleanup in overlay definitions (removed empty lines comments) 2021-07-12 12:34:03 +02:00
Maarten van Gompel b053404199 moved backspace key down in dialer layer (mobile-intl and simple layout), for more consistency with other layers 2021-07-12 12:33:55 +02:00
Maarten van Gompel b5775349f6 minor documentation update 2021-07-12 12:33:50 +02:00
Maarten van Gompel 2164466746 protection against segfault if overlay has more keys than the keyboard itself 2021-07-12 12:33:44 +02:00
Maarten van Gompel b70948b74c exclude certain modifier keys and basic keys from being overlayed
This ensures that modifiers like shift/ctrl can be correctly used with the overlay.
2021-07-12 12:33:39 +02:00
Maarten van Gompel e2828d4f7a added missing e caron to overlay in international and simple layouts (e.g. for czech) 2021-07-12 12:33:32 +02:00
Hiltjo Posthuma 4c9182636c no need to initialize these variables here 2021-07-03 11:45:15 +02:00
Hiltjo Posthuma 2a2acdacaa small code-style changes 2021-07-03 11:45:05 +02:00
Hiltjo Posthuma 81c96cec89 check key for NULL dereference, just in case
This matches the check pattern in other parts of the code.
2021-07-03 11:44:18 +02:00
Hiltjo Posthuma fd01322564 adjust other layouts for the second label change
From the commit:

	commit d06db9eb4f
	Author: Maarten van Gompel <proycon@anaproy.nl>
	Date:   Sat Mar 6 16:30:44 2021 +0100

	    Added a second key label for the shift-activated symbols
2021-07-03 11:30:53 +02:00
Sebastian LaVine e2dff73599 Fix broken key definitions in layout.en.h
There were two problems with this file.

First, there were commas missing from the definitions for XK_7, XK_0,
XK_minus, and XK_plus. This prevented svkbd from even compiling.

Secondly, XK_Return was misdefined. This resulted in an immediate
segmentation fault upon loading the program.
2021-07-03 11:02:50 +02:00
Hiltjo Posthuma 34e5659db8 remove unused variable 2021-06-13 23:19:45 +02:00
Maarten van Gompel 5491251610 added an additional minimal mobile layer 2021-06-13 23:15:46 +02:00
Maarten van Gompel a5cb7d53ce increase spacing, set scheme for window, make window render faster by removing unnecessary map requests to X 2021-06-13 23:15:39 +02:00
Maarten van Gompel 2a84ae50f9 adding dead spacing between keys to prevent misclicks and adapting keyboard layout to a less rigid grid (all aimed to reduce typos) 2021-06-13 23:15:32 +02:00
Hiltjo Posthuma 2306b8eb40 remove unneeded initialization to zero
This removes a warning when compiling with -Wall (tested with clang 11.1.0).
2021-06-13 22:35:16 +02:00
silver 34530800bb Fix error in >1 wide key width calc, also 2021
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-06-13 22:33:11 +02:00
Max Schillinger 42380f62eb allow neutralizing a key modifier by applying the same modifier again
svkbd allows you to create keys for symbols of the second (=shift) layer by defining them with a modifier included, like:

    { "|", "|", XK_backslash, 1, XK_Shift_L },

This key creates a pipe symbol by sending shift + backslash. But unfortunately, this way you can't emit get the original symbol (backslash) anymore. So you still need a separate key for typing a backslash, wasting precious space on the screen.

The appended patch fixes this by allowing to neutralize the shift by tapping this key with shift. It works both by tapping first shift, then the pipe key on the on-screen keyboard, or by clicking the pipe key with the middle mouse button (assuming XK_Shift_L is set as the button 2 mod).

This way you can create a "flipped" backslash/pipe key:

    { "|", "\\", XK_backslash, 1, XK_Shift_L },

This patch works equally for AltGr symbols in a `de`-based layout. For example:

    { "~", "+", XK_plus, 1, XK_ISO_Level3_Shift },

(In the German QWERTZ layout, you enter "~" with AltGr-"+".)

Best regards,
Max

Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-06-13 22:33:03 +02:00
Hiltjo Posthuma b25e55e462 bump version to 0.3
... and change 0.3.0 to be consistent to the 0.2 and 0.1 release.
2021-03-28 22:54:23 +02:00
Stacy Harper 1d5e9346e8 Add missing keys on lazy layers
As I used it, it really feels like ctrl and alt should be accessible
Esc now replace shift on symbol page (as shift is useless here anyway)
As we now got keys on the two first layers, I removed the smart
old layer.

Signed-off-by: Stacy Harper <contact@stacyharper.net>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 19:08:49 +02:00
Hiltjo Posthuma 4c4a085580 code-style 2021-03-28 15:24:42 +02:00
Hiltjo Posthuma d509e189d4 usage already exits, remove exit(2)
This now exits with the same status 1.
Document exit status in the man page.
2021-03-28 15:19:38 +02:00
Hiltjo Posthuma d81fe4c879 bump LICENSE year 2021-03-28 15:13:04 +02:00
Hiltjo Posthuma c91cf4a12a rm unused variables 2021-03-28 15:12:30 +02:00
Hiltjo Posthuma 1cc5f87511 usage: add -g information entry and fix newline after -H option 2021-03-28 15:10:40 +02:00
Hiltjo Posthuma d6026943d3 improve command-line parsing, fix crash with -fn without argument
Print the usage information instead of silently continuing.
On an invalid argument print the invalid argument and usage.
2021-03-28 15:05:56 +02:00
Hiltjo Posthuma 55de8b5184 comment style 2021-03-28 15:03:09 +02:00
Hiltjo Posthuma 7c06a0caf5 code-style changes 2021-03-28 15:02:25 +02:00
Hiltjo Posthuma 8f6a7b5e42 use sizeof(buffer) instead of hardcoded 32 2021-03-28 14:58:19 +02:00
Hiltjo Posthuma 4b5a61b275 add check for debug flag in printdbg() function itself 2021-03-28 14:56:05 +02:00
Hiltjo Posthuma 7980cb5f51 estrdup errors out, so remove the condition 2021-03-28 14:52:03 +02:00
Hiltjo Posthuma 9c492b6913 some code-style changes 2021-03-28 14:51:00 +02:00
Hiltjo Posthuma ea4b058833 fix unnecesary c99-ism, fixes compilation on OpenBSD using gcc 2021-03-28 14:42:38 +02:00
Hiltjo Posthuma d19a80dfe5 put estrdup in util and use die() instead of BSD err() 2021-03-28 14:41:32 +02:00
Maarten van Gompel b80819aa3f Various indentation fixes for a more consistent style 2021-03-28 14:39:58 +02:00
Maarten van Gompel 02f13a74c3 ternary operator was used in the wrong order 2021-03-28 14:39:51 +02:00
Maarten van Gompel f2322e9c0e Added a util function estrdup() to check all memory allocations 2021-03-28 14:39:45 +02:00
Maarten van Gompel 10024fc963 removed debugging flag
This patch series is to be applied on top of the 24 I already sent and
addressed the feedback received thus-far.
2021-03-28 14:39:39 +02:00
Maarten van Gompel 2fa04e74fe fixed double free error 2021-03-28 14:35:01 +02:00
Maarten van Gompel 5fd07406ae Updated the documentation to describe the new functionality 2021-03-28 14:35:01 +02:00
Maarten van Gompel 444ceabde3 cleanup and reworking some of the logic 2021-03-28 14:35:01 +02:00
Maarten van Gompel a43bf5c4c1 fix for output key on release 2021-03-28 14:35:01 +02:00
Reed Wade 4ec3b00d6c Rebuild on layout update
Signed-off-by: Reed Wade <reedwade@misterbanal.net>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 14:35:01 +02:00
Reed Wade 7a6742e6e4 fix the highlighted key on dragged touch
Signed-off-by: Reed Wade <reedwade@misterbanal.net>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 14:35:01 +02:00
Reed Wade b6055b3310 Added mobile-simple layout
Signed-off-by: Reed Wade <reedwade@misterbanal.net>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 14:35:01 +02:00
tetrakist 8c28fd15f3 Add Xresources support.
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 14:35:01 +02:00
Maarten van Gompel 869a4328c9 fixed print output mode 2021-03-28 14:35:01 +02:00
Maarten van Gompel 9b5ebd8447 adapted plain layout and legacy layouts to new structure 2021-03-28 14:35:01 +02:00
Maarten van Gompel 72b936baf6 Allow toggling modifier keys even when an overlay is displayed 2021-03-28 14:35:01 +02:00
Maarten van Gompel bd3620acf4 fix for earlier overlay width patch (there was a conflict with multirow overlays) 2021-03-28 14:35:01 +02:00
Maarten van Gompel c2251315e5 Simpler implementation for keeping track overlay keys (solution by stacy) 2021-03-28 14:35:01 +02:00
Maarten van Gompel 174c86d8fa Implemented key output option to stdout 2021-03-28 14:35:01 +02:00
Maarten van Gompel d06db9eb4f Added a second key label for the shift-activated symbols 2021-03-28 14:35:01 +02:00
Reed Wade 6633915997 Usefull if you want to skip somekeys that you want still displayed under the overlay.
Signed-off-by: Reed Wade <reedwade@misterbanal.net>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 14:35:01 +02:00
Reed Wade d10af923a3 Extended key definition to allow setting explicit symbol for shift modifier.
This allow key definitions as :

{ "?", XK_slash, 1, XK_Shift_L },

Which will press <S-/> wich output `?`

Signed-off-by: Reed Wade <reedwade@misterbanal.net>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2021-03-28 14:35:01 +02:00
Maarten van Gompel 3be1e21c9f Implementing a print output mode and ability to not simulate keypresses for X 2021-03-28 14:35:01 +02:00
Maarten van Gompel e9208cb088 Applied different styling to overlays 2021-03-28 14:35:01 +02:00
Maarten van Gompel 7f59daca5f bump version to 0.3.0 2021-03-28 14:35:01 +02:00
Maarten van Gompel 6dc8c78b82 Implemented press-on-release and repetition after delay (the latter only for keys without overlay) 2021-03-28 14:35:01 +02:00
Maarten van Gompel 9fd94b637a Removed grid drwawing and set different slightly theme for abc keys 2021-03-28 14:35:01 +02:00
Maarten van Gompel 6f3308b327 Added an extra row to the mobile-intl layout for numbers/punctuation, reshuffling some keys, added navigation layer and disabled the functions layer 2021-03-28 14:35:01 +02:00
Jochen Sprickerhof 0ea4559388 Force installing executable
So we don't fail if it is executed at the same time.
2021-02-25 19:16:09 +01:00
Hiltjo Posthuma 84715dd6c6 bump version to 0.2.2 2020-12-11 18:37:15 +01:00
Maarten van Gompel 1fff13a1b4 fixed a bug that reset the layer to layer one after hiding the overlay 2020-12-11 18:25:53 +01:00
Maarten van Gompel 79ff93369c fixed russian keyboard layout in mobile-intl, Р key was missing, moved З to an overlay on е because of lack of space 2020-12-11 18:25:44 +01:00
Hiltjo Posthuma 02a2f77fbb config.mk: set DEFAULT_SOURCE
This suppresses warnings about usleep and strdup on Linux glibc and musl.

(Also tested on OpenBSD and FreeBSD, which didn't give such a warning).

Thanks to quinq for reporting it.
2020-09-18 12:59:17 +02:00
Maarten van Gompel 3a51eafd3a Make install fix: install the actual compiled layout 2020-09-16 23:31:37 +02:00
19 changed files with 2148 additions and 991 deletions

View File

@ -2,7 +2,8 @@ MIT/X Consortium License
© 2011 Christoph Lohmann <20h@r-36.net>
© 2008-2011 Enno Boland <g # s01 ' de>
© 2020 Maarten van Gompel <proycon@anaproy.nl>
© 2020-2021 Maarten van Gompel <proycon@anaproy.nl>
© 2020-2023 Hiltjo Posthuma <hiltjo@codemadness.org>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View File

@ -3,13 +3,13 @@
.POSIX:
NAME = svkbd
VERSION = 0.2
VERSION = 0.4.1
include config.mk
BIN = ${NAME}-${LAYOUT}
SRC = drw.c ${NAME}.c util.c
OBJ = ${SRC:.c=.o}
OBJ = drw.o ${NAME}-${LAYOUT}.o util.o
MAN1 = ${NAME}.1
all: ${BIN}
@ -24,6 +24,9 @@ options:
config.h:
cp config.def.h $@
svkbd-${LAYOUT}.o: config.h layout.${LAYOUT}.h
${CC} ${SVKBD_CFLAGS} ${SVKBD_CPPFLAGS} -c svkbd.c -o $@
.c.o:
${CC} ${SVKBD_CFLAGS} ${SVKBD_CPPFLAGS} -c $<
@ -33,7 +36,7 @@ ${BIN}: ${OBJ}
${CC} -o ${BIN} ${OBJ} ${SVKBD_LDFLAGS}
clean:
rm -f ${NAME}-?? ${NAME}-??.o ${OBJ} ${BIN}
rm -f ${NAME}-?? ${NAME}-*.o ${OBJ} ${BIN}
dist:
rm -rf "${NAME}-${VERSION}"
@ -50,11 +53,8 @@ dist:
install: all
mkdir -p ${DESTDIR}${PREFIX}/bin
for i in ${NAME}-??; \
do \
cp $$i ${DESTDIR}${PREFIX}/bin; \
chmod 755 ${DESTDIR}${PREFIX}/bin/$$i; \
done
cp -f ${NAME}-${LAYOUT} ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}-${LAYOUT}
mkdir -p "${DESTDIR}${MANPREFIX}/man1"
sed "s/VERSION/${VERSION}/g" < ${MAN1} > ${DESTDIR}${MANPREFIX}/man1/${MAN1}
chmod 644 ${DESTDIR}${MANPREFIX}/man1/${MAN1}

View File

@ -10,7 +10,7 @@ Installation
$ make
$ make install
This will create by default `svkbd-intl`, which is svkbd using an international
This will create by default `svkbd-mobile-intl`, which is svkbd using an international
layout with multiple layers and overlays, and optimised for mobile devices.
You can create svkbd for additional layouts by doing:
@ -31,11 +31,13 @@ The following layouts are available:
diacritics and other variants, as well as some emoji. The layers are:
* a basic qwerty layer
* a layer for numeric input, arrows, and punctuation
* a layer for function keys, media keys, and arrows
* a cyrillic layer (ЙЦУКЕН)
* a cyrillic layer (ЙЦУКЕН based); the э key is moved to an overlay on е
* a dialer/numeric layer
* an arrow layer
* a more minimal qwerty layer (bigger keys) for smaller screens/larger fingers.
* ``mobile-plain`` - This is a plain layout with only a qwerty layer and numeric/punctuation layer. It was
originally made for [sxmo](https://sr.ht/~mil/Sxmo/).
* ``mobile-simple`` - This is a more minimalistic layout that is more similar to what Android and iOS offer.
* **Traditional layouts**:
* ``en`` - An english layout without layers (QWERTY)
* ``de`` - A german layout (QWERTZ)
@ -59,25 +61,50 @@ some space of the screen being reserved for it.
$ svkbd-mobile-intl -g 400x200+1+1
This will start svkbd-intl with a size of 400x200 and at the upper left
This will start svkbd-mobile-intl with a size of 400x200 and at the upper left
window corner.
For layouts that consist of multiple layers, you can enable layers on program start through either the ``-l`` flag or
through the ``SVKBD_LAYERS`` environment variable. They both take a comma separated list of layer names (as defined in
your ``layout.*.h``). Use the ``↺`` button in the bottom-left to cycle through all the layers.
your ``layout.*.h``). Use the ``↺`` button in the bottom-left to cycle through all the layers in the exact order they
were specified.
Some layouts come with overlays that will show when certain keys are hold pressed for a longer time. For
example, a long press on the ``a`` key will enable an overview showing all kinds of diacritic combinations for ``a``.
Some layouts come with overlays that will show when certain keys are hold pressed for a longer time. For example, a long
press on the ``a`` key will enable an overview showing all kinds of diacritic combinations for ``a``. In the
``mobile-intl`` layout, a long press on a punctuation key will show an overlay with all further punctuation options (the
same for all punctuation keys). Moreover, a long press on the ``q`` key doubles as a trigger for the emoji overlay in
this layout.
Overlay functionality interferes with the ability to hold a key and have it outputted repeatedly. You can disable
overlay functionality with the ``-O`` flag or by setting the environment variable ``SVKBD_ENABLEOVERLAYS=0``. There is
also a key on the function layer of the keyboard itself to enable/disable this behaviour on the fly. Its label shows
``≅`` when the overlay functionality is enabled and ``≇`` when not.
Svkbd has been optimised for use on mobile devices with a touchscreen and implements press-on-release
behaviour (which can be disabled), it also works fine on normal desktop systems with a regular mouse.
Advanced Usage
---------------
Svkbd has an extra output mode where all keypresses are printed to standard output. Optionally, you can also disable the
default X11 keypress emulation. This gives you the freedom to use svkbd in other contexts and use simple pipes to
connect it to other tools:
$ svkbd-mobile-intl -n -o | cowsay
This becomes especially useful if you want things like haptic feedback or audio feedback upon keypress. This is
deliberately not implemented in svkbd itself (we want to keep things simple after all), but can be accomplished using
the external tool [clickclack](https://git.sr.ht/~proycon/clickclack):
$ svkbd-mobile-intl -o | clickclack -V -f keypress.wav
Notes
---------
This virtual keyboard does not actually modify the X keyboard layout, the ``mobile-intl``, ``mobile-plain`` and ``en`` layouts simply rely on a standard US QWERTY layout (setxkbmap us) being activated, the other layouts (``de``, ``ru``, ``sh``) require their respective XKB keymaps to be active.
This virtual keyboard does not actually modify the X keyboard layout, the ``mobile-intl``, ``mobile-plain``,
``mobile-simple`` and ``en`` layouts simply rely on a standard US QWERTY layout (setxkbmap us) being activated, the
other layouts (``de``, ``ru``, ``sh``) require their respective XKB keymaps to be active.
If you use another XKB layout you will get unpredictable output that does not match the labels on the virtual keycaps!

View File

@ -1,13 +1,30 @@
static const Bool wmborder = True;
static int fontsize = 20;
static int fontsize = 22;
/* overlay delay in seconds */
static double overlay_delay = 1.0;
static int heightfactor = 16; //one row of keys takes up 1/x of the screen height
static const char *fonts[] = {
"DejaVu Sans:bold:size=20"
/* repeat delay in seconds, will not work on keys with overlays */
static double repeat_delay = 0.75;
/* scan rate in microseconds, affects key repetition rate */
static int scan_rate = 50;
/* one row of keys takes up 1/x of the screen height */
static int heightfactor = 14;
static int xspacing = 5;
static int yspacing = 5;
static const char *defaultfonts[] = {
"DejaVu Sans:bold:size=22"
};
static const char *colors[SchemeLast][2] = {
static const char *defaultcolors[SchemeLast][2] = {
/* fg bg */
[SchemeNorm] = { "#ffffff", "#14313d" },
[SchemePress] = { "#ffffff", "#000000" },
[SchemeNorm] = { "#bbbbbb", "#132a33" },
[SchemeNormShift] = { "#008ac0", "#132a33" },
[SchemeNormABC] = { "#ffffff", "#14313d" },
[SchemeNormABCShift] = { "#008ac0", "#14313d" },
[SchemePress] = { "#ffffff", "#259937" },
[SchemePressShift] = { "#00c001", "#259937" },
[SchemeHighlight] = { "#58a7c6", "#005577" },
[SchemeHighlightShift] = { "#008ac0", "#005577" },
[SchemeOverlay] = { "#ffffff", "#2b3313" },
[SchemeOverlayShift] = { "#008ac0", "#2b3313" },
[SchemeWindow] = { "#bbbbbb", "#132a33" },
};

View File

@ -24,4 +24,4 @@ LIBS = -L${X11LIB} -lX11 -lXtst -lXft ${XINERAMALIBS} \
# use system flags
SVKBD_CFLAGS = ${CFLAGS} ${INCS}
SVKBD_LDFLAGS = ${LDFLAGS} ${LIBS}
SVKBD_CPPFLAGS = ${CPPFLAGS} -DVERSION=\"VERSION\" ${XINERAMAFLAGS} -DLAYOUT=\"layout.${LAYOUT}.h\"
SVKBD_CPPFLAGS = ${CPPFLAGS} -D_DEFAULT_SOURCE -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} -DLAYOUT=\"layout.${LAYOUT}.h\"

85
layout.am.h Normal file
View File

@ -0,0 +1,85 @@
#define KEYS 63
static Key keys_am[] = {
{ "՝","՜", XK_Armenian_exclam, 1 },
{ "ֆ","Ֆ", XK_Armenian_fe, 1 },
{ "ձ","Ձ", XK_Armenian_dza, 1 },
{ "֊","", XK_Armenian_hyphen, 1 },
{ ",","՟", XK_comma, 1 },
{ "։","", XK_Armenian_full_stop, 1 },
{ "՞","%", XK_Armenian_question, 1 },
{ "","և", XK_Armenian_ligature_ew, 1 },
{ "՛","՚", XK_Armenian_accent, 1 },
{ ")","(", XK_parenright, 1 },
{ "օ","Օ", XK_Armenian_o, 1 },
{ "է","Է", XK_Armenian_e, 1 },
{ "ղ","Ղ", XK_Armenian_ghat, 1 },
{ "<-", 0, XK_BackSpace, 2 },
{ "Del", 0, XK_Delete, 1},
{ 0 }, /* New row */
{ "->|", 0, XK_Tab, 1 },
{ "ճ", "Ճ", XK_Armenian_tche, 1 },
{ "փ", "Փ", XK_Armenian_pyur, 1 },
{ "բ", "Բ", XK_Armenian_ben, 1 },
{ "ս", "Ս", XK_Armenian_se, 1 },
{ "մ", "Մ", XK_Armenian_men, 1 },
{ "ո", "Ո", XK_Armenian_vo, 1 },
{ "ւ", "Ւ", XK_Armenian_vyun, 1 },
{ "կ","Կ", XK_Armenian_ken, 1 },
{ "ը", "Ը", XK_Armenian_at, 1 },
{ "թ", "Թ", XK_Armenian_to, 1 },
{ "ծ", "Ծ", XK_Armenian_tsa, 1 },
{ "ց", "Ց", XK_Armenian_tso, 1 },
{ "Return", 0, XK_Return, 3 },
{ 0 }, /* New row */
{ 0, 0, XK_Caps_Lock, 2 },
{ "ջ", "Ջ", XK_Armenian_je, 1 },
{ "վ", "Վ", XK_Armenian_vev, 1 },
{ "գ", "Գ", XK_Armenian_gim, 1 },
{ "ե", "Ե", XK_Armenian_yech, 1 },
{ "ա", "Ա", XK_Armenian_ayb, 1 },
{ "ն", "Ն", XK_Armenian_nu, 1 },
{ "ի", "Ի", XK_Armenian_ini, 1 },
{ "տ", "Տ", XK_Armenian_tyun, 1 },
{ "հ", "Հ", XK_Armenian_ho, 1 },
{ "պ", "Պ", XK_Armenian_pe, 1 },
{ "ր", "Ր", XK_Armenian_re, 1 },
{ "\\","/", XK_backslash, 1 },
{ 0 }, /* New row */
{ 0, 0, XK_Shift_L, 3 },
{ "ժ", "Ժ", XK_Armenian_zhe, 1 },
{ "դ", "Դ", XK_Armenian_da, 1 },
{ "չ", "Չ", XK_Armenian_cha, 1 },
{ "յ", "Յ", XK_Armenian_hi, 1 },
{ "զ", "Զ", XK_Armenian_za, 1 },
{ "լ", "Լ", XK_Armenian_lyun, 1 },
{ "ք", "Ք", XK_Armenian_ke, 1 },
{ "խ", "Խ", XK_Armenian_khe, 1 },
{ "շ", "Շ", XK_Armenian_sha, 1 },
{ "ռ", "Ռ", XK_Armenian_ra, 1 },
{ 0, 0, XK_Shift_R, 2 },
{ 0 }, /* New row */
{ "Ctrl", 0, XK_Control_L, 2 },
{ "Alt", 0,XK_Alt_L, 2 },
{ "", 0,XK_space, 5 },
{ "Alt", 0,XK_Alt_R, 2 },
{ "Ctrl", 0,XK_Control_R, 2 },
};
Buttonmod buttonmods[] = {
{ XK_Shift_L, Button2 },
{ XK_Alt_L, Button3 },
};
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, 0, XK_Cancel },
};
#define LAYERS 1
static char* layer_names[LAYERS] = {
"am",
};
static Key* available_layers[LAYERS] = {
keys_am,
};

View File

@ -1,11 +1,11 @@
#define KEYS 6
static Key keys_arrows[] = {
{ 0, XK_Shift_L, 2 },
{ "", XK_Left, 1 },
{ "", XK_Down, 1 },
{ "", XK_Up, 1 },
{ "", XK_Right, 1},
{ "Alt", XK_Alt_L, 2 },
{ 0, 0, XK_Shift_L, 2 },
{ "", 0, XK_Left, 1 },
{ "", 0, XK_Down, 1 },
{ "", 0, XK_Up, 1 },
{ "", 0, XK_Right, 1},
{ "Alt", 0, XK_Alt_L, 2 },
};
Buttonmod buttonmods[] = {
@ -15,7 +15,7 @@ Buttonmod buttonmods[] = {
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, XK_Cancel },
{ 0, 0, XK_Cancel },
};
#define LAYERS 1

View File

@ -1,71 +1,71 @@
#define KEYS 66
static Key keys_de[KEYS] = {
{ "^°′", XK_dead_circumflex, 1},
{ "1", XK_1, 1 },
{ "2\"²", XK_2, 1 },
{ "3§³", XK_3, 1 },
{ "4", XK_4, 1 },
{ "5", XK_5, 1 },
{ "6", XK_6, 1 },
{ "7/{", XK_7, 1 },
{ "8([", XK_8, 1 },
{ "9)]", XK_9, 1 },
{ "0=}", XK_0, 1 },
{ "ß?\\", XK_ssharp, 1 },
{ "´`¸", XK_dead_acute, 1 },
{ "<-", XK_BackSpace, 2 },
{ "Entf", XK_Delete, 1},
{ "^","°′", XK_dead_circumflex, 1},
{ "1", "", XK_1, 1 },
{ "2","\"²", XK_2, 1 },
{ "3","§³", XK_3, 1 },
{ "4","", XK_4, 1 },
{ "5","", XK_5, 1 },
{ "6","", XK_6, 1 },
{ "7","/{", XK_7, 1 },
{ "8","([", XK_8, 1 },
{ "9",")]", XK_9, 1 },
{ "0","=}", XK_0, 1 },
{ "ß","?\\", XK_ssharp, 1 },
{ "´","`¸", XK_dead_acute, 1 },
{ "<-", 0, XK_BackSpace, 2 },
{ "Entf", 0, XK_Delete, 1},
{ 0 }, /* New row */
{ "->|", XK_Tab, 1 },
{ "qQ@", XK_q, 1 },
{ "w", XK_w, 1 },
{ "eE€", XK_e, 1 },
{ "r", XK_r, 1 },
{ "t", XK_t, 1 },
{ "zZ←", XK_z, 1 },
{ "uU↓", XK_u, 1 },
{ "iI→", XK_i, 1 },
{ "o", XK_o, 1 },
{ "p", XK_p, 1 },
{ "üܨ", 0xfc, 1 },
{ "+*~", XK_plus, 1 },
{ "Enter", XK_Return, 3 },
{ "->|", 0, XK_Tab, 1 },
{ "q","Q@", XK_q, 1 },
{ "w","", XK_w, 1 },
{ "e","E€", XK_e, 1 },
{ "r","", XK_r, 1 },
{ "t","", XK_t, 1 },
{ "z","Z←", XK_z, 1 },
{ "u","U↓", XK_u, 1 },
{ "i","I→", XK_i, 1 },
{ "o","", XK_o, 1 },
{ "p","", XK_p, 1 },
{ "ü","ܨ", 0xfc, 1 },
{ "+","*~", XK_plus, 1 },
{ "Enter", 0, XK_Return, 3 },
{ 0 }, /* New row */
{ 0, XK_Caps_Lock, 2 },
{ "a", XK_a, 1 },
{ "sSſ", XK_s, 1 },
{ "d", XK_d, 1 },
{ "f", XK_f, 1 },
{ "g", XK_g, 1 },
{ "h", XK_h, 1 },
{ "jJ̣̣", XK_j, 1 },
{ "k", XK_k, 1 },
{ "l", XK_l, 1 },
{ "öÖ˝", 0xf6, 1 },
{ "äÄ^", 0xe4, 1 },
{ "#'", XK_numbersign, 1 },
{ 0, 0, XK_Caps_Lock, 2 },
{ "a","", XK_a, 1 },
{ "s","Sſ", XK_s, 1 },
{ "d","", XK_d, 1 },
{ "f","", XK_f, 1 },
{ "g","", XK_g, 1 },
{ "h","", XK_h, 1 },
{ "j","J̣̣", XK_j, 1 },
{ "k","", XK_k, 1 },
{ "l","", XK_l, 1 },
{ "ö","Ö˝", 0xf6, 1 },
{ "ä","Ä^", 0xe4, 1 },
{ "#","'", XK_numbersign, 1 },
{ 0 }, /* New row */
{ 0, XK_Shift_L, 2 },
{ "<>|", XK_less, 1 },
{ "y", XK_y, 1 },
{ "x", XK_x, 1 },
{ "c", XK_c, 1 },
{ "vV„", XK_v, 1 },
{ "bB“", XK_b, 1 },
{ "nN”", XK_n, 1 },
{ "m", XK_m, 1 },
{ ",", XK_comma, 1 },
{ ".:…", XK_period, 1 },
{ "-_", XK_minus, 1 },
{ 0, XK_Shift_R, 2 },
{ 0, 0, XK_Shift_L, 2 },
{ "<",">|", XK_less, 1 },
{ "y","", XK_y, 1 },
{ "x","", XK_x, 1 },
{ "c","", XK_c, 1 },
{ "v","V„", XK_v, 1 },
{ "b","B“", XK_b, 1 },
{ "n","N”", XK_n, 1 },
{ "m","", XK_m, 1 },
{ ",","", XK_comma, 1 },
{ ".",":…", XK_period, 1 },
{ "-","_", XK_minus, 1 },
{ 0, 0, XK_Shift_R, 2 },
{ 0 }, /* New row */
{ "Ctrl", XK_Control_L, 2 },
{ "Win", XK_Super_L, 2 },
{ "Alt", XK_Alt_L, 2 },
{ "", XK_space, 5 },
{ "Alt Gr", XK_ISO_Level3_Shift, 2 },
{ "Menu", XK_Menu, 2 },
{ "Ctrl", XK_Control_R, 2 },
{ "Ctrl", 0, XK_Control_L, 2 },
{ "Win", 0, XK_Super_L, 2 },
{ "Alt", 0, XK_Alt_L, 2 },
{ "", 0, XK_space, 5 },
{ "Alt Gr", 0, XK_ISO_Level3_Shift, 2 },
{ "Menu", 0, XK_Menu, 2 },
{ "Ctrl", 0, XK_Control_R, 2 },
};
Buttonmod buttonmods[] = {
@ -75,7 +75,7 @@ Buttonmod buttonmods[] = {
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, XK_Cancel },
{ 0, 0, XK_Cancel },
};
#define LAYERS 1

View File

@ -1,66 +1,66 @@
#define KEYS 61
static Key keys_en[] = {
{ "1!", XK_1, 1 },
{ "2@", XK_2, 1 },
{ "3#", XK_3, 1 },
{ "4$", XK_4, 1 },
{ "5%", XK_5, 1 },
{ "6^", XK_6, 1 },
{ "7&", XK_7, 1 },
{ "8*", XK_8, 1 },
{ "9(", XK_9, 1 },
{ "0)", XK_0, 1 },
{ "-_", XK_minus, 1 },
{ "=+", XK_plus, 1 },
{ "<-", XK_BackSpace, 2 },
{ "1","!", XK_1, 1 },
{ "2","@", XK_2, 1 },
{ "3","#", XK_3, 1 },
{ "4","$", XK_4, 1 },
{ "5","%", XK_5, 1 },
{ "6","^", XK_6, 1 },
{ "7","&", XK_7, 1 },
{ "8","*", XK_8, 1 },
{ "9","(", XK_9, 1 },
{ "0",")", XK_0, 1 },
{ "-","_", XK_minus, 1 },
{ "=","+", XK_plus, 1 },
{ "⌫Bksp",0, XK_BackSpace, 2 },
{ 0 }, /* New row */
{ "->|", XK_Tab, 1 },
{ 0, XK_q, 1 },
{ 0, XK_w, 1 },
{ 0, XK_e, 1 },
{ 0, XK_r, 1 },
{ 0, XK_t, 1 },
{ 0, XK_y, 1 },
{ 0, XK_u, 1 },
{ 0, XK_i, 1 },
{ 0, XK_o, 1 },
{ 0, XK_p, 1 },
{ "[", XK_bracketleft, 1 },
{ "]", XK_bracketright, 1 },
{ "Return", XK_Return, 3 },
{ "->|",0, XK_Tab, 1 },
{ 0, 0, XK_q, 1 },
{ 0, 0, XK_w, 1 },
{ 0, 0, XK_e, 1 },
{ 0, 0, XK_r, 1 },
{ 0, 0, XK_t, 1 },
{ 0, 0, XK_y, 1 },
{ 0, 0, XK_u, 1 },
{ 0, 0, XK_i, 1 },
{ 0, 0, XK_o, 1 },
{ 0, 0, XK_p, 1 },
{ "[","{", XK_bracketleft, 1 },
{ "]", "}", XK_bracketright, 1 },
{ "Enter", 0, XK_Return, 3 },
{ 0 }, /* New row */
{ 0, XK_Caps_Lock, 2 },
{ 0, XK_a, 1 },
{ 0, XK_s, 1 },
{ 0, XK_d, 1 },
{ 0, XK_f, 1 },
{ 0, XK_g, 1 },
{ 0, XK_h, 1 },
{ 0, XK_j, 1 },
{ 0, XK_k, 1 },
{ 0, XK_l, 1 },
{ ":;", XK_semicolon, 1 },
{ "'\"", XK_exclam, 1 },
{ "\\|", XK_backslash, 1 },
{ 0, 0, XK_Caps_Lock, 2 },
{ 0, 0, XK_a, 1 },
{ 0, 0, XK_s, 1 },
{ 0, 0, XK_d, 1 },
{ 0, 0, XK_f, 1 },
{ 0, 0, XK_g, 1 },
{ 0, 0, XK_h, 1 },
{ 0, 0, XK_j, 1 },
{ 0, 0, XK_k, 1 },
{ 0, 0, XK_l, 1 },
{ ":",";", XK_semicolon, 1 },
{ "'","\"", XK_exclam, 1 },
{ "\\", "|", XK_backslash, 1 },
{ 0 }, /* New row */
{ 0, XK_Shift_L, 3 },
{ 0, XK_z, 1 },
{ 0, XK_x, 1 },
{ 0, XK_c, 1 },
{ 0, XK_v, 1 },
{ 0, XK_b, 1 },
{ 0, XK_n, 1 },
{ 0, XK_m, 1 },
{ ",", XK_colon, 1 },
{ ".", XK_period, 1 },
{ "/?", XK_slash, 1 },
{ 0, XK_Shift_R, 2 },
{ 0, 0, XK_Shift_L, 3 },
{ 0, 0, XK_z, 1 },
{ 0, 0, XK_x, 1 },
{ 0, 0, XK_c, 1 },
{ 0, 0, XK_v, 1 },
{ 0, 0, XK_b, 1 },
{ 0, 0, XK_n, 1 },
{ 0, 0, XK_m, 1 },
{ ",", "<", XK_colon, 1 },
{ ".", ">", XK_period, 1 },
{ "/", "?", XK_slash, 1 },
{ 0, 0, XK_Shift_R, 2 },
{ 0 }, /* New row */
{ "Ctrl", XK_Control_L, 2 },
{ "Alt", XK_Alt_L, 2 },
{ "", XK_space, 5 },
{ "Alt", XK_Alt_R, 2 },
{ "Ctrl", XK_Control_R, 2 },
{ "Ctrl",0, XK_Control_L, 2 },
{ "Alt", 0, XK_Alt_L, 2 },
{ "", 0, XK_space, 5 },
{ "Alt", 0, XK_Alt_R, 2 },
{ "Ctrl", 0, XK_Control_R, 2 },
};
Buttonmod buttonmods[] = {
@ -70,15 +70,14 @@ Buttonmod buttonmods[] = {
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, XK_Cancel },
{ 0, 0, XK_Cancel },
};
#define LAYERS 1
static char* layer_names[LAYERS] = {
"en",
"en",
};
static Key* available_layers[LAYERS] = {
keys_en,
keys_en,
};

File diff suppressed because it is too large Load Diff

View File

@ -1,125 +1,122 @@
#define KEYS 40
#define KEYS 44
static Key keys_en[KEYS] = {
{ 0, XK_q, 1 },
{ 0, XK_w, 1 },
{ 0, XK_e, 1 },
{ 0, XK_r, 1 },
{ 0, XK_t, 1 },
{ 0, XK_y, 1 },
{ 0, XK_u, 1 },
{ 0, XK_i, 1 },
{ 0, XK_o, 1 },
{ 0, XK_p, 1 },
{ 0, 0, XK_q, 1 },
{ 0, 0, XK_w, 1 },
{ 0, 0, XK_e, 1 },
{ 0, 0, XK_r, 1 },
{ 0, 0, XK_t, 1 },
{ 0, 0, XK_y, 1 },
{ 0, 0, XK_u, 1 },
{ 0, 0, XK_i, 1 },
{ 0, 0, XK_o, 1 },
{ 0, 0, XK_p, 1 },
{ 0 }, /* New row */
{ 0 }, /* New row */
{ 0, XK_a, 1 },
{ 0, XK_s, 1 },
{ 0, XK_d, 1 },
{ 0, XK_f, 1 },
{ 0, XK_g, 1 },
{ 0, XK_h, 1 },
{ 0, XK_j, 1 },
{ 0, XK_k, 1 },
{ 0, XK_l, 1 },
{ ";:", XK_colon, 1 },
/*{ "'", XK_apostrophe, 2 },*/
{ 0, 0, XK_a, 1 },
{ 0, 0, XK_s, 1 },
{ 0, 0, XK_d, 1 },
{ 0, 0, XK_f, 1 },
{ 0, 0, XK_g, 1 },
{ 0, 0, XK_h, 1 },
{ 0, 0, XK_j, 1 },
{ 0, 0, XK_k, 1 },
{ 0, 0, XK_l, 1 },
{ ";",":", XK_colon, 1 },
/*{ "'", XK_apostrophe, 2 },*/
{ 0 }, /* New row */
{ 0 }, /* New row */
{ 0, XK_z, 1 },
{ 0, XK_x, 1 },
{ 0, XK_c, 1 },
{ 0, XK_v, 1 },
{ 0, XK_b, 1 },
{ 0, XK_n, 1 },
{ 0, XK_m, 1 },
/*{ "/?", XK_slash, 1 },*/
{ "Tab", XK_Tab, 1 },
{ "⇍ Bksp", XK_BackSpace, 2 },
{ 0, 0, XK_z, 1 },
{ 0, 0, XK_x, 1 },
{ 0, 0, XK_c, 1 },
{ 0, 0, XK_v, 1 },
{ 0, 0, XK_b, 1 },
{ 0, 0, XK_n, 1 },
{ 0, 0, XK_m, 1 },
/*{ "/?", XK_slash, 1 },*/
{ "Tab", 0, XK_Tab, 1 },
{ "⇍ Bksp", 0, XK_BackSpace, 2 },
{ 0 }, /* New row */
{ "", XK_Cancel, 1},
{ "Shft", XK_Shift_L, 1 },
/*{ "L", XK_Left, 1 },*/
{ "", XK_Down, 1 },
{ "", XK_Up, 1 },
/*{ "R", XK_Right, 1 },*/
{ "", XK_space, 2 },
{ "Esc", XK_Escape, 1 },
{ "Ctrl", XK_Control_L, 1 },
/*{ "Alt", XK_Alt_L, 1 },*/
{ "↲ Enter", XK_Return, 2 },
{ 0 }, /* New row */
{ "", 0, XK_Cancel, 1},
{ "Shft", 0, XK_Shift_L, 1 },
/*{ "L", XK_Left, 1 },*/
{ "", 0, XK_Down, 1 },
{ "", 0, XK_Up, 1 },
/*{ "R", XK_Right, 1 },*/
{ "", 0, XK_space, 2 },
{ "Esc", 0, XK_Escape, 1 },
{ "Ctrl", 0, XK_Control_L, 1 },
/*{ "Alt", XK_Alt_L, 1 },*/
{ "↲ Enter", 0, XK_Return, 2 },
};
static Key keys_symbols[40] = {
{ "1!", XK_1, 1 },
{ "2@", XK_2, 1 },
{ "3#", XK_3, 1 },
{ "4$", XK_4, 1 },
{ "5%", XK_5, 1 },
{ "6^", XK_6, 1 },
{ "7&", XK_7, 1 },
{ "8*", XK_8, 1 },
{ "9(", XK_9, 1 },
{ "0)", XK_0, 1 },
static Key keys_symbols[KEYS] = {
{ "1", "!", XK_1, 1 },
{ "2", "@", XK_2, 1 },
{ "3", "#", XK_3, 1 },
{ "4", "$", XK_4, 1 },
{ "5", "%", XK_5, 1 },
{ "6", "^", XK_6, 1 },
{ "7", "&", XK_7, 1 },
{ "8", "*", XK_8, 1 },
{ "9", "(", XK_9, 1 },
{ "0", ")", XK_0, 1 },
{ 0 }, /* New row */
{ 0 }, /* New row */
{ "'\"", XK_apostrophe, 1 },
{ "`~", XK_grave, 1 },
{ "-_", XK_minus, 1 },
{ "=+", XK_plus, 1 },
{ "[{", XK_bracketleft, 1 },
{ "]}", XK_bracketright, 1 },
{ ",<", XK_comma, 1 },
{ ".>", XK_period, 1 },
{ "/?", XK_slash, 1 },
{ "\\|", XK_backslash, 1 },
{ "'", "\"", XK_apostrophe, 1 },
{ "`", "~", XK_grave, 1 },
{ "-", "_", XK_minus, 1 },
{ "=", "+", XK_plus, 1 },
{ "[", "{", XK_bracketleft, 1 },
{ "]", "}", XK_bracketright, 1 },
{ ",", "<", XK_comma, 1 },
{ ".", ">", XK_period, 1 },
{ "/", "?", XK_slash, 1 },
{ "\\", "|", XK_backslash, 1 },
{ 0 }, /* New row */
{ 0 }, /* New row */
{ "", XK_Shift_L|XK_bar, 1 },
{ "", XK_Home, 1 },
{ "", XK_Left, 1 },
{ "", XK_Right, 1 },
{ "", XK_End, 1 },
{ "", XK_Next, 1 },
{ "", XK_Prior, 1 },
{ "Tab", XK_Tab, 1 },
{ "⇍ Bksp", XK_BackSpace, 2 },
{ "", 0, XK_Shift_L|XK_bar, 1 },
{ "", 0, XK_Home, 1 },
{ "", 0, XK_Left, 1 },
{ "", 0, XK_Right, 1 },
{ "", 0, XK_End, 1 },
{ "", 0, XK_Next, 1 },
{ "", 0, XK_Prior, 1 },
{ "Tab", 0, XK_Tab, 1 },
{ "⇍ Bksp", 0, XK_BackSpace, 2 },
{ 0 }, /* New row */
{ "", XK_Cancel, 1},
{ "Shft", XK_Shift_L, 1 },
/*{ "L", XK_Left, 1 },*/
{ "", XK_Down, 1 },
{ "", XK_Up, 1 },
/*{ "R", XK_Right, 1 },*/
{ "", XK_space, 2 },
{ "Esc", XK_Escape, 1 },
{ "Ctrl", XK_Control_L, 1 },
/*{ "Alt", XK_Alt_L, 1 },*/
{ "↲ Enter", XK_Return, 2 },
{ 0 }, /* New row */
{ "", 0, XK_Cancel, 1},
{ "Shft", 0, XK_Shift_L, 1 },
{ "", 0, XK_Down, 1 },
{ "", 0, XK_Up, 1 },
{ "", 0, XK_space, 2 },
{ "Esc", 0, XK_Escape, 1 },
{ "Ctrl", 0, XK_Control_L, 1 },
{ "↲ Enter", 0, XK_Return, 2 },
};
Buttonmod buttonmods[] = {
{ XK_Shift_L, Button2 },
{ XK_Alt_L, Button3 },
{ XK_Shift_L, Button2 },
{ XK_Alt_L, Button3 },
};
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, XK_Cancel },
{ 0, 0, XK_Cancel },
};
#define LAYERS 2
static char* layer_names[LAYERS] = {
"en",
"symbols",
"en",
"symbols",
};
static Key* available_layers[LAYERS] = {
keys_en,
keys_symbols,
keys_en,
keys_symbols,
};

408
layout.mobile-simple.h Normal file
View File

@ -0,0 +1,408 @@
#define KEYS 43
static Key keys_lazy_en[KEYS] = {
{ 0, 0, XK_q, 1 },
{ 0, 0, XK_w, 1 },
{ 0, 0, XK_e, 1 },
{ 0, 0, XK_r, 1 },
{ 0, 0, XK_t, 1 },
{ 0, 0, XK_y, 1 },
{ 0, 0, XK_u, 1 },
{ 0, 0, XK_i, 1 },
{ 0, 0, XK_o, 1 },
{ 0, 0, XK_p, 1 },
{ 0 },
{ 0, 0, XK_a, 1 },
{ 0, 0, XK_s, 1 },
{ 0, 0, XK_d, 1 },
{ 0, 0, XK_f, 1 },
{ 0, 0, XK_g, 1 },
{ 0, 0, XK_h, 1 },
{ 0, 0, XK_j, 1 },
{ 0, 0, XK_k, 1 },
{ 0, 0, XK_l, 1 },
{ "'", 0, XK_apostrophe, 1 },
{ 0 },
{ "", 0, XK_Shift_L, 1 },
{ 0, 0, XK_z, 1 },
{ 0, 0, XK_x, 1 },
{ 0, 0, XK_c, 1 },
{ 0, 0, XK_v, 1 },
{ 0, 0, XK_b, 1 },
{ 0, 0, XK_n, 1 },
{ 0, 0, XK_m, 1 },
{ "Tab", 0, XK_Tab, 1 },
{ "", 0, XK_BackSpace, 1 },
{ 0 },
{ "?123", 0, XK_Cancel, 3 },
{ "-", 0, XK_minus, 2 },
{ "", 0, 0x101f642, 2 },
{ "Ctl", 0, XK_Control_L, 2 },
{ "Alt", 0, XK_Alt_L, 2 },
{ "", 0, XK_space, 4 },
{ ".", 0, XK_period, 2 },
{ "↲Enter", 0, XK_Return, 3 }
};
static Key keys_symbols[KEYS] = {
{ "1", 0, XK_1, 1 },
{ "2", 0, XK_2, 1 },
{ "3", 0, XK_3, 1 },
{ "4", 0, XK_4, 1 },
{ "5", 0, XK_5, 1 },
{ "6", 0, XK_6, 1 },
{ "7", 0, XK_7, 1 },
{ "8", 0, XK_8, 1 },
{ "9", 0, XK_9, 1 },
{ "0", 0, XK_0, 1 },
{ 0 },
{ "!", 0, XK_1, 1, XK_Shift_L },
{ "@", 0, XK_2, 1, XK_Shift_L },
{ "#", 0, XK_3, 1, XK_Shift_L },
{ "$", 0, XK_4, 1, XK_Shift_L },
{ "%", 0, XK_5, 1, XK_Shift_L },
{ "^", 0, XK_6, 1, XK_Shift_L },
{ "&", 0, XK_7, 1, XK_Shift_L },
{ "*", 0, XK_8, 1, XK_Shift_L },
{ "(", 0, XK_9, 1, XK_Shift_L },
{ ")", 0, XK_0, 1, XK_Shift_L },
{ 0 },
{ "Esc", 0, XK_Escape, 1 },
{ "~", 0, XK_grave, 1, XK_Shift_L },
{ "\\", 0, XK_backslash, 1 },
{ "|", 0, XK_backslash, 1, XK_Shift_L },
{ "", 0, XK_Left, 1 },
{ "", 0, XK_Down, 1 },
{ "", 0, XK_Up, 1 },
{ "", 0, XK_Right, 1 },
{ "Tab", 0, XK_Tab, 1 },
{ "", 0, XK_BackSpace, 1 },
{ 0 },
{ "abc", 0, XK_Mode_switch, 3 },
{ "-", 0, XK_minus, 2 },
{ "", 0, XK_Cancel, 2 },
{ "Ctl", 0, XK_Control_L, 2 },
{ "Alt", 0, XK_Alt_L, 2 },
{ "", 0, XK_space, 4 },
{ ".", 0, XK_period, 2 },
{ "↲Enter", 0, XK_Return, 3 }
};
static Key keys_functions[KEYS] = {
{ "Esc", 0, XK_Escape, 1 },
{ "F1", 0, XK_F1, 1 },
{ "F2", 0, XK_F2, 1 },
{ "F3", 0, XK_F3, 1 },
{ "F4", 0, XK_F4, 1 },
{ "F5", 0, XK_F5, 1 },
{ "F6", 0, XK_F6, 1 },
{ "F7", 0, XK_F7, 1 },
{ "F8", 0, XK_F8, 1 },
{ "F9", 0, XK_F9, 1 },
{ "F10", 0, XK_F10, 1 },
{ 0 },
{ "", 0, XK_KP_Insert, 1 },
{ "", 0, XF86XK_AudioPlay, 1 },
{ "", 0, XF86XK_AudioRecord, 1 },
{ "", 0, XF86XK_AudioStop, 1 },
{ "◂◂", 0, XF86XK_AudioPrev, 1 },
{ "▸▸", 0, XF86XK_AudioNext, 1 },
{ "♫M", 0, XF86XK_AudioMute, 1 },
{ "♫-", 0, XF86XK_AudioLowerVolume, 1 },
{ "♫+", 0, XF86XK_AudioRaiseVolume, 1 },
{ "☀-", 0, XF86XK_MonBrightnessDown, 1 },
{ "☀+", 0, XF86XK_MonBrightnessUp, 1 },
{ 0 },
{ "abc", 0, XK_Mode_switch, 1 },
{ "Del", 0, XK_Delete, 1 },
{ "", 0, XK_Home, 1 },
{ "", 0, XK_Left, 1 },
{ "", 0, XK_Right, 1 },
{ "", 0, XK_End, 1 },
{ "", 0, XK_Next, 1 },
{ "", 0, XK_Prior, 1 },
{ "Tab", 0, XK_Tab, 1 },
{ "", 0, XK_BackSpace, 2 },
{ 0 },
{ "", 0, XK_Cancel, 1},
{ "Shift", 0, XK_Shift_L, 2 },
{ "Ctrl", 0, XK_Control_L, 1 },
{ "Alt", 0, XK_Alt_L, 1 },
{ "", 0, XK_space, 2 },
{ "", 0, XK_Down, 1 },
{ "", 0, XK_Up, 1 },
{ "↲ Enter", 0, XK_Return, 2 },
};
#define DIALER_KEYS 27
static Key keys_dialer[DIALER_KEYS] = {
{ "Esc", 0, XK_Escape, 1 },
{ "1!", 0, XK_1, 1 },
{ "2@", 0, XK_2, 1 },
{ "3#", 0, XK_3, 1 },
{ "-_", 0, XK_minus, 1 },
{ ",<", 0, XK_comma, 1 },
{ 0 },
{ "Shift", 0, XK_Shift_L, 1 },
{ "4$", 0, XK_4, 1 },
{ "5%", 0, XK_5, 1 },
{ "6^", 0, XK_6, 1 },
{ "=+", 0, XK_equal, 1 },
{ "/?", 0, XK_slash, 1 },
{ 0 },
{ "abc", 0, XK_Mode_switch, 1 },
{ "7&", 0, XK_7, 1 },
{ "8*", 0, XK_8, 1 },
{ "9(", 0, XK_9, 1 },
{ "", 0, XK_BackSpace, 2 },
{ 0 },
{ "", 0, XK_Cancel, 1},
{ "", 0, XK_space, 1 },
{ "0)", 0, XK_0, 1 },
{ ".>", 0, XK_period, 1 },
{ "↲ Enter", 0, XK_Return, 2},
};
#define OVERLAYS 193
static Key overlay[OVERLAYS] = {
{ 0, 0, XK_a },
{ "à", 0, XK_agrave },
{ "á", 0, XK_aacute },
{ "â", 0, XK_acircumflex },
{ "ä", 0, XK_adiaeresis },
{ "ą", 0, XK_aogonek },
{ "ã", 0, XK_atilde },
{ "ā", 0, XK_amacron },
{ "ă", 0, XK_abreve },
{ "å", 0, XK_aring },
{ "æ", 0, XK_ae },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_e },
{ "è", 0, XK_egrave },
{ "é", 0, XK_eacute },
{ "ê", 0, XK_ecircumflex },
{ "ë", 0, XK_ediaeresis },
{ "ę", 0, XK_eogonek },
{ "ē", 0, XK_emacron },
{ "ė", 0, XK_eabovedot },
{ "ě", 0, XK_ecaron },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_y },
{ "", 0, XK_ygrave },
{ "ý", 0, XK_yacute },
{ "ŷ", 0, XK_ycircumflex },
{ "ÿ", 0, XK_ydiaeresis },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_u },
{ "ù", 0, XK_ugrave },
{ "ú", 0, XK_uacute },
{ "û", 0, XK_ucircumflex },
{ "ü", 0, XK_udiaeresis },
{ "ų", 0, XK_uogonek },
{ "ū", 0, XK_umacron },
{ "ů", 0, XK_uring},
{ "ŭ", 0, XK_ubreve},
{ "ű", 0, XK_udoubleacute },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_i },
{ "ì", 0, XK_igrave },
{ "í", 0, XK_iacute },
{ "î", 0, XK_icircumflex },
{ "ï", 0, XK_idiaeresis },
{ "į", 0, XK_iogonek },
{ "ī", 0, XK_imacron },
{ "ı", 0, XK_idotless },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_o },
{ "ò", 0, XK_ograve },
{ "ó", 0, XK_oacute },
{ "ô", 0, XK_ocircumflex },
{ "ö", 0, XK_odiaeresis },
{ "ǫ", 0, XK_ogonek },
{ "õ", 0, XK_otilde },
{ "ō", 0, XK_omacron },
{ "ø", 0, XK_oslash },
{ "ő", 0, XK_odoubleacute },
{ "œ", 0, XK_oe },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_d },
{ "ď", 0, XK_dcaron },
{ "ð", 0, XK_eth },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_c },
{ "ç", 0, XK_ccedilla },
{ "ĉ", 0, XK_ccircumflex },
{ "č", 0, XK_ccaron },
{ "ć", 0, XK_cacute },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_s },
{ "ş", 0, XK_scedilla },
{ "ŝ", 0, XK_scircumflex },
{ "š", 0, XK_scaron },
{ "ś", 0, XK_sacute },
{ "ß", 0, XK_ssharp },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_z },
{ "ž", 0, XK_zcaron },
{ "ż", 0, XK_zabovedot },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_n },
{ "ñ", 0, XK_ntilde },
{ "ń", 0, XK_nacute },
{ "ň", 0, XK_ncaron },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_t },
{ "ț", 0, XK_tcedilla },
{ "ť", 0, XK_tcaron },
{ "þ", 0, XK_thorn },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_g },
{ "ĝ", 0, XK_gcircumflex },
{ "ğ", 0, XK_gbreve },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_h },
{ "ĥ", 0, XK_hcircumflex },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_j },
{ "ĵ", 0, XK_jcircumflex },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_l },
{ "ł", 0, XK_lstroke },
{ "ľ", 0, XK_lcaron },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_r },
{ "ř", 0, XK_rcaron },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_softsign },
{ "ъ", 0, XK_Cyrillic_hardsign },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_ie },
{ "ё", 0, XK_Cyrillic_io },
{ "э", 0, XK_Cyrillic_e },
{ "Є", 0, XK_Ukrainian_ie },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_i },
{ "і", 0, XK_Ukrainian_i },
{ "ї", 0, XK_Ukrainian_yi },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_u },
{ "ў", 0, XK_Byelorussian_shortu },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_shorti },
{ "ј", 0, XK_Cyrillic_je },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_el },
{ "љ", 0, XK_Cyrillic_lje },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_en },
{ "њ", 0, XK_Cyrillic_nje },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_tse },
{ "џ", 0, XK_Cyrillic_dzhe },
{ 0, 0, XK_Cancel },
{ 0, 0, XK_Cyrillic_che },
{ "ћ", 0, XK_Serbian_tshe },
{ "ђ", 0, XK_Serbian_dje },
{ 0, 0, XK_Cancel },
{ "🙂", 0, 0x101f642 },
{ "😀", 0, 0x101f600 },
{ "😁", 0, 0x101f601 },
{ "😂", 0, 0x101f602 },
{ "😃", 0, 0x101f603 },
{ "😄", 0, 0x101f604 },
{ "😅", 0, 0x101f605 },
{ "😆", 0, 0x101f606 },
{ "😇", 0, 0x101f607 },
{ "😈", 0, 0x101f608 },
{ "😉", 0, 0x101f609 },
{ "😊", 0, 0x101f60a },
{ "😋", 0, 0x101f60b },
{ "😌", 0, 0x101f60c },
{ "😍", 0, 0x101f60d },
{ "😎", 0, 0x101f60e },
{ "😏", 0, 0x101f60f },
{ "😐", 0, 0x101f610 },
{ "😒", 0, 0x101f612 },
{ "😓", 0, 0x101f613 },
{ "😛", 0, 0x101f61b },
{ "😮", 0, 0x101f62e },
{ "😟", 0, 0x101f61f },
{ "😟", 0, 0x101f620 },
{ "😢", 0, 0x101f622 },
{ "😭", 0, 0x101f62d },
{ "😳", 0, 0x101f633 },
{ "😴", 0, 0x101f634 },
{ 0, 0, XK_Cancel },
{ ".", 0, XK_period, },
{ ":", 0, XK_colon, 26, XK_Shift_L },
{ ";", 0, XK_colon, 0 },
{ "!", 0, XK_1, 0, XK_Shift_L },
{ "?", 0, XK_slash, 0, XK_Shift_L },
{ ",", 0, XK_comma, 0 },
{ 0, 0, XK_Cancel },
{ "-", 0, XK_minus },
{ "_", 0, XK_minus, 24, XK_Shift_L },
{ "+", 0, XK_plus, 0, XK_Shift_L },
{ "/", 0, XK_slash, 0 },
{ "*", 0, XK_8, 0, XK_Shift_L },
{ "=", 0, XK_plus },
{ 0, 0, XK_Cancel },
{ "'", 0, XK_apostrophe },
{ "{", 0, XK_bracketleft, 7, XK_Shift_L },
{ "}", 0, XK_bracketright, 0, XK_Shift_L },
{ "[", 0, XK_bracketleft, 0 },
{ "]", 0, XK_bracketright, 0 },
{ "<", 0, XK_comma, 6, XK_Shift_L },
{ ">", 0, XK_period, 0, XK_Shift_L },
{ "`", 0, XK_grave, 0 },
{ "\"", 0, XK_apostrophe, 0, XK_Shift_L },
{ "'", 0, XK_apostrophe },
{ 0, 0, XK_Cancel },
};
#define LAYERS 4
static char* layer_names[LAYERS] = {
"lazy en",
"symbols",
"functions",
"dialer",
};
static Key* available_layers[LAYERS] = {
keys_lazy_en,
keys_symbols,
keys_functions,
keys_dialer,
};
Buttonmod buttonmods[] = {
{ XK_Shift_L, Button2 },
{ XK_Alt_L, Button3 },
};

View File

@ -1,68 +1,68 @@
#define KEYS 63
static Key keys_ru[] = {
{ "ёЁ", XK_Cyrillic_io, 1 },
{ "1!", XK_1, 1 },
{ "2\"", XK_2, 1 },
{ "3", XK_3, 1 },
{ "4;", XK_4, 1 },
{ "5%", XK_5, 1 },
{ "6:", XK_6, 1 },
{ "7?", XK_7, 1 },
{ "8*", XK_8, 1 },
{ "9(", XK_9, 1 },
{ "0)", XK_0, 1 },
{ "-_", XK_minus, 1 },
{ "=+", XK_plus, 1 },
{ "<-", XK_BackSpace, 2 },
{ "Del", XK_Delete, 1},
{ "ё","Ё", XK_Cyrillic_io, 1 },
{ "1","!", XK_1, 1 },
{ "2","\"", XK_2, 1 },
{ "3","", XK_3, 1 },
{ "4",";", XK_4, 1 },
{ "5","%", XK_5, 1 },
{ "6",":", XK_6, 1 },
{ "7","?", XK_7, 1 },
{ "8","*", XK_8, 1 },
{ "9","(", XK_9, 1 },
{ "0",")", XK_0, 1 },
{ "-","_", XK_minus, 1 },
{ "=","+", XK_plus, 1 },
{ "<-", 0, XK_BackSpace, 2 },
{ "Del", 0, XK_Delete, 1},
{ 0 }, /* New row */
{ "->|", XK_Tab, 1 },
{ "йЙ", XK_Cyrillic_shorti, 1 },
{ "цЦ", XK_Cyrillic_tse, 1 },
{ "уУ", XK_Cyrillic_u, 1 },
{ "кК", XK_Cyrillic_ka, 1 },
{ "еЕ", XK_Cyrillic_ie, 1 },
{ "нН", XK_Cyrillic_en, 1 },
{ "гГ", XK_Cyrillic_ghe, 1 },
{ "шШ", XK_Cyrillic_sha, 1 },
{ "щЩ", XK_Cyrillic_shcha, 1 },
{ "зЗ", XK_Cyrillic_ze, 1 },
{ "хХ", XK_Cyrillic_ha, 1 },
{ "ъЪ", XK_Cyrillic_hardsign, 1 },
{ "Return", XK_Return, 3 },
{ "->|", 0, XK_Tab, 1 },
{ "й", 0, XK_Cyrillic_shorti, 1 },
{ "ц", 0, XK_Cyrillic_tse, 1 },
{ "у", 0, XK_Cyrillic_u, 1 },
{ "к", 0, XK_Cyrillic_ka, 1 },
{ "е", 0, XK_Cyrillic_ie, 1 },
{ "н", 0, XK_Cyrillic_en, 1 },
{ "г", 0, XK_Cyrillic_ghe, 1 },
{ "ш", 0, XK_Cyrillic_sha, 1 },
{ "щ", 0, XK_Cyrillic_shcha, 1 },
{ "з", 0, XK_Cyrillic_ze, 1 },
{ "х", 0, XK_Cyrillic_ha, 1 },
{ "ъ", 0, XK_Cyrillic_hardsign, 1 },
{ "Return", 0, XK_Return, 3 },
{ 0 }, /* New row */
{ 0, XK_Caps_Lock, 2 },
{ "фФ", XK_Cyrillic_ef, 1 },
{ "ыЫ", XK_Cyrillic_yeru, 1 },
{ "вВ", XK_Cyrillic_ve, 1 },
{ "аА", XK_Cyrillic_a, 1 },
{ "пП", XK_Cyrillic_pe, 1 },
{ "рР", XK_Cyrillic_er, 1 },
{ "оО", XK_Cyrillic_o, 1 },
{ "лЛ", XK_Cyrillic_el, 1 },
{ "дД", XK_Cyrillic_de, 1 },
{ "жЖ", XK_Cyrillic_zhe, 1 },
{ "эЭ", XK_Cyrillic_e, 1 },
{ "\\/", XK_backslash, 1 },
{ 0, 0, XK_Caps_Lock, 2 },
{ "ф", 0, XK_Cyrillic_ef, 1 },
{ "ы", 0, XK_Cyrillic_yeru, 1 },
{ "в", 0, XK_Cyrillic_ve, 1 },
{ "а", 0, XK_Cyrillic_a, 1 },
{ "п", 0, XK_Cyrillic_pe, 1 },
{ "р", 0, XK_Cyrillic_er, 1 },
{ "о", 0, XK_Cyrillic_o, 1 },
{ "л", 0, XK_Cyrillic_el, 1 },
{ "д", 0, XK_Cyrillic_de, 1 },
{ "ж", 0, XK_Cyrillic_zhe, 1 },
{ "э", 0, XK_Cyrillic_e, 1 },
{ "\\","/", XK_backslash, 1 },
{ 0 }, /* New row */
{ 0, XK_Shift_L, 3 },
{ "яЯ", XK_Cyrillic_ya, 1 },
{ "чЧ", XK_Cyrillic_che, 1 },
{ "сС", XK_Cyrillic_es, 1 },
{ "мМ", XK_Cyrillic_em, 1 },
{ "иИ", XK_Cyrillic_i, 1 },
{ "тТ", XK_Cyrillic_te, 1 },
{ "ьЬ", XK_Cyrillic_softsign, 1 },
{ "бБ", XK_Cyrillic_be, 1 },
{ "юЮ", XK_Cyrillic_yu, 1 },
{ ".,", XK_period, 1 },
{ 0, XK_Shift_R, 2 },
{ 0, 0, XK_Shift_L, 3 },
{ "я", 0, XK_Cyrillic_ya, 1 },
{ "ч", 0, XK_Cyrillic_che, 1 },
{ "с", 0, XK_Cyrillic_es, 1 },
{ "м", 0, XK_Cyrillic_em, 1 },
{ "и", 0, XK_Cyrillic_i, 1 },
{ "т", 0, XK_Cyrillic_te, 1 },
{ "ь", 0, XK_Cyrillic_softsign, 1 },
{ "б", 0, XK_Cyrillic_be, 1 },
{ "ю", 0, XK_Cyrillic_yu, 1 },
{ ".", ",", XK_period, 1 },
{ 0, 0, XK_Shift_R, 2 },
{ 0 }, /* New row */
{ "Ctrl", XK_Control_L, 2 },
{ "Alt", XK_Alt_L, 2 },
{ "", XK_space, 5 },
{ "Alt", XK_Alt_R, 2 },
{ "Ctrl", XK_Control_R, 2 },
{ "Ctrl", 0, XK_Control_L, 2 },
{ "Alt", 0,XK_Alt_L, 2 },
{ "", 0,XK_space, 5 },
{ "Alt", 0,XK_Alt_R, 2 },
{ "Ctrl", 0,XK_Control_R, 2 },
};
Buttonmod buttonmods[] = {
@ -72,7 +72,7 @@ Buttonmod buttonmods[] = {
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, XK_Cancel },
{ 0, 0, XK_Cancel },
};
#define LAYERS 1

View File

@ -1,71 +1,71 @@
#define KEYS 66
static Key keys_sh[] = {
{ "`~", XK_quoteleft, 1},
{ "1!~", XK_1, 1 },
{ "2\"ˇ", XK_2, 1 },
{ "3#^", XK_3, 1 },
{ "4", XK_4, 1 },
{ "5", XK_5, 1 },
{ "6&˛", XK_6, 1 },
{ "7/`", XK_7, 1 },
{ "8", XK_8, 1 },
{ "9)'", XK_9, 1 },
{ "0", XK_0, 1 },
{ "'", XK_apostrophe, 1 },
{ "+*¸", XK_plus, 1 },
{ "<-", XK_BackSpace, 2 },
{ "Del", XK_Delete, 1},
{ "`","~", XK_quoteleft, 1},
{ "1","!~", XK_1, 1 },
{ "2","\"ˇ", XK_2, 1 },
{ "3","#^", XK_3, 1 },
{ "4","", XK_4, 1 },
{ "5","", XK_5, 1 },
{ "6","&˛", XK_6, 1 },
{ "7","/`", XK_7, 1 },
{ "8","", XK_8, 1 },
{ "9",")'", XK_9, 1 },
{ "0","", XK_0, 1 },
{ "'","", XK_apostrophe, 1 },
{ "+","*¸", XK_plus, 1 },
{ "<","-", XK_BackSpace, 2 },
{ "Del",0, XK_Delete, 1},
{ 0 }, /* New row */
{ "->|", XK_Tab, 1 },
{ "qQ\\", XK_q, 1 },
{ "wW|", XK_w, 1 },
{ "eE", XK_e, 1 },
{ "rR", XK_r, 1 },
{ "tT", XK_t, 1 },
{ "zZ", XK_z, 1 },
{ "uU", XK_u, 1 },
{ "iI", XK_i, 1 },
{ "oO", XK_o, 1 },
{ "pP", XK_p, 1 },
{ "šŠ÷", XK_scaron, 1 },
{ "đĐ×", XK_dstroke, 1 },
{ "Enter", XK_Return, 3 },
{ "->|", 0, XK_Tab, 1 },
{ "q","Q\\", XK_q, 1 },
{ "w","W|", XK_w, 1 },
{ "e","E", XK_e, 1 },
{ "r","R", XK_r, 1 },
{ "t","T", XK_t, 1 },
{ "z","Z", XK_z, 1 },
{ "u","U", XK_u, 1 },
{ "i","I", XK_i, 1 },
{ "o","O", XK_o, 1 },
{ "p","P", XK_p, 1 },
{ "š","Š÷", XK_scaron, 1 },
{ "đ","Đ×", XK_dstroke, 1 },
{ "Enter",0, XK_Return, 3 },
{ 0 }, /* New row */
{ 0, XK_Caps_Lock, 2 },
{ "aA", XK_a, 1 },
{ "sS", XK_s, 1 },
{ "dD", XK_d, 1 },
{ "fF[", XK_f, 1 },
{ "gG]", XK_g, 1 },
{ "hH", XK_h, 1 },
{ "jJ̣̣", XK_j, 1 },
{ "k", XK_k, 1 },
{ "l", XK_l, 1 },
{ "čČ", XK_ccaron, 1 },
{ "ćĆß", XK_cacute, 1 },
{ "žŽ¤", XK_zcaron, 1 },
{ 0, 0, XK_Caps_Lock, 2 },
{ "a","A", XK_a, 1 },
{ "s","S", XK_s, 1 },
{ "d","D", XK_d, 1 },
{ "f","F[", XK_f, 1 },
{ "g","G]", XK_g, 1 },
{ "h","H", XK_h, 1 },
{ "j","J̣̣", XK_j, 1 },
{ "k","", XK_k, 1 },
{ "l","", XK_l, 1 },
{ "č","Č", XK_ccaron, 1 },
{ "ć","Ćß", XK_cacute, 1 },
{ "ž","Ž¤", XK_zcaron, 1 },
{ 0 }, /* New row */
{ 0, XK_Shift_L, 2 },
{ "<>«»", XK_less, 1 },
{ "yY", XK_y, 1 },
{ "xX", XK_x, 1 },
{ "cC", XK_c, 1 },
{ "vV@", XK_v, 1 },
{ "bB{", XK_b, 1 },
{ "nN}", XK_n, 1 },
{ "m", XK_m, 1 }, /* XXX no symbol */
{ ",;", XK_comma, 1 },
{ ".:", XK_period, 1 },
{ "-_", XK_minus, 1 },
{ 0, XK_Shift_R, 2 },
{ 0, 0, XK_Shift_L, 2 },
{ "<",">«»", XK_less, 1 },
{ "y","Y", XK_y, 1 },
{ "x","X", XK_x, 1 },
{ "c","C", XK_c, 1 },
{ "v","V@", XK_v, 1 },
{ "b","B{", XK_b, 1 },
{ "n","N}", XK_n, 1 },
{ "m","", XK_m, 1 }, /* XXX no symbol */
{ ",",";", XK_comma, 1 },
{ ".",":", XK_period, 1 },
{ "-","_", XK_minus, 1 },
{ 0, 0, XK_Shift_R, 2 },
{ 0 }, /* New row */
{ "Ctrl", XK_Control_L, 2 },
{ "Win", XK_Super_L, 2 },
{ "Alt", XK_Alt_L, 2 },
{ "", XK_space, 5 },
{ "Alt Gr", XK_ISO_Level3_Shift, 2 },
{ "Menu", XK_Menu, 2 },
{ "Ctrl", XK_Control_R, 2 },
{ "Ctrl", 0, XK_Control_L, 2 },
{ "Win", 0, XK_Super_L, 2 },
{ "Alt", 0, XK_Alt_L, 2 },
{ "", 0, XK_space, 5 },
{ "Alt Gr", 0, XK_ISO_Level3_Shift, 2 },
{ "Menu", 0, XK_Menu, 2 },
{ "Ctrl", 0, XK_Control_R, 2 },
};
Buttonmod buttonmods[] = {
@ -75,7 +75,7 @@ Buttonmod buttonmods[] = {
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, XK_Cancel },
{ 0, 0, XK_Cancel },
};
#define LAYERS 1

88
layout.sr.h Normal file
View File

@ -0,0 +1,88 @@
#define KEYS 66
static Key keys_sr[] = {
{ "`","~", XK_quoteleft, 1},
{ "1","!", XK_1, 1 },
{ "2","\"", XK_2, 1 },
{ "3","#", XK_3, 1 },
{ "4","$", XK_4, 1 },
{ "5","%", XK_5, 1 },
{ "6","&", XK_6, 1 },
{ "7","/", XK_7, 1 },
{ "8","(", XK_8, 1 },
{ "9",")", XK_9, 1 },
{ "0","=", XK_0, 1 },
{ "'","?", XK_apostrophe, 1 },
{ "+","*", XK_plus, 1 },
{ "<-",0, XK_BackSpace, 2 },
{ "Del",0, XK_Delete, 1},
{ 0 }, /* New row */
{ "->|", 0, XK_Tab, 1 },
{ "љ","Љ", XK_Cyrillic_lje, 1 },
{ "њ","Њ", XK_Cyrillic_nje, 1 },
{ "е","Е", XK_Cyrillic_ie, 1 },
{ "р","Р", XK_Cyrillic_er, 1 },
{ "т","Т", XK_Cyrillic_te, 1 },
{ "з","З", XK_Cyrillic_ze, 1 },
{ "у","У", XK_Cyrillic_u, 1 },
{ "и","И", XK_Cyrillic_i, 1 },
{ "о","О", XK_Cyrillic_o, 1 },
{ "п","П", XK_Cyrillic_pe, 1 },
{ "ш","Ш", XK_Cyrillic_sha, 1 },
{ "ђ","Ђ", XK_Serbian_dje, 1 },
{ "Enter",0, XK_Return, 3 },
{ 0 }, /* New row */
{ 0, 0, XK_Caps_Lock, 2 },
{ "а","А", XK_Cyrillic_a, 1 },
{ "с","С", XK_Cyrillic_es, 1 },
{ "д","Д", XK_Cyrillic_de, 1 },
{ "ф","Ф", XK_Cyrillic_ef, 1 },
{ "г","Г", XK_Cyrillic_ghe, 1 },
{ "х","Х", XK_Cyrillic_ha, 1 },
{ "j","J̣̣", XK_Cyrillic_je, 1 },
{ "к","К", XK_Cyrillic_ka, 1 },
{ "л","Л", XK_Cyrillic_el, 1 },
{ "ч","Ч", XK_Cyrillic_che, 1 },
{ "ћ","Ћ", XK_Serbian_tshe, 1 },
{ "ж","Ж", XK_Cyrillic_zhe, 1 },
{ 0 }, /* New row */
{ 0, 0, XK_Shift_L, 2 },
{ "<",">", XK_less, 1 },
{ "ѕ","Ѕ", XK_Serbian_dze, 1 },
{ "џ","Џ", XK_Cyrillic_dzhe, 1 },
{ "ц","Ц", XK_Cyrillic_tse, 1 },
{ "в","В", XK_Cyrillic_ve, 1 },
{ "б","Б", XK_Cyrillic_be, 1 },
{ "н","Н", XK_Cyrillic_en, 1 },
{ "м","М", XK_Cyrillic_em, 1 },
{ ",",";", XK_comma, 1 },
{ ".",":", XK_period, 1 },
{ "-","_", XK_minus, 1 },
{ 0, 0, XK_Shift_R, 2 },
{ 0 }, /* New row */
{ "Ctrl", 0, XK_Control_L, 2 },
{ "Win", 0, XK_Super_L, 2 },
{ "Alt", 0, XK_Alt_L, 2 },
{ "", 0, XK_space, 5 },
{ "Alt Gr", 0, XK_ISO_Level3_Shift, 2 },
{ "Menu", 0, XK_Menu, 2 },
{ "Ctrl", 0, XK_Control_R, 2 },
};
Buttonmod buttonmods[] = {
{ XK_Shift_L, Button2 },
{ XK_Alt_L, Button3 },
};
#define OVERLAYS 1
static Key overlay[OVERLAYS] = {
{ 0, 0, XK_Cancel },
};
#define LAYERS 1
static char* layer_names[LAYERS] = {
"sr",
};
static Key* available_layers[LAYERS] = {
keys_sr,
};

48
svkbd.1
View File

@ -1,4 +1,4 @@
.Dd August 4, 2020
.Dd March 15, 2021
.Dt SVKBD 1
.Os
.Sh NAME
@ -41,11 +41,17 @@ One row of keys takes up 1/heighfactor of the screen's total height.
Comma separated list of layers to enable (by name). If not set, all layers
in the layout will be available.
The layer names are defined by the layout you compiled.
.It Fl n
Do not simulate key presses for X
.It Fl R
Disable press-on-release
.It Fl s Ar layer
The layer to show on program start-up (by name). If not set, the first
layer of the layout will be shown.
.It Fl O
Disable overlay functionality.
.It Fl o
Print pressed keys to standard output
.It Fl v
Show the version information.
.El
@ -63,6 +69,44 @@ Set this to 0 if you want to disable overlay functionality.
Affects the vertical space taken by the keyboard.
One row of keys takes up 1/heighfactor of the screen's total height.
.El
.Sh XRESOURCES
The appearance of svkbd can be configured via xresources:
.Bl -tag -width Ds
.It Ev svkbd.font
An Xft font specification like "Monospace:bold:size=20".
.It Ev svkbd.background
The background colour for the keycaps (in #rrggbb syntax)
.It Ev svkbd.foreground
The foreground colour for the keycaps (in #rrggbb syntax)
.It Ev svkbd.shiftforeground
The foreground colour for the secondary labels (shift layer) on the keycaps
.It Ev svkbd.shiftbackground
The background colour for the secondary labels (shift layer) on the keycaps
.It Ev svkbd.abcforeground
.It Ev svkbd.abcbackbround
The colour for alphabetical keys
.It Ev svkbd.abcshiftbackground
.It Ev svkbd.abcshiftforeground
The colour for the secondary labels (shift layer) on alphabetical keys
.It Ev svkbd.pressforeground
.It Ev svkbd.pressforebackground
The colour for keys when held pressed
.It Ev svkbd.highlightforeground
.It Ev svkbd.highlightforebackground
The colour for keys when hovering over them or just after release
.It Ev svkbd.highlightshiftforeground
.It Ev svkbd.highlightshiftforebackground
The colour for the secondary label on keys when hovering over them or just
after release
.It Ev svkbd.overlayforeground
.It Ev svkbd.overlaybackground
The colour for keys when they are part of an overlay
.It Ev svkbd.overlayshiftforeground
.It Ev svkbd.overlayshiftbackground
The colour for the secondary label on keys when they are part of an overlay
.El
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr XParseGeometry 3
.Sh AUTHORS
@ -70,3 +114,5 @@ One row of keys takes up 1/heighfactor of the screen's total height.
.An Enno Boland Aq Mt gottox@s01.de
.An Miles Alan Aq Mt m@milesalan.com
.An Maarten van Gompel Aq Mt proycon@anaproy.nl
.An Tetrakist Aq Mt tetrakist@mutandum.com
.An Stacy Aq Mt stacy@stacyharper.net

556
svkbd.c
View File

@ -2,12 +2,13 @@
#include <sys/select.h>
#include <sys/time.h>
#include <ctype.h>
#include <locale.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
@ -20,6 +21,7 @@
#include <X11/Xproto.h>
#include <X11/extensions/XTest.h>
#include <X11/Xft/Xft.h>
#include <X11/Xresource.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif
@ -29,21 +31,28 @@
/* macros */
#define LENGTH(x) (sizeof x / sizeof x[0])
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)))
#define STRINGTOKEYSYM(X) (XStringToKeySym(X))
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)))
/* enums */
enum { SchemeNorm, SchemePress, SchemeHighlight, SchemeLast };
enum {
SchemeNorm, SchemeNormABC, SchemeNormABCShift, SchemeNormShift, SchemePress,
SchemePressShift, SchemeHighlight, SchemeHighlightShift, SchemeOverlay,
SchemeOverlayShift, SchemeWindow, SchemeLast
};
enum { NetWMWindowType, NetLast };
/* typedefs */
typedef struct {
char *label;
char *label2;
KeySym keysym;
unsigned int width;
double width;
KeySym modifier;
int x, y, w, h;
Bool pressed;
Bool highlighted;
Bool isoverlay;
} Key;
typedef struct {
@ -61,11 +70,11 @@ static void configurenotify(XEvent *e);
static void countrows();
static int countkeys(Key *layer);
static void drawkeyboard(void);
static void drawkey(Key *k);
static void drawkey(Key *k, Bool map);
static void expose(XEvent *e);
static Key *findkey(int x, int y);
static void leavenotify(XEvent *e);
static void press(Key *k, KeySym mod);
static void press(Key *k, KeySym buttonmod);
static double get_press_duration();
static void run(void);
static void setup(void);
@ -76,8 +85,9 @@ static void hideoverlay();
static void cyclelayer();
static void setlayer();
static void togglelayer();
static void unpress(Key *k, KeySym mod);
static void unpress(Key *k, KeySym buttonmod);
static void updatekeys();
static void printkey(Key *k, KeySym mod);
/* variables */
static int screen;
@ -95,20 +105,25 @@ static Drw *drw;
static Window root, win;
static Clr* scheme[SchemeLast];
static Bool running = True, isdock = False;
static KeySym pressedmod = 0;
static struct timeval pressbegin;
static int currentlayer = 0;
static int enableoverlays = 1;
static int currentoverlay = -1; /* -1 = no overlay */
static int pressonrelease = 1;
static KeySym overlaykeysym = 0; /* keysym for which the overlay is presented */
static int releaseprotect = 0; /* set to 1 after overlay is shown, protecting against immediate release */
static int tmp_keycode = 1;
static int rows = 0, ww = 0, wh = 0, wx = 0, wy = 0;
static int simulateoutput = 1; /* simulate key presses for X */
static int printoutput = 0; /* print key pressed to stdout */
static char *name = "svkbd";
static int debug = 0;
static int numlayers = 0;
static int numkeys = 0;
static char *colors[11][2]; /* 11 schemes, 2 colors each */
static char *fonts[] = { 0 };
static KeySym ispressingkeysym;
Bool ispressing = False;
@ -121,14 +136,16 @@ Bool sigtermd = False;
#endif
#include LAYOUT
static Key keys[KEYS] = { NULL };
static Key* layers[LAYERS];
static Key keys[KEYS];
static Key *layers[LAYERS];
void
motionnotify(XEvent *e)
{
XPointerMovedEvent *ev = &e->xmotion;
int i;
int lostfocus = -1;
int gainedfocus = -1;
for (i = 0; i < numkeys; i++) {
if (keys[i].keysym && ev->x > keys[i].x
@ -137,25 +154,36 @@ motionnotify(XEvent *e)
&& ev->y < keys[i].y + keys[i].h) {
if (keys[i].highlighted != True) {
if (ispressing) {
keys[i].pressed = True;
gainedfocus = i;
} else {
keys[i].highlighted = True;
}
drawkey(&keys[i]);
drawkey(&keys[i], True);
}
continue;
}
if (!IsModifierKey(keys[i].keysym) && keys[i].pressed == True) {
unpress(&keys[i], 0);
drawkey(&keys[i]);
}
if (keys[i].highlighted == True) {
} else if (keys[i].highlighted == True) {
keys[i].highlighted = False;
drawkey(&keys[i]);
drawkey(&keys[i], True);
}
}
for (i = 0; i < numkeys; i++) {
if (!IsModifierKey(keys[i].keysym) && keys[i].pressed == True &&
lostfocus != gainedfocus) {
printdbg("Pressed key lost focus: %ld\n", keys[i].keysym);
lostfocus = i;
ispressingkeysym = 0;
keys[i].pressed = 0;
drawkey(&keys[i], True);
}
}
if ((lostfocus != -1) && (gainedfocus != -1) && (lostfocus != gainedfocus)) {
printdbg("Clicking new key that gained focus\n");
press(&keys[gainedfocus], 0);
keys[gainedfocus].pressed = True;
keys[gainedfocus].highlighted = True;
}
}
void
@ -168,14 +196,23 @@ buttonpress(XEvent *e)
ispressing = True;
if (!(k = findkey(ev->x, ev->y)))
return;
for (i = 0; i < LENGTH(buttonmods); i++) {
if (ev->button == buttonmods[i].button) {
mod = buttonmods[i].mod;
break;
}
}
if ((k = findkey(ev->x, ev->y)))
press(k, mod);
if (k->modifier) {
if (mod == k->modifier)
mod = 0;
else
mod = k->modifier;
}
press(k, mod);
}
void
@ -197,8 +234,12 @@ buttonrelease(XEvent *e)
if (ev->x < 0 || ev->y < 0) {
unpress(NULL, mod);
} else {
if ((k = findkey(ev->x, ev->y)))
} else if ((k = findkey(ev->x, ev->y))) {
if (k->modifier == mod)
unpress(k, 0);
else if (k->modifier)
unpress(k, k->modifier);
else
unpress(k, mod);
}
}
@ -213,7 +254,6 @@ cleanup(void)
drw_sync(drw);
drw_free(drw);
XSync(dpy, False);
drw_free(drw);
XDestroyWindow(dpy, win);
XSync(dpy, False);
XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
@ -238,8 +278,13 @@ countrows(void)
int i;
for (i = 0, rows = 1; i < numkeys; i++) {
if (keys[i].keysym == 0)
if (keys[i].keysym == 0) {
rows++;
if ((i > 0) && (keys[i-1].keysym == 0)) {
rows--;
break;
}
}
}
}
@ -264,26 +309,38 @@ drawkeyboard(void)
{
int i;
drw_setscheme(drw, scheme[SchemeWindow]);
drw_rect(drw, 0, 0, ww, wh, 1, 1);
for (i = 0; i < numkeys; i++) {
if (keys[i].keysym != 0)
drawkey(&keys[i]);
drawkey(&keys[i], False);
}
drw_map(drw, win, 0, 0, ww, wh);
}
void
drawkey(Key *k)
drawkey(Key *k, Bool map)
{
int x, y, w, h;
const char *l;
int use_scheme = SchemeNorm;
if (k->pressed)
drw_setscheme(drw, scheme[SchemePress]);
use_scheme = SchemePress;
else if (k->highlighted)
drw_setscheme(drw, scheme[SchemeHighlight]);
use_scheme = SchemeHighlight;
else if (k->isoverlay)
use_scheme = SchemeOverlay;
else if ((k->keysym == XK_Return) ||
((k->keysym >= XK_a) && (k->keysym <= XK_z)) ||
((k->keysym >= XK_Cyrillic_io) && (k->keysym <= XK_Cyrillic_hardsign)))
use_scheme = SchemeNormABC;
else
drw_setscheme(drw, scheme[SchemeNorm]);
use_scheme = SchemeNorm;
drw_setscheme(drw, scheme[use_scheme]);
drw_rect(drw, k->x, k->y, k->w, k->h, 1, 1);
drw_rect(drw, k->x, k->y, k->w, k->h, 0, 0);
if (k->keysym == XK_KP_Insert) {
if (enableoverlays) {
@ -301,7 +358,26 @@ drawkey(Key *k)
w = TEXTW(l);
x = k->x + (k->w / 2) - (w / 2);
drw_text(drw, x, y, w, h, 0, l, 0);
drw_map(drw, win, k->x, k->y, k->w, k->h);
if (k->label2) {
if (use_scheme == SchemeNorm)
use_scheme = SchemeNormShift;
else if (use_scheme == SchemeNormABC)
use_scheme = SchemeNormABCShift;
else if (use_scheme == SchemePress)
use_scheme = SchemePressShift;
else if (use_scheme == SchemeHighlight)
use_scheme = SchemeHighlightShift;
else if (use_scheme == SchemeOverlay)
use_scheme = SchemeOverlayShift;
drw_setscheme(drw, scheme[use_scheme]);
x += w;
y -= 15;
l = k->label2;
w = TEXTW(l);
drw_text(drw, x, y, w, h, 0, l, 0);
}
if (map)
drw_map(drw, win, k->x, k->y, k->w, k->h);
}
void
@ -335,9 +411,9 @@ hasoverlay(KeySym keysym)
begin = 0;
for (i = 0; i < OVERLAYS; i++) {
if (overlay[i].keysym == XK_Cancel) {
begin = i+1;
begin = i + 1;
} else if (overlay[i].keysym == keysym) {
return begin+1;
return begin + 1;
}
}
return -1;
@ -348,6 +424,7 @@ leavenotify(XEvent *e)
{
if (currentoverlay != -1)
hideoverlay();
ispressingkeysym = 0;
unpress(NULL, 0);
}
@ -360,14 +437,14 @@ record_press_begin(KeySym ks)
}
void
press(Key *k, KeySym mod)
press(Key *k, KeySym buttonmod)
{
int i;
int overlayidx = -1;
k->pressed = !k->pressed;
if (debug) printdbg("Begin press: %ld\n", k->keysym);
printdbg("Begin click: %ld\n", k->keysym);
pressbegin.tv_sec = 0;
pressbegin.tv_usec = 0;
ispressingkeysym = 0;
@ -375,23 +452,21 @@ press(Key *k, KeySym mod)
if (!IsModifierKey(k->keysym)) {
if (enableoverlays && currentoverlay == -1)
overlayidx = hasoverlay(k->keysym);
if (enableoverlays && overlayidx != -1) {
if (!pressbegin.tv_sec && !pressbegin.tv_usec) {
/*record the begin of the press, don't simulate the actual keypress yet */
record_press_begin(k->keysym);
}
if ((pressonrelease) || (enableoverlays && overlayidx != -1)) {
/* record the begin of the press, don't simulate the actual keypress yet */
record_press_begin(k->keysym);
} else {
if (debug) printdbg("Simulating press: %ld\n", k->keysym);
printdbg("Simulating press: %ld (mod %ld)\n", k->keysym, buttonmod);
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed && IsModifierKey(keys[i].keysym)) {
simulate_keypress(keys[i].keysym);
}
}
pressedmod = mod;
if (pressedmod) {
simulate_keypress(mod);
}
if (buttonmod)
simulate_keypress(buttonmod);
simulate_keypress(k->keysym);
if (printoutput)
printkey(k, buttonmod);
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed && IsModifierKey(keys[i].keysym)) {
@ -400,22 +475,79 @@ press(Key *k, KeySym mod)
}
}
}
drawkey(k);
drawkey(k, True);
}
int
tmp_remap(KeySym keysym)
{
XChangeKeyboardMapping(dpy, tmp_keycode, 1, &keysym, 1);
/* map lower and upper case of keysym to the temporary keycode */
KeySym syms[2];
XConvertCase(keysym, &syms[0], &syms[1]);
/* if keysym is capital letter then swap upper and lower case */
if (keysym == syms[1])
syms[1] = syms[0], syms[0] = keysym;
XChangeKeyboardMapping(dpy, tmp_keycode, syms[0] == syms[1] ? 1 : 2, syms, 1);
XSync(dpy, False);
printdbg("Temporary map keysym %ld (%ld, %ld) to keycode %d\n", keysym, syms[0], syms[1], tmp_keycode);
return tmp_keycode;
}
void
printkey(Key *k, KeySym mod)
{
int i, shift;
shift = (mod == XK_Shift_L) || (mod == XK_Shift_R) || (mod == XK_Shift_Lock);
if (!shift) {
for (i = 0; i < numkeys; i++) {
if ((keys[i].pressed) && ((keys[i].keysym == XK_Shift_L) ||
(keys[i].keysym == XK_Shift_R) || (keys[i].keysym == XK_Shift_Lock))) {
shift = True;
break;
}
}
}
printdbg("Printing key %ld (shift=%d)\n", k->keysym, shift);
if (k->keysym == XK_Cancel)
return;
KeySym *keysym = &(k->keysym);
XIM xim = XOpenIM(dpy, 0, 0, 0);
XIC xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, NULL);
XKeyPressedEvent event;
event.type = KeyPress;
event.display = dpy;
event.state = shift ? ShiftMask : 0;
event.keycode = XKeysymToKeycode(dpy, *keysym);
if (event.keycode == 0)
event.keycode = tmp_remap(*keysym);
char buffer[32];
KeySym ignore;
Status return_status;
int l = Xutf8LookupString(xic, &event, buffer, sizeof(buffer), &ignore, &return_status);
buffer[l] = '\0';
printdbg("Print buffer: [%s] (length=%d)\n", &buffer, l);
printf("%s", buffer);
XDestroyIC(xic);
XCloseIM(xim);
}
void
simulate_keypress(KeySym keysym)
{
KeyCode code = XKeysymToKeycode(dpy, keysym);
KeyCode code;
if (!simulateoutput)
return;
code = XKeysymToKeycode(dpy, keysym);
if (code == 0)
code = tmp_remap(keysym);
XTestFakeKeyEvent(dpy, code, True, 0);
@ -424,7 +556,12 @@ simulate_keypress(KeySym keysym)
void
simulate_keyrelease(KeySym keysym)
{
KeyCode code = XKeysymToKeycode(dpy, keysym);
KeyCode code;
if (!simulateoutput)
return;
code = XKeysymToKeycode(dpy, keysym);
if (code == 0)
code = tmp_remap(keysym);
XTestFakeKeyEvent(dpy, code, False, 0);
@ -438,16 +575,17 @@ get_press_duration(void)
gettimeofday(&now, NULL);
return (double) ((now.tv_sec * 1000000L + now.tv_usec) -
(pressbegin.tv_sec * 1000000L + pressbegin.tv_usec)) /
(double) 1000000L;
(pressbegin.tv_sec * 1000000L + pressbegin.tv_usec)) /
(double) 1000000L;
}
void
unpress(Key *k, KeySym mod)
unpress(Key *k, KeySym buttonmod)
{
int i;
Bool neutralizebuttonmod = False;
if (k != NULL) {
if (k) {
switch(k->keysym) {
case XK_Cancel:
cyclelayer();
@ -466,62 +604,57 @@ unpress(Key *k, KeySym mod)
}
}
if ((pressbegin.tv_sec || pressbegin.tv_usec) && enableoverlays && k && k->keysym == ispressingkeysym) {
if (currentoverlay == -1) {
if (get_press_duration() < overlay_delay) {
if (debug) printdbg("Delayed simulation of press after release: %ld\n", k->keysym);
/* simulate the press event, as we postponed it earlier in press() */
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed && IsModifierKey(keys[i].keysym)) {
simulate_keypress(keys[i].keysym);
}
}
pressedmod = mod;
if (pressedmod) {
simulate_keypress(mod);
}
simulate_keypress(k->keysym);
pressbegin.tv_sec = 0;
pressbegin.tv_usec = 0;
} else {
return;
if ((pressbegin.tv_sec || pressbegin.tv_usec) && (enableoverlays || pressonrelease) && k && k->keysym == ispressingkeysym) {
printdbg("Delayed simulation of press after release: %ld\n", k->keysym);
/* simulate the press event, as we postponed it earlier in press() */
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed && IsModifierKey(keys[i].keysym)) {
if (keys[i].keysym == buttonmod)
neutralizebuttonmod = True;
else
simulate_keypress(keys[i].keysym);
}
}
}
if (debug) {
if (k) {
printdbg("Simulation of release: %ld\n", k->keysym);
} else {
printdbg("Simulation of release (all keys)\n");
if (buttonmod && !neutralizebuttonmod) {
simulate_keypress(buttonmod);
}
simulate_keypress(k->keysym);
pressbegin.tv_sec = 0;
pressbegin.tv_usec = 0;
}
if (k)
printdbg("Simulation of release: %ld\n", k->keysym);
else
printdbg("Simulation of release (all keys)\n");
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
simulate_keyrelease(keys[i].keysym);
if (printoutput)
printkey(&keys[i], buttonmod);
keys[i].pressed = 0;
drawkey(&keys[i]);
break;
drawkey(&keys[i], True);
}
}
if (i != numkeys) {
if (pressedmod) {
simulate_keyrelease(mod);
}
pressedmod = 0;
if (buttonmod && !neutralizebuttonmod) {
simulate_keyrelease(buttonmod);
}
if (k == NULL || !IsModifierKey(k->keysym)) {
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed) {
simulate_keyrelease(keys[i].keysym);
if (keys[i].pressed && IsModifierKey(keys[i].keysym)) {
if (!(keys[i].keysym == buttonmod && neutralizebuttonmod))
simulate_keyrelease(keys[i].keysym);
keys[i].pressed = 0;
drawkey(&keys[i]);
drawkey(&keys[i], True);
}
}
}
if (enableoverlays && currentoverlay != -1) {
if (enableoverlays && currentoverlay != -1 &&
(k == NULL || !IsModifierKey(k->keysym))) {
if (releaseprotect) {
releaseprotect = 0;
} else {
@ -537,12 +670,13 @@ run(void)
int xfd;
fd_set fds;
struct timeval tv;
double duration = 0.0;
double duration;
int overlayidx;
int i, r;
xfd = ConnectionNumber(dpy);
tv.tv_sec = 1;
tv.tv_usec = 0;
tv.tv_sec = 0;
tv.tv_usec = scan_rate;
XFlush(dpy);
@ -562,25 +696,33 @@ run(void)
/* time-out expired without anything interesting happening, check for long-presses */
if (ispressing && ispressingkeysym) {
duration = get_press_duration();
if (debug == 2) printdbg("%f\n", duration);
if (get_press_duration() >= overlay_delay) {
if (debug) printdbg("press duration %f\n", duration);
showoverlay(hasoverlay(ispressingkeysym));
if (debug >= 2)
printdbg("%f\n", duration);
overlayidx = hasoverlay(ispressingkeysym);
duration = get_press_duration();
if (overlayidx != -1 && duration >= overlay_delay) {
printdbg("press duration %f, activating overlay\n", duration);
showoverlay(overlayidx);
pressbegin.tv_sec = 0;
pressbegin.tv_usec = 0;
ispressingkeysym = 0;
} else if ((overlayidx == -1) && (duration >= repeat_delay)) {
printdbg("press duration %f, activating repeat\n", duration);
simulate_keyrelease(ispressingkeysym);
simulate_keypress(ispressingkeysym);
XSync(dpy, False);
}
}
}
if (r == -1 || sigtermd) {
/* an error occurred or we received a signal */
/* E.g. Generally in scripts we want to call SIGTERM on svkbd in which case
if the user is holding for example the enter key (to execute
the kill or script that does the kill), that causes an issue
since then X doesn't know the keyup is never coming.. (since
process will be dead before finger lifts - in that case we
just trigger out fake up presses for all keys */
if (debug) printdbg("signal received, releasing all keys");
if the user is holding for example the enter key (to execute
the kill or script that does the kill), that causes an issue
since then X doesn't know the keyup is never coming.. (since
process will be dead before finger lifts - in that case we
just trigger out fake up presses for all keys */
printdbg("signal received, releasing all keys");
for (i = 0; i < numkeys; i++) {
XTestFakeKeyEvent(dpy, XKeysymToKeycode(dpy, keys[i].keysym), False, 0);
}
@ -589,6 +731,80 @@ run(void)
}
}
void
readxresources(void)
{
XrmDatabase xdb;
XrmValue xval;
char *type, *xrm;
XrmInitialize();
if ((xrm = XResourceManagerString(drw->dpy))) {
xdb = XrmGetStringDatabase(xrm);
if (XrmGetResource(xdb, "svkbd.font", "*", &type, &xval) && !fonts[0])
fonts[0] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.background", "*", &type, &xval) && !colors[SchemeNorm][ColBg])
colors[SchemeNorm][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.foreground", "*", &type, &xval) && !colors[SchemeNorm][ColFg])
colors[SchemeNorm][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.shiftforeground", "*", &type, &xval) && !colors[SchemeNormShift][ColFg])
colors[SchemeNormShift][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.shiftbackground", "*", &type, &xval) && !colors[SchemeNormShift][ColBg])
colors[SchemeNormShift][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.ABCforeground", "*", &type, &xval) && !colors[SchemeNormABC][ColFg])
colors[SchemeNormABC][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.ABCbackground", "*", &type, &xval) && !colors[SchemeNormABC][ColBg])
colors[SchemeNormABC][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.ABCshiftforeground", "*", &type, &xval) && !colors[SchemeNormABCShift][ColFg])
colors[SchemeNormABCShift][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.ABCshiftbackground", "*", &type, &xval) && !colors[SchemeNormABCShift][ColBg])
colors[SchemeNormABCShift][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.pressbackground", "*", &type, &xval) && !colors[SchemePress][ColBg])
colors[SchemePress][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.pressforeground", "*", &type, &xval) && !colors[SchemePress][ColFg])
colors[SchemePress][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.pressshiftbackground", "*", &type, &xval) && !colors[SchemePressShift][ColBg])
colors[SchemePressShift][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.pressshiftforeground", "*", &type, &xval) && !colors[SchemePressShift][ColFg])
colors[SchemePressShift][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.highlightbackground", "*", &type, &xval) && !colors[SchemeHighlight][ColBg])
colors[SchemeHighlight][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.highlightforeground", "*", &type, &xval) && !colors[SchemeHighlight][ColFg])
colors[SchemeHighlight][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.highlightshiftbackground", "*", &type, &xval) && !colors[SchemeHighlightShift][ColBg])
colors[SchemeHighlightShift][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.highlightshiftforeground", "*", &type, &xval) && !colors[SchemeHighlightShift][ColFg])
colors[SchemeHighlightShift][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.overlaybackground", "*", &type, &xval) && !colors[SchemeOverlay][ColBg])
colors[SchemeOverlay][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.overlayforeground", "*", &type, &xval) && !colors[SchemeOverlay][ColFg])
colors[SchemeOverlay][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.overlayshiftbackground", "*", &type, &xval) && !colors[SchemeOverlayShift][ColBg])
colors[SchemeOverlayShift][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.overlayshiftforeground", "*", &type, &xval) && !colors[SchemeOverlayShift][ColFg])
colors[SchemeOverlayShift][ColFg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.windowbackground", "*", &type, &xval) && !colors[SchemeWindow][ColBg])
colors[SchemeWindow][ColBg] = estrdup(xval.addr);
if (XrmGetResource(xdb, "svkbd.windowforeground", "*", &type, &xval) && !colors[SchemeWindow][ColFg])
colors[SchemeWindow][ColFg] = estrdup(xval.addr);
XrmDestroyDatabase(xdb);
}
}
void
setup(void)
{
@ -620,8 +836,23 @@ setup(void)
sh = DisplayHeight(dpy, screen);
}
drw = drw_create(dpy, screen, root, sw, sh);
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
readxresources();
/* Apply defaults to font and colors*/
if (!fonts[0])
fonts[0] = estrdup(defaultfonts[0]);
for (i = 0; i < SchemeLast; ++i) {
for (j = 0; j < 2; ++j) {
if (!colors[i][j])
colors[i][j] = estrdup(defaultcolors[i][j]);
}
}
if (!drw_fontset_create(drw, (const char **) fonts, LENGTH(fonts)))
die("no fonts could be loaded");
free(fonts[0]);
drw_setscheme(drw, scheme[SchemeNorm]);
/* find an unused keycode to use as a temporary keycode (derived from source:
@ -652,7 +883,12 @@ setup(void)
/* init appearance */
for (j = 0; j < SchemeLast; j++)
scheme[j] = drw_scm_create(drw, colors[j], 2);
scheme[j] = drw_scm_create(drw, (const char **) colors[j], 2);
for (j = 0; j < SchemeLast; ++j) {
free(colors[j][ColFg]);
free(colors[j][ColBg]);
}
/* init atoms */
if (isdock) {
@ -705,8 +941,7 @@ setup(void)
ch->res_class = name;
ch->res_name = name;
XSetWMProperties(dpy, win, &str, &str, NULL, 0, sizeh, wmh,
ch);
XSetWMProperties(dpy, win, &str, &str, NULL, 0, sizeh, wmh, ch);
XFree(keysyms);
XFree(ch);
@ -731,18 +966,21 @@ void
updatekeys(void)
{
int i, j;
int x = 0, y = 0, h, base, r = rows;
double base;
int x, y = 0, h, r = rows;
h = (wh - 1) / rows;
for (i = 0; i < numkeys; i++, r--) {
for (j = i, base = 0; j < numkeys && keys[j].keysym != 0; j++)
base += keys[j].width;
for (x = 0; i < numkeys && keys[i].keysym != 0; i++) {
keys[i].x = x;
keys[i].y = y;
keys[i].w = keys[i].width * (ww - 1) / base;
keys[i].x = x + xspacing;
keys[i].y = y + yspacing;
keys[i].w = keys[i].width * ww / base;
keys[i].h = r == 1 ? wh - y - 1 : h;
x += keys[i].w;
keys[i].w = keys[i].w - (xspacing * 2);
keys[i].h = keys[i].h - (yspacing * 2);
}
if (base != 0)
keys[i - 1].w = ww - 1 - keys[i - 1].x;
@ -753,15 +991,19 @@ updatekeys(void)
void
usage(char *argv0)
{
fprintf(stderr, "usage: %s [-hdvDO] [-g geometry] [-fn font] [-l layers] [-s initial_layer]\n", argv0);
fprintf(stderr, "usage: %s [-hdnovDOR] [-g geometry] [-fn font] [-l layers] [-s initial_layer]\n", argv0);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -d - Set Dock Window Type\n");
fprintf(stderr, " -D - Enable debug\n");
fprintf(stderr, " -O - Disable overlays\n");
fprintf(stderr, " -R - Disable press-on-release\n");
fprintf(stderr, " -n - Do not simulate key presses for X\n");
fprintf(stderr, " -o - Print to standard output\n");
fprintf(stderr, " -l - Comma separated list of layers to enable\n");
fprintf(stderr, " -s - Layer to select on program start\n");
fprintf(stderr, " -H [int] - Height fraction, one key row takes 1/x of the screen height");
fprintf(stderr, " -H [int] - Height fraction, one key row takes 1/x of the screen height\n");
fprintf(stderr, " -fn [font] - Set font (Xft, e.g: DejaVu Sans:bold:size=20)\n");
fprintf(stderr, " -g - Set the window position or size using the X geometry format\n");
exit(1);
}
@ -770,6 +1012,7 @@ setlayer(void)
{
numkeys = countkeys(layers[currentlayer]);
memcpy(&keys, layers[currentlayer], sizeof(Key) * numkeys);
countrows();
}
void
@ -778,7 +1021,7 @@ cyclelayer(void)
currentlayer++;
if (currentlayer >= numlayers)
currentlayer = 0;
if (debug) printdbg("Cycling to layer %d\n", currentlayer);
printdbg("Cycling to layer %d\n", currentlayer);
setlayer();
updatekeys();
drawkeyboard();
@ -792,7 +1035,7 @@ togglelayer(void)
} else if (numlayers > 1) {
currentlayer = 1;
}
if (debug) printdbg("Toggling layer %d\n", currentlayer);
printdbg("Toggling layer %d\n", currentlayer);
setlayer();
updatekeys();
drawkeyboard();
@ -801,25 +1044,40 @@ togglelayer(void)
void
showoverlay(int idx)
{
if (debug) printdbg("Showing overlay %d\n", idx);
int i,j;
int i, j;
printdbg("Showing overlay %d\n", idx);
/* unpress existing key (visually only) */
for (i = 0; i < numkeys; i++) {
if (keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
keys[i].pressed = 0;
drawkey(&keys[i]);
drawkey(&keys[i], True);
break;
}
}
for (i = idx, j=0; i < OVERLAYS; i++, j++) {
if (overlay[i].keysym == XK_Cancel)
for (i = idx, j = 0; i < OVERLAYS; i++, j++) {
if (overlay[i].keysym == XK_Cancel) {
break;
while (keys[j].keysym == 0)
}
/* certain modifier keys and basic keys are excluded from being overlayed: */
while (keys[j].keysym == 0 || keys[j].keysym == XK_Shift_L ||
keys[j].keysym == XK_Shift_R || keys[j].keysym == XK_Control_L ||
keys[j].keysym == XK_Control_R || keys[j].keysym == XK_Alt_L ||
keys[j].keysym == XK_Alt_R || keys[j].keysym == XK_BackSpace ||
keys[j].keysym == XK_Return || keys[j].keysym == XK_space ||
keys[j].keysym == XK_Cancel)
j++;
if (overlay[i].width > 1)
j += overlay[i].width - 1;
if (j >= numkeys)
break;
keys[j].label = overlay[i].label;
keys[j].label2 = overlay[i].label2;
keys[j].keysym = overlay[i].keysym;
keys[j].modifier = overlay[i].modifier;
keys[j].isoverlay = True;
}
currentoverlay = idx;
overlaykeysym = ispressingkeysym;
@ -832,10 +1090,10 @@ showoverlay(int idx)
void
hideoverlay(void)
{
if (debug) printdbg("Hiding overlay, overlay was #%d\n", currentoverlay);
printdbg("Hiding overlay, overlay was #%d\n", currentoverlay);
currentoverlay = -1;
overlaykeysym = 0;
currentlayer = -1;
currentlayer--;
cyclelayer();
}
@ -844,7 +1102,7 @@ sigterm(int signo)
{
running = False;
sigtermd = True;
if (debug) printdbg("SIGTERM received\n");
printdbg("SIGTERM received\n");
}
void
@ -867,7 +1125,7 @@ init_layers(char *layer_names_list, const char *initial_layer_name)
} else {
s = strtok(layer_names_list, ",");
while (s != NULL) {
if (numlayers+1 > LAYERS)
if (numlayers + 1 > LAYERS)
die("too many layers specified");
found = 0;
for (j = 0; j < LAYERS; j++) {
@ -895,6 +1153,9 @@ init_layers(char *layer_names_list, const char *initial_layer_name)
void
printdbg(const char *fmt, ...)
{
if (!debug)
return;
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
@ -919,26 +1180,26 @@ main(int argc, char *argv[])
if ((tmp = getenv("SVKBD_ENABLEOVERLAYS")))
enableoverlays = atoi(tmp);
}
if ((tmp = getenv("SVKBD_LAYERS"))) {
if (!(layer_names_list = strdup(tmp)))
die("memory allocation error");
}
if ((tmp = getenv("SVKBD_LAYERS")))
layer_names_list = estrdup(tmp);
if ((tmp = getenv("SVKBD_HEIGHTFACTOR")))
heightfactor = atoi(tmp);
if ((tmp = getenv("SVKBD_PRESSONRELEASE"))) /* defaults to 1 */
pressonrelease = atoi(tmp);
/* parse command line arguments */
for (i = 1; argv[i]; i++) {
if (!strcmp(argv[i], "-v")) {
die("svkbd-"VERSION);
} else if (!strcmp(argv[i], "-d")) {
isdock = True;
continue;
} else if (!strncmp(argv[i], "-g", 2)) {
if (i >= argc - 1)
continue;
usage(argv[0]);
bitm = XParseGeometry(argv[i + 1], &xr, &yr, &wr, &hr);
bitm = XParseGeometry(argv[++i], &xr, &yr, &wr, &hr);
if (bitm & XValue)
wx = xr;
if (bitm & YValue)
@ -951,35 +1212,44 @@ main(int argc, char *argv[])
wx = -1;
if (bitm & YNegative && wy == 0)
wy = -1;
i++;
} else if (!strcmp(argv[i], "-fn")) { /* font or font set */
fonts[0] = argv[++i];
if (i >= argc - 1)
usage(argv[0]);
fonts[0] = estrdup(argv[++i]);
} else if (!strcmp(argv[i], "-D")) {
debug = 1;
} else if (!strcmp(argv[i], "-h")) {
usage(argv[0]);
} else if (!strcmp(argv[i], "-O")) {
enableoverlays = 0;
} else if (!strcmp(argv[i], "-o")) {
printoutput = 1;
} else if (!strcmp(argv[i], "-n")) {
simulateoutput = 0;
} else if (!strcmp(argv[i], "-R")) {
pressonrelease = 0;
} else if (!strcmp(argv[i], "-l")) {
if (i >= argc - 1)
continue;
usage(argv[0]);
free(layer_names_list);
if (!(layer_names_list = strdup(argv[++i])))
die("memory allocation error");
layer_names_list = estrdup(argv[++i]);
} else if (!strcmp(argv[i], "-s")) {
if (i >= argc - 1)
continue;
usage(argv[0]);
initial_layer_name = argv[++i];
} else if (!strcmp(argv[i], "-H")) {
if (i >= argc - 1)
continue;
usage(argv[0]);
heightfactor = atoi(argv[++i]);
} else {
fprintf(stderr, "Invalid argument: %s\n", argv[i]);
exit(2);
usage(argv[0]);
}
}
if (printoutput)
setbuf(stdout, NULL); /* unbuffered output */
if (heightfactor <= 0)
die("height factor must be a positive integer");

10
util.c
View File

@ -16,6 +16,16 @@ ecalloc(size_t nmemb, size_t size)
return p;
}
char *
estrdup(const char *s)
{
char *p;
if (!(p = strdup(s)))
die("strdup:");
return p;
}
void
die(const char *fmt, ...)
{

1
util.h
View File

@ -6,3 +6,4 @@
void die(const char *fmt, ...);
void *ecalloc(size_t nmemb, size_t size);
char *estrdup(const char *s);