Merge pull request #33 from rbreaves/dev

Full wordwise support for Web Browsers, misc kintox11 optimizations.
This commit is contained in:
Ben Reaves
2020-02-18 02:29:44 +00:00
committed by GitHub
15 changed files with 297 additions and 11 deletions

View File

@@ -30,3 +30,17 @@ default partial xkb_symbols "mac_levelssym" {
// actions[Group1]= [ NoAction(), NoAction(), RedirectKey(key=<DELE>,clearmods=Control)]
// };
};
partial xkb_symbols "mac_chrome" {
// Back Button
replace key <LEFT> {
type[Group1]= "ONE_LEVEL_CTRL",
symbols[Group1]= [ Left, Left, Left ],
actions[Group1]= [ NoAction(), RedirectKey(key=<UP>), RedirectKey(key=<LEFT>,modifiers=Mod1,clearmods=Control)]
};
// Forwards Button
replace key <RGHT> {
type[Group1]= "ONE_LEVEL_CTRL",
symbols[Group1]= [ Right, Right, Right ],
actions[Group1]= [ NoAction(), RedirectKey(key=<DOWN>), RedirectKey(key=<RGHT>,modifiers=Mod1,clearmods=Control)]
};
};

View File

@@ -32,12 +32,21 @@ Kinto works for standard Windows, Apple and Chromebook keyboards. The following
- Python (initial install only)
- systemd
- x11
- IBus
- Debian/Ubuntu based distro 16.04+
If you need kintox11 recompiled for your distro please let me know and I will add a binary for your distro if my binary fails.
You can also attempt to compile kintox11.c on your system as well, but you will need to compile and install json-c first as its libraries will be required to compile and run the program.
IBUS is needed to support wordwise during browser app usage as the keymap will need to change slightly depending if the cursor/caret is on screen waiting for input. You may install ibus with the following.
```
ibus-setup
```
And then navigate to your "Language Support" and set "Keyboard input method system:" to IBus for full word-wise support with web browsers.
Wayland support is planned, but not ready yet.
## How to install

View File

@@ -4,15 +4,18 @@ systemctl --user stop keyswap >/dev/null 2>&1
systemctl --user disable keyswap >/dev/null 2>&1
systemctl --user stop keyswap.timer >/dev/null 2>&1
systemctl --user disable keyswap.timer >/dev/null 2>&1
swapcmd="\/home\/`whoami`\/.config\/kinto\/xactive.sh"
swapcmd="\/bin\/bash -c \"\/home\/`whoami`\/.config\/kinto\/xactive.sh carrots\""
swapstopcmd="\/bin\/bash \/home\/`whoami`\/.config\/kinto\/cleanup.sh"
mkdir -p ~/.config/systemd/user
mkdir -p ~/.config/autostart
cp ./system-config/keyswap.service ~/.config/systemd/user/keyswap.service
cp ./system-config/kinto.desktop ~/.config/autostart/kinto.desktop
cp ./kintox11/binary/kintox11 ~/.config/kinto/kintox11
cp ./system-config/xactive.sh ~/.config/kinto/xactive.sh
cp ./system-config/caret_status.sh ~/.config/kinto/caret_status.sh
cp ./system-config/cleanup.sh ~/.config/kinto/cleanup.sh
cp ./system-config/.firefox-nw ~/.config/kinto/.firefox-nw
sed -i "s/{username}/`whoami`/g" ~/.config/systemd/user/keyswap.service
sed -i "s/ExecStart=/ExecStart=${swapcmd}/g" ~/.config/systemd/user/keyswap.service
systemctl --user daemon-reload
systemctl --user enable keyswap
systemctl --user start keyswap

Binary file not shown.

View File

@@ -2,4 +2,4 @@ CFLAGS=-g $(shell pkg-config --cflags json-c xmu)
LDFLAGS=-g $(shell pkg-config --libs json-c xmu)
all:
$(CC) kintox11.c $(CFLAGS) $(LDFLAGS) -o kintox11
$(CC) kintox11.c $(CFLAGS) $(LDFLAGS) -lm -o kintox11

View File

@@ -22,9 +22,112 @@
#include <X11/Xlib.h> // `apt-get install libx11-dev`
#include <X11/Xmu/WinUtil.h> // `apt-get install libxmu-dev`
#include <json-c/json.h> // `apt install libjson-c-dev`
#include <sys/select.h>
#include <math.h>
#include <sys/time.h>
long long timeInMilliseconds(void) {
struct timeval tv;
gettimeofday(&tv,NULL);
return (((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
}
static int wait_fd(int fd, double seconds)
{
struct timeval tv;
fd_set in_fds;
FD_ZERO(&in_fds);
FD_SET(fd, &in_fds);
tv.tv_sec = trunc(seconds);
tv.tv_usec = (seconds - trunc(seconds))*1000000;
return select(fd+1, &in_fds, 0, 0, &tv);
}
int XNextEventTimeout(Display *d, XEvent *e, double seconds, long long event_ts, int last_event, long long *event_ts_ptr, int *last_event_ptr)
{
if (XPending(d) || wait_fd(ConnectionNumber(d),seconds)) {
// XNextEvent(d, e);
// while (1) {
// XNextEvent(d, e);
// if(e->type != 16){
// printf("Inside XNextEvent timeout\n");
// break;
// }
// }
while (1) {
XNextEvent(d, e);
long long int new_ts = timeInMilliseconds();
if(!(e->type == 22 && (e->type == last_event) && timeInMilliseconds()-event_ts < 419)){
// printf("%d == %d\n",e->type, last_event);
// printf("Timestamp: %lld\n",timeInMilliseconds()-event_ts);
*event_ts_ptr = new_ts;
*last_event_ptr = e->type;
// printf("in event_ts_ptr: %lld\n",*event_ts_ptr);
// printf("in last_event_ptr: %d\n",*last_event_ptr);
break;
}
*event_ts_ptr = new_ts;
*last_event_ptr = e->type;
// printf("event_ts_ptr: %lld\n",*event_ts_ptr);
// printf("last_event_ptr: %d\n",*last_event_ptr);
}
return 0;
} else {
return 1;
}
}
Bool xerror = False;
char *trimwhitespace(char *str)
{
char *end;
// Trim leading space
while(isspace((unsigned char)*str)) str++;
if(*str == 0) // All spaces?
return str;
// Trim trailing space
end = str + strlen(str) - 1;
while(end > str && isspace((unsigned char)*end)) end--;
// Write new null terminator character
end[1] = '\0';
return str;
}
int check_caret()
{
int caretint;
char * fpname;
fpname = malloc(sizeof(char)*20);
strcpy(fpname,"/tmp/kinto/caret");
if( access( fpname, F_OK ) != -1 ) {
char *buffer = NULL;
size_t size = 0;
FILE *fp = fopen(fpname, "r");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
rewind(fp);
buffer = malloc((size + 1) * sizeof(*buffer));
fread(buffer, size, 1, fp);
buffer[size] = '\0';
trimwhitespace(buffer);
caretint = atoi(buffer);
if(caretint == 1){
// printf("caret: %s\n", buffer);
return 1;
}
// printf("found nothing\n");
return 0;
}
else{
printf("file %s does not exist\n",fpname);
return 0;
}
}
int in_int(int a[],int size,int item)
{
int i,pos=-1;
@@ -173,10 +276,10 @@ int main(void){
FILE *fp;
char buffer[10240];
struct json_object *parsed_json, *config, *config_obj,
*config_obj_name, *config_obj_run, *config_obj_de,
*config_obj_appnames, *appnames_obj, *init, *de,
*de_obj, *de_obj_id, *de_obj_active, *de_obj_run,
*de_obj_runterm,*de_obj_rungui;
*config_obj_name, *config_obj_run, *config_obj_run_oninput,
*config_obj_run_offinput, *config_obj_de, *config_obj_appnames,
*appnames_obj, *init, *de, *de_obj, *de_obj_id, *de_obj_active,
*de_obj_run, *de_obj_runterm,*de_obj_rungui;
int arraylen;
int appnames_len, init_len, de_len, config_de_len;
@@ -201,6 +304,8 @@ int main(void){
const char *name_array[arraylen];
const char *run_array[arraylen];
const char *run_oninput_array[arraylen];
const char *run_offinput_array[arraylen];
int init_array[init_len];
int de_id_array[de_len];
@@ -249,10 +354,16 @@ int main(void){
for (i = 0; i < arraylen; i++) {
config_obj = json_object_array_get_idx(config, i);
config_obj_name = json_object_object_get(config_obj, "name");
config_obj_run = json_object_object_get(config_obj, "run");
config_obj_run_oninput = json_object_object_get(config_obj, "run_onInput");
config_obj_run_offinput = json_object_object_get(config_obj, "run_offInput");
name_array[i] = json_object_get_string(config_obj_name);
run_array[i] = json_object_get_string(config_obj_run);
run_oninput_array[i] = json_object_get_string(config_obj_run_oninput);
run_offinput_array[i] = json_object_get_string(config_obj_run_offinput);
// printf("%s\n%s\n", json_object_get_string(config_obj_name), json_object_get_string(config_obj_run));
config_obj_appnames = json_object_object_get(config_obj, "appnames");
@@ -310,10 +421,16 @@ int main(void){
XSelectInput(d, DefaultRootWindow(d), SubstructureNotifyMask);
XSetErrorHandler(handle_error);
char * run_normal;
char * run_onInput;
char * run_offInput;
char * prior_app;
char * current_app;
char * prior_category;
char * current_category;
run_onInput = malloc(sizeof(char)*400);
run_offInput = malloc(sizeof(char)*400);
run_normal = malloc(sizeof(char)*400);
prior_app = malloc(sizeof(char)*100);
current_app = malloc(sizeof(char)*100);
prior_category = malloc(sizeof(char)*100);
@@ -335,10 +452,12 @@ int main(void){
printf("First window name: %s \n",str_window_class(d, w,prior_app));
int breakouter;
int last_event=0;
Bool ran_onInput = 0;
long long int event_ts = timeInMilliseconds();
for (;;)
{
strcpy(current_app,str_window_class(d, w,prior_app));
int category_idx;
// printf("current: %s\n",current_app);
@@ -379,6 +498,11 @@ int main(void){
printf("%s: %s\n",current_category,current_app);
// printf("run: %s\n",run_array[category_idx]);
system(run_array[category_idx]);
strcpy(run_normal,run_array[category_idx]);
ran_onInput = 0;
strcpy(run_onInput,run_oninput_array[category_idx]);
strcpy(run_offInput,run_offinput_array[category_idx]);
system(run_offInput);
for(r = 0; r < config_de_max; r++){
if(config_de_array[category_idx][r] != -1){
int de_id_idx = in_int(de_id_array, de_len, config_de_array[category_idx][r]);
@@ -403,8 +527,41 @@ int main(void){
strcpy(prior_app,current_app);
strcpy(prior_category,current_category);
// printf("run_onInput: %ld\n",strlen(run_onInput));
XEvent e;
XNextEvent(d, &e);
if(strlen(run_onInput) > 0){
while(XNextEventTimeout(d, &e, .5, event_ts, last_event, &event_ts, &last_event)){
if(check_caret() && ran_onInput == 0){
// printf("run_onInput: %s\n",run_onInput);
system(run_onInput);
ran_onInput = 1;
}
else if(!check_caret() && ran_onInput == 1){
// printf("run_offInput: %s\n",run_offInput);
system(run_offInput);
ran_onInput = 0;
}
// e.type = Expose;
// e.xexpose.count = 0;
}
}
else{
// XNextEvent(d, &e);
while (1) {
XNextEvent(d, &e);
if(!(e.type == 22 && (e.type == last_event) && timeInMilliseconds()-event_ts < 300)){
// printf("%d == %d\n",e.type, last_event);
// printf("Timestamp: %lld\n",timeInMilliseconds()-event_ts);
event_ts = timeInMilliseconds();
last_event = e.type;
break;
}
event_ts = timeInMilliseconds();
last_event = e.type;
}
}
w = get_focus_window(d);
w = get_top_window(d, w);
w = get_named_window(d, w);

View File

@@ -15,6 +15,32 @@ def cmdline(command):
)
return process.communicate()[0]
def requirements():
print(bcolors.CYELLOW + "You need to install some packages, " +run_pkg+ ", for Kinto to fully remap browsers during input focus.\n" + bcolors.ENDC)
print("sudo apt-get install -y " + run_pkg + "\n")
run_install = yn_choice(bcolors.CYELLOW + "Would you like to run it now? (Will require sudo privileges.)\n" + bcolors.ENDC)
if(run_install):
os.system("sudo apt-get install -y " + run_pkg)
print("\n")
check_xbind = symbols_gui_line = cmdline("which xbindkeys").strip()
check_xdotool = symbols_gui_line = cmdline("which xdotool").strip()
runpkg = 0
run_pkg = ""
if len(check_xbind) > 0 and len(check_xdotool) > 0:
print("Xbindkeys, and xdotool requirement is installed.")
if len(check_xbind) == 0:
run_pkg = "xbindkeys"
runpkg = 1
if len(check_xdotool) == 0:
run_pkg += " xdotool"
runpkg = 1
if runpkg != 0:
requirements()
try:
f = open("defaults.json")
except IOError:
@@ -96,6 +122,8 @@ if os.path.isdir(homedir + "/.xkb/keymap") == False:
time.sleep(0.5)
os.system('setxkbmap -option')
os.system('setxkbmap -print > ~/.xkb/keymap/kbd.mac.gui')
os.system('setxkbmap -print > ~/.xkb/keymap/kbd.mac.gui.nw')
os.system('setxkbmap -print > ~/.xkb/keymap/kbd.mac.gui.chrome')
os.system('setxkbmap -print > ~/.xkb/keymap/kbd.mac.term')
time.sleep(0.5)
@@ -107,6 +135,11 @@ cmdline('sed -i '' -e "' + symbols_gui_line + 's/\\"/' + keyboardconfigs[default
cmdline('sed -i '' -e "' + types_gui_line + 's/\\"/' + keyboardconfigs[defaultkb-1]['xkb_types_gui'] + '\\"/2" ~/.xkb/keymap/kbd.mac.gui')
cmdline('sed -i '' -e "' + symbols_term_line + 's/\\"/' + keyboardconfigs[defaultkb-1]['xkb_symbols_term'] + '\\"/2" ~/.xkb/keymap/kbd.mac.term')
cmdline('sed -i '' -e "' + symbols_gui_line + 's/\\"/' + keyboardconfigs[defaultkb-1]['xkb_symbols_gui'].replace("+mac_gui(mac_levelssym)","") + '\\"/2" ~/.xkb/keymap/kbd.mac.gui.nw')
cmdline('sed -i '' -e "' + symbols_gui_line + 's/\\"/' + keyboardconfigs[defaultkb-1]['xkb_symbols_gui'].replace("+mac_gui(mac_levelssym)","+mac_gui(mac_chrome)") + '\\"/2" ~/.xkb/keymap/kbd.mac.gui.chrome')
cmdline('sed -i '' -e "' + types_gui_line + 's/\\"/' + keyboardconfigs[defaultkb-1]['xkb_types_gui'] + '\\"/2" ~/.xkb/keymap/kbd.mac.gui.nw')
cmdline('sed -i '' -e "' + types_gui_line + 's/\\"/' + keyboardconfigs[defaultkb-1]['xkb_types_gui'] + '\\"/2" ~/.xkb/keymap/kbd.mac.gui.chrome')
user_file = homedir + '/.config/kinto/user_config.json'
with open(user_file, 'r') as f:
@@ -152,9 +185,15 @@ if len(defaultde) != 0:
user_config['config'][0]['de'] = tweaks_selected
# term
user_config['config'][1]['de'] = tweaks_selected
# firefox
user_config['config'][2]['de'] = tweaks_selected
# chrome
user_config['config'][3]['de'] = tweaks_selected
user_config['config'][0]['run'] = keyboardconfigs[defaultkb-1]['gui']
user_config['config'][1]['run'] = keyboardconfigs[defaultkb-1]['term']
user_config['config'][2]['run'] = keyboardconfigs[defaultkb-1]['gui']
user_config['config'][3]['run'] = keyboardconfigs[defaultkb-1]['gui'].replace("kbd.mac.gui","kbd.mac.gui.chrome")
os.remove(user_file)
with open(user_file, 'w') as f:

7
system-config/.chrome-nw Normal file
View File

@@ -0,0 +1,7 @@
"xdotool key --delay 0 --clearmodifiers Alt+Left"
Control + Left + Release
#Home + release
"xdotool key --delay 0 --clearmodifiers Alt+Right"
Control + Right + Release
#End + release

5
system-config/.chrome-ww Normal file
View File

@@ -0,0 +1,5 @@
"xdotool key --delay 0 --clearmodifiers Home"
Control + Left + Release
"xdotool key --delay 0 --clearmodifiers End"
Control + Right + Release

View File

@@ -0,0 +1,7 @@
#"xte 'keydown Control_L' 'key bracketleft' 'keyup Control_L'"
"xdotool key --delay 0 --clearmodifiers Control_L+bracketleft"
Home + Release
#"xte 'keydown Control_R' 'key bracketright' 'keyup Control_R'"
"xdotool key --delay 0 --clearmodifiers Control_L+bracketright"
End + Release

10
system-config/caret_status.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
mkdir -p /tmp/kinto
IBUSADD=$(cat ~/.config/ibus/bus/`ls ~/.config/ibus/bus -1rt | tail -n1` | awk -F'IBUS_ADDRESS=' '{print $2}' | xargs)
dbus-monitor --address $IBUSADD "path='/org/freedesktop/IBus/Panel',interface='org.freedesktop.IBus.Panel',member='FocusOut'" 2> /dev/null | grep --line-buffered -o -P '(?<=object path \"/org/freedesktop/IBus/InputContext_).*(?=[\"])' |
while read ln
do
printf '%s\n' "$ln" > /tmp/kinto/caret
done

5
system-config/cleanup.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
setxkbmap -option
killall xbindkeys > /dev/null 2>&1
rm /tmp/kinto/caret

View File

@@ -7,7 +7,8 @@ Type=simple
Restart=always
RestartSec=1
WorkingDirectory=/home/{username}/.config/kinto
ExecStart=
ExecStart=/bin/bash -c "/home/{username}/.config/kinto/xactive.sh carrots"
ExecStop=/bin/bash /home/{username}/.config/kinto/cleanup.sh
[Install]
WantedBy=default.target

View File

@@ -1,3 +1,4 @@
#!/bin/bash
./caret_status.sh &
./kintox11

View File

@@ -1,15 +1,43 @@
{"config":[{
"name":"gui",
"run":"",
"run_onInput":"",
"run_offInput": "killall xbindkeys > /dev/null 2>&1",
"symbols":"",
"types":"",
"de":[],
"appnames":[ "" ]
},
{
"name":"term",
"run":"",
"run_onInput":"",
"run_offInput": "killall xbindkeys > /dev/null 2>&1",
"symbols":"",
"types":"",
"de":[],
"appnames":[ "Gnome-terminal","konsole","io.elementary.terminal","terminator","sakura","guake","tilda","xterm","eterm" ]
}],
},
{
"name": "firefox",
"run": "",
"run_onInput": "killall xbindkeys > /dev/null 2>&1",
"run_offInput": "killall xbindkeys > /dev/null 2>&1;xbindkeys -f $HOME/.config/kinto/.firefox-nw",
"symbols": "",
"types": "",
"de": [],
"appnames": [ "Firefox" ]
},
{
"name": "chrome",
"run": "",
"run_onInput": "xkbcomp -w0 -I$HOME/.xkb ~/.xkb/keymap/kbd.mac.gui $DISPLAY",
"run_offInput": "xkbcomp -w0 -I$HOME/.xkb ~/.xkb/keymap/kbd.mac.gui.chrome $DISPLAY",
"symbols": "",
"types": "",
"de": [],
"appnames": [ "Chromium","Chromium-browser" ]
}],
"init": [],
"detypes":["gnome2","gnome3","kde4","kde5","xfce","i3wm"],
"de":[{