Skip to content

Commit

Permalink
1.02: Temporary layout switching added
Browse files Browse the repository at this point in the history
  • Loading branch information
zvezdochiot committed Jun 1, 2019
1 parent 01d8fb3 commit 9f9f469
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 39 deletions.
29 changes: 19 additions & 10 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,50 @@

Installation

Unpack archive and copy as root the s1kls file to the any location that is suitable for programs, /usr/bin/ for instance
Unpack archive and copy as root the s1kls file to the any location that is suitable for programs, /usr/bin/ for instance.
It is recommended to run this program with root privileges for better poll accuracy. For do this set after installation SUID flag:
chmod u+s /usr/bin/s1kls

Command line

xkbs1kls keycode1 keycode2 ...
xkbs1kls keycode0 keycode1 ... -sN keycode ...

The key with keycode 'keycode1' sets the layout 1,
the key with keycode 'keycode2' sets the layout 2 ...
The key with keycode 'keycode0' sets the layout 0,
the key with keycode 'keycode1' sets the layout 1 ...
You may also define several keycodes for switch to desired layouts temporary (while pressed). Layout is the digit N after '-s' (without space).

Features

Only LockGroup switch type supported (each key select the own layout). No layout indicator supported.
Only "LockGroup" switch type supported for permanent switch (each key select the own layout). No layout indicator supported. Also "Switch" type supported for temoparay switch.
Key codes you can find out by calling this program in the terminal without parameters.

Backgrownd

Standard X11 layout switcher is activated immediately by pressing the keys and therefore conflicts with the application shortcuts.
This switcher is activated by releasing the keys, but only under the condition that no other key is pressed. For example, You were asked to switch to the layout 2 by RCtrl. Then if You press and release RCtrl, the layout will be switched. But if You pressed in a text editor RCtrl-Right, then the editor performs jump forward a word and layout will not be switched.
Standard X11 permanent layout switcher is activated immediately by PRESSING the keys and therefore conflicts with the application shortcuts. Also it is not possible to define Compose key that work regardless of the current layout.
In this program permanent layout switcher is activated by RELEASING the keys, but only under the condition that no other key is pressed. For example, You were asked to switch to the layout 2 by RCtrl. Then if You press and release RCtrl, the layout will be switched. But if You pressed in a text editor RCtrl-Right, then the editor performs jump forward a word and layout will not be switched.
Temporary layout switcher in this program works simultaneously with the standart X features and it is useful to define as temporary switcher to the English keyboard the same key thаt used as X Compose Key.

If You need a layout indicator, You can use a standard X11 LED indicator or any tray indicator as xxkb.

Example

I use 3 layouts: (us,ru,ua), LED "ScrollLock" as indicator and keys following: RShift sets "us", RCtrl sets "ru" and RWin sets "ua". On the pc105 keyboard these keys have the keycodes 62, 105 and 134.
I use 3 layouts: (us,ru,ua) and CapsLock as compose key. I want tu use for the permanent switching the keys following: RShift sets "us", RCtrl sets "ru" and RWin sets "ua". Also I define CapsLock as temopary switcher to tu "us" layout. On the pc105 keyboard these keys have the keycodes 62, 105, 134 and 66.

In the X11 keyboard config (in my ArchLinux it is the file /etc/X11/xorg.conf.d/01-keyboard-layout.conf) I define:

Option "XkbLayout" "us, ru, ua"
Option "XkbOptions" "grp_led:scroll"
Option "XKbOptions" "grp_led:scroll,compose:caps"

In the autostart I call this program:

xkbs1kls 62 105 134 &
xkbs1kls 62 105 134 -s0 66 &


===========

What's new

1.02 Temporary layout switching added,
1.01 First public release.

https://sourceforge.net/projects/s1kls/
141 changes: 112 additions & 29 deletions s1kls.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Simple X11 1-key Keyboard layout switcher.
Simple X11 1-key Keyboard layout locker.
Only LockGroup switch type supported (each key select the own layout).
No indicator supported.
Expand All @@ -20,15 +20,21 @@ but only yf no other key(s) has been pressed.
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XKBlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>

//#define TRACE

static int switcher[16];
static int locker[10];
static struct {int key, layout;} switcher[10];
static int n_switcher, n_locker; // counts of the each type switchers
static bool view_codes = 0;

/* some keycodes on the pc105 keyboard:
62 rshift
105 rctrl
Expand All @@ -37,11 +43,10 @@ static int switcher[16];
50 lshift
37 lctrl
64 lalt
66 caps
133 lwin
*/

typedef unsigned char bool;

/* set realtime priority if possible */
void set_rt_prio(void){
struct sched_param param;
Expand All @@ -50,6 +55,74 @@ void set_rt_prio(void){
pthread_setschedparam(pthread_self(), SCHED_FIFO, &param); // do not check success
}

static int get_group(Display *dpy) {
XkbStateRec state[1];
memset(state, 0, sizeof(state));
XkbGetState(dpy, XkbUseCoreKbd, state);
return state->group;
}

static void init(int argc, char *argv[]){
int n;
char c;

n_switcher = 0;
n_locker = 0;
for (n=1; n<argc-1; n++){
if (argv[n][0] == '-'){
if (strlen(argv[n]) != 3){
printf("'%s' wrong lengh\n\n", argv[n]);
goto help;
}
if (argv[n][1] != 's'){
printf("'%s' wrong key\n\n", argv[n]);
goto help;
}
c = argv[n][2]; // layout number
if ((c < '0') || (c > '9')) {
printf("'%s' wrong layout number\n\n", argv[n]);
goto help;
}
switcher[n_switcher].layout = c-'0';
if (n_locker == argc-1){
printf("keycode missng after '%s'\n\n", argv[n]);
goto help;
}
n++;
sscanf(argv[n], "%d", &switcher[n_switcher].key);
if (switcher[n_switcher].key <= 0){
printf("'%s' wrong keycode\n\n", argv[n]);
goto help;
}
n_switcher++;
}
else
{
sscanf(argv[n], "%d", &locker[n_locker]);
if (locker[n_locker] <= 0){
printf("'%s' wrong keycode\n\n", argv[n]);
goto help;
}
n_locker++;
}
}

if ((n_locker < 2) && (n_switcher == 0)){
help:
printf("Simple X11 1-key Keyboard layout locker. Version 1.02.\n");
printf("(c) Alexey Korop, 2019. Free software under GNU GPLv3\n\n");
printf(" It is recommended to run this program with root privileges for better poll accuracy\n");
printf(" Command line: s1kls keycode0 keycode1 ... -s<layout> keycode ...\n\n");
printf("The key with keycode 'keycode0' sets the layout 0, \n");
printf("the key with keycode 'keycode1' sets the layout 1 ... \n\n");
printf(" You may also define several keycodes for switch to desired layout temporary (while pressed)\n");
printf("Layout is the digit after '-s' (without space), for instance:\n");
printf(" -s0 108 - this define right Alt as tempoary switch to the layout 0.\n\n");
printf("Now You may press the desired keys and see their keycodes.\n");
view_codes = 1;
}
}

int main(int argc, char *argv[]) {
Display *display;
char keys_cur[32], keys_prev[32];
Expand All @@ -58,30 +131,13 @@ int main(int argc, char *argv[]) {
int keycode = 0;
int i;
int byte, bit;
int n;
bool view_codes = 0;
int old_layout = -1; // !=-1 during temporary switching
int layout = -1;/*
-2 - Awaiting release all keys;
-1 - all keys are released;
0... - the key that selects this layout is pressed; expect its release */

for (n=0; n<argc-1; n++){
sscanf(argv[n+1], "%d", &switcher[n]);
if (switcher[n] <= 0)
goto help;
}
if (n < 2){
help:
printf("Simple X11 1-key Keyboard layout switcher. Version 1.01.\n");
printf("(c) Alexey Korop, 2014. Free software under GNU GPLv3\n\n");
printf("It is recommended to run this program with root privileges for better poll accuracy\n");
printf("Command line: s1kls keycode1 keycode2 ...\n\n");
printf("The key with keycode 'keycode1' sets the layout 1, \n");
printf("the key with keycode 'keycode2' sets the layout 2 ... \n\n");
printf("Now You may press the desired keys and see their keycodes.\n");
view_codes = 1;
}

init(argc, argv);
set_rt_prio();
display = XOpenDisplay(NULL);
if (display == NULL){
Expand Down Expand Up @@ -112,7 +168,7 @@ int main(int argc, char *argv[]) {
}
if (cur & 0x01)
n_keys_pressed++;
diff >>= 1;
diff >>= 1;
cur >>= 1;
}
}
Expand All @@ -128,7 +184,17 @@ int main(int argc, char *argv[]) {
}
else { // normal work
if (n_keys_pressed == 0){
if (layout >= 0){
if (old_layout >= 0){
#ifdef TRACE
printf("return to layout %d\n", old_layout);
#endif
if (!XkbLockGroup(display, XkbUseCoreKbd, old_layout)){
fprintf(stderr, "XkbLockGroup error \n");
return(1);
}
old_layout = layout = -1;
}
else if (layout >= 0){
#ifdef TRACE
printf("new layout %d\n", layout);
#endif
Expand All @@ -141,19 +207,36 @@ int main(int argc, char *argv[]) {
}
else if (layout == -2)
;
else if ((n_keys_pressed == 1) && (keycode == switcher[layout]))
else if ((n_keys_pressed == 1) && (keycode == locker[layout]))
; //hold the key
else if ((n_keys_pressed == 1) && (layout == -1)){
layout = -2;
for (i=0; i<n; ++i)
if (keycode == switcher[i]){
// try key as layout locker
for (i=0; i<n_locker; ++i)
if (keycode == locker[i]){
layout = i;
#ifdef TRACE
printf("wait for release the key %d\n", switcher[layout]);
printf("wait for release the key %d\n", locker[layout]);
#endif
break;
}
if (layout == -2){
// try key as layout switcher
for (i=0; i<n_switcher; ++i)
if (keycode == switcher[i].key){
layout = switcher[i].layout;
old_layout = get_group(display);
if (!XkbLockGroup(display, XkbUseCoreKbd, layout)){
fprintf(stderr, "XkbLockGroup error \n");
return(1);
}
#ifdef TRACE
printf("key %d switch to layout %d\n", switcher[i].key, switcher[i].layout);
#endif
break;
}
}
}
else{
#ifdef TRACE
if (layout >= 0)
Expand Down

0 comments on commit 9f9f469

Please sign in to comment.