mirror of
https://github.com/rbreaves/kinto.git
synced 2025-08-06 10:58:26 +02:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5d135afe5e | ||
![]() |
a4fa9b225e | ||
![]() |
eac62fb605 | ||
![]() |
ab679ddf9d | ||
![]() |
f4cef736be | ||
![]() |
2179176881 | ||
![]() |
26f70ccd31 | ||
![]() |
0ff7a42f9b | ||
![]() |
58da4fcd90 | ||
![]() |
20170f0a7d | ||
![]() |
d90829928b | ||
![]() |
6f913538e8 | ||
![]() |
7dfbe884ff | ||
![]() |
3a115f91ae | ||
![]() |
4c218b55bd | ||
![]() |
94cd3ed907 | ||
![]() |
b0bde4fecf | ||
![]() |
b930b96066 | ||
![]() |
2df4920344 | ||
![]() |
ce9c80a02f |
@@ -1,15 +1,15 @@
|
|||||||
default partial xkb_symbols "mac_levelssym" {
|
default partial xkb_symbols "mac_levelssym" {
|
||||||
// LEFT to Begin Line
|
// LEFT to Begin Line or Beginning of word
|
||||||
replace key <LEFT> {
|
replace key <LEFT> {
|
||||||
type[Group1]= "ONE_LEVEL_CTRL",
|
type[Group1]= "ONE_LEVEL_CTRL",
|
||||||
symbols[Group1]= [ Left, Left, NoSymbol ],
|
symbols[Group1]= [ Left, Left, NoSymbol ],
|
||||||
actions[Group1]= [ NoAction(), NoAction(), RedirectKey(key=<HOME>,clearmods=Control)]
|
actions[Group1]= [ NoAction(), RedirectKey(key=<LEFT>,modifiers=Control,clearmods=Mod1), RedirectKey(key=<HOME>,clearmods=Control)]
|
||||||
};
|
};
|
||||||
// Right to End of Line
|
// Right to End of Line or end of word
|
||||||
replace key <RGHT> {
|
replace key <RGHT> {
|
||||||
type[Group1]= "ONE_LEVEL_CTRL",
|
type[Group1]= "ONE_LEVEL_CTRL",
|
||||||
symbols[Group1]= [ Right, Right, NoSymbol ],
|
symbols[Group1]= [ Right, Right, NoSymbol ],
|
||||||
actions[Group1]= [ NoAction(), NoAction(), RedirectKey(key=<END>,clearmods=Control)]
|
actions[Group1]= [ NoAction(), RedirectKey(key=<RGHT>,modifiers=Control,clearmods=Mod1), RedirectKey(key=<END>,clearmods=Control)]
|
||||||
};
|
};
|
||||||
// Up to Mac Home
|
// Up to Mac Home
|
||||||
replace key <UP> {
|
replace key <UP> {
|
||||||
|
@@ -1,20 +1,11 @@
|
|||||||
default partial xkb_types "addmac_levels" {
|
default partial xkb_types "addmac_levels" {
|
||||||
type "ONE_LEVEL_CTRL" {
|
type "ONE_LEVEL_CTRL" {
|
||||||
modifiers= Shift+Control;
|
modifiers= Mod1+Control;
|
||||||
map[Shift]= Level2;
|
map[Mod1]= Level2;
|
||||||
map[Control]= Level3;
|
map[Control]= Level3;
|
||||||
map[Shift+Control]= Level3;
|
map[Mod1+Control]= Level3;
|
||||||
level_name[Level1]= "Base";
|
level_name[Level1]= "Base";
|
||||||
level_name[Level2]= "Caps";
|
level_name[Level2]= "Alt";
|
||||||
level_name[Level3]= "With Control";
|
|
||||||
};
|
|
||||||
type "TWO_LEVEL_CTRL" {
|
|
||||||
modifiers= Shift+Control;
|
|
||||||
map[Shift]= Level2;
|
|
||||||
map[Control]= Level3;
|
|
||||||
map[Shift+Control]= Level3;
|
|
||||||
level_name[Level1]= "Base";
|
|
||||||
level_name[Level2]= "Caps";
|
|
||||||
level_name[Level3]= "With Control";
|
level_name[Level3]= "With Control";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
29
README.md
29
README.md
@@ -165,19 +165,41 @@ systemctl --user stop keyswap && setxkbmap -option;setxkbmap -option altwin:swap
|
|||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Does not start when you log in or after you reboot?
|
||||||
|
|
||||||
|
1. Check the status
|
||||||
|
```
|
||||||
|
systemctl --user status keyswap
|
||||||
|
```
|
||||||
|
2. Check the service journal
|
||||||
|
```
|
||||||
|
journalctl -xe
|
||||||
|
```
|
||||||
|
|
||||||
|
Open a ticket and send me the info.
|
||||||
|
|
||||||
### Keyswap is not occurring, but it was working.
|
### Keyswap is not occurring, but it was working.
|
||||||
|
|
||||||
Now that Kinto is using a custom written C program I am not aware of any specific bugs or issues, but you can start here if you having difficulties and please report it if it is reproducible.
|
Now that Kinto is using a custom written C program I am not aware of any specific bugs or issues, but you can start here if you having difficulties and please report it if it is reproducible.
|
||||||
|
1. Get status
|
||||||
1. Restart Kinto
|
```
|
||||||
|
systemctl --user status keyswap
|
||||||
|
```
|
||||||
|
2. Restart Kinto
|
||||||
```
|
```
|
||||||
systemctl --user restart keyswap
|
systemctl --user restart keyswap
|
||||||
```
|
```
|
||||||
2. Check the Status of Kinto and open a ticket with the output.
|
3. Check the Status again and open a ticket if you need to.
|
||||||
```
|
```
|
||||||
systemctl --user status keyswap
|
systemctl --user status keyswap
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also do the following to see if it is an actual issue with kintox11 not running or your service file.
|
||||||
|
```
|
||||||
|
cd ~/.config/kinto
|
||||||
|
./kintox11
|
||||||
|
```
|
||||||
|
|
||||||
## Language Support
|
## Language Support
|
||||||
I'd appreciate any help from people with non-US based keyboards, to help ensure that these keymaps and keyswap methods work in all or most languages.
|
I'd appreciate any help from people with non-US based keyboards, to help ensure that these keymaps and keyswap methods work in all or most languages.
|
||||||
|
|
||||||
@@ -194,6 +216,7 @@ https://superuser.com/questions/385748/binding-superc-superv-to-copy-and-paste
|
|||||||
|
|
||||||
## More information about Kinto
|
## More information about Kinto
|
||||||
|
|
||||||
|
https://medium.com/@benreaves/kinto-v1-0-released-2018e6401d2e
|
||||||
https://medium.com/@benreaves/kinto-a-mac-inspired-keyboard-mapping-for-linux-58f731817c0
|
https://medium.com/@benreaves/kinto-a-mac-inspired-keyboard-mapping-for-linux-58f731817c0
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
@@ -4,7 +4,7 @@ systemctl --user stop keyswap >/dev/null 2>&1
|
|||||||
systemctl --user disable keyswap >/dev/null 2>&1
|
systemctl --user disable keyswap >/dev/null 2>&1
|
||||||
systemctl --user stop keyswap.timer >/dev/null 2>&1
|
systemctl --user stop keyswap.timer >/dev/null 2>&1
|
||||||
systemctl --user disable keyswap.timer >/dev/null 2>&1
|
systemctl --user disable keyswap.timer >/dev/null 2>&1
|
||||||
swapcmd="\/bin\/bash\ \/home\/`whoami`\/.config\/kinto\/xactive.sh"
|
swapcmd="\/home\/`whoami`\/.config\/kinto\/xactive.sh"
|
||||||
mkdir -p ~/.config/systemd/user
|
mkdir -p ~/.config/systemd/user
|
||||||
mkdir -p ~/.config/autostart
|
mkdir -p ~/.config/autostart
|
||||||
cp ./system-config/keyswap.service ~/.config/systemd/user/keyswap.service
|
cp ./system-config/keyswap.service ~/.config/systemd/user/keyswap.service
|
||||||
|
115
kintopy/kinto.py
Normal file
115
kintopy/kinto.py
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Kinto - Python implementation of Xlib
|
||||||
|
#
|
||||||
|
# Based on code by Stephan Sokolow
|
||||||
|
# Source: https://gist.github.com/ssokolow/e7c9aae63fb7973e4d64cff969a78ae8
|
||||||
|
from contextlib import contextmanager
|
||||||
|
import Xlib
|
||||||
|
import Xlib.display
|
||||||
|
|
||||||
|
# Connect to the X server and get the root window
|
||||||
|
disp = Xlib.display.Display()
|
||||||
|
root = disp.screen().root
|
||||||
|
|
||||||
|
# Prepare the property names we use so they can be fed into X11 APIs
|
||||||
|
NET_ACTIVE_WINDOW = disp.intern_atom('_NET_ACTIVE_WINDOW')
|
||||||
|
NET_WM_NAME = disp.intern_atom('_NET_WM_NAME') # UTF-8
|
||||||
|
WM_NAME = disp.intern_atom('WM_NAME') # Legacy encoding
|
||||||
|
NET_WM_CLASS = disp.intern_atom('_NET_WM_CLASS') # UTF-8
|
||||||
|
WM_CLASS = disp.intern_atom('WM_CLASS')
|
||||||
|
|
||||||
|
last_seen = { 'xid': None, 'title': None }
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def window_obj(win_id):
|
||||||
|
"""Simplify dealing with BadWindow (make it either valid or None)"""
|
||||||
|
window_obj = None
|
||||||
|
if win_id:
|
||||||
|
try:
|
||||||
|
window_obj = disp.create_resource_object('window', win_id)
|
||||||
|
except Xlib.error.XError:
|
||||||
|
pass
|
||||||
|
yield window_obj
|
||||||
|
|
||||||
|
def get_active_window():
|
||||||
|
"""Return a (window_obj, focus_has_changed) tuple for the active window."""
|
||||||
|
win_id = root.get_full_property(NET_ACTIVE_WINDOW,Xlib.X.AnyPropertyType).value[0]
|
||||||
|
|
||||||
|
focus_changed = (win_id != last_seen['xid'])
|
||||||
|
if focus_changed:
|
||||||
|
with window_obj(last_seen['xid']) as old_win:
|
||||||
|
if old_win:
|
||||||
|
old_win.change_attributes(event_mask=Xlib.X.NoEventMask)
|
||||||
|
|
||||||
|
last_seen['xid'] = win_id
|
||||||
|
with window_obj(win_id) as new_win:
|
||||||
|
if new_win:
|
||||||
|
new_win.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
|
||||||
|
|
||||||
|
return win_id, focus_changed
|
||||||
|
|
||||||
|
def _get_window_class_inner(win_obj):
|
||||||
|
for atom in (NET_WM_CLASS, WM_CLASS):
|
||||||
|
try:
|
||||||
|
window_class = win_obj.get_full_property(atom, 0)
|
||||||
|
|
||||||
|
except UnicodeDecodeError: # Apparently a Debian distro package bug
|
||||||
|
title = "<could not decode characters>"
|
||||||
|
else:
|
||||||
|
if window_class:
|
||||||
|
win_class = window_class.value.split('\x00')[1]
|
||||||
|
if isinstance(win_class, bytes):
|
||||||
|
# Apparently COMPOUND_TEXT is so arcane that this is how
|
||||||
|
# tools like xprop deal with receiving it these days
|
||||||
|
win_class = win_class.split('\x00')[1].decode('latin1', 'replace')
|
||||||
|
return win_class
|
||||||
|
else:
|
||||||
|
title = "<unnamed window>"
|
||||||
|
|
||||||
|
return "{} (XID: {})".format(title, win_obj.id)
|
||||||
|
|
||||||
|
def get_window_class(win_id):
|
||||||
|
"""Look up the window name for a given X11 window ID"""
|
||||||
|
if not win_id:
|
||||||
|
last_seen['title'] = "<no window id>"
|
||||||
|
return last_seen['title']
|
||||||
|
|
||||||
|
title_changed = False
|
||||||
|
with window_obj(win_id) as wobj:
|
||||||
|
if wobj:
|
||||||
|
win_title = _get_window_class_inner(wobj)
|
||||||
|
title_changed = (win_title != last_seen['title'])
|
||||||
|
last_seen['title'] = win_title
|
||||||
|
|
||||||
|
return last_seen['title'], title_changed
|
||||||
|
|
||||||
|
def handle_xevent(event):
|
||||||
|
# Loop through, ignoring events until we're notified of focus/title change
|
||||||
|
if event.type != Xlib.X.PropertyNotify:
|
||||||
|
return
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
if event.atom == NET_ACTIVE_WINDOW:
|
||||||
|
if get_active_window()[1]:
|
||||||
|
changed = changed or get_window_class(last_seen['xid'])[1]
|
||||||
|
elif event.atom in (NET_WM_CLASS, WM_CLASS):
|
||||||
|
changed = changed or get_window_class(last_seen['xid'])[1]
|
||||||
|
|
||||||
|
if changed:
|
||||||
|
handle_change(last_seen)
|
||||||
|
|
||||||
|
def handle_change(new_state):
|
||||||
|
"""Replace this with whatever you want to actually do"""
|
||||||
|
print(new_state['title'])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Listen for _NET_ACTIVE_WINDOW changes
|
||||||
|
root.change_attributes(event_mask=Xlib.X.PropertyChangeMask)
|
||||||
|
|
||||||
|
# Prime last_seen with whatever window was active when we started this
|
||||||
|
get_window_class(get_active_window()[0])
|
||||||
|
handle_change(last_seen)
|
||||||
|
|
||||||
|
while True: # next_event() sleeps until we get an event
|
||||||
|
handle_xevent(disp.next_event())
|
Binary file not shown.
@@ -18,6 +18,7 @@
|
|||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <X11/Xlib.h> // `apt-get install libx11-dev`
|
#include <X11/Xlib.h> // `apt-get install libx11-dev`
|
||||||
#include <X11/Xmu/WinUtil.h> // `apt-get install libxmu-dev`
|
#include <X11/Xmu/WinUtil.h> // `apt-get install libxmu-dev`
|
||||||
#include <json-c/json.h> // `apt install libjson-c-dev`
|
#include <json-c/json.h> // `apt install libjson-c-dev`
|
||||||
@@ -58,9 +59,20 @@ int strcicmp(char const *a, char const *b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Display* open_display(){
|
Display* open_display(){
|
||||||
|
int i;
|
||||||
Display* d = XOpenDisplay(NULL);
|
Display* d = XOpenDisplay(NULL);
|
||||||
|
for (i = 0; i < 60; i++) {
|
||||||
|
if(d == NULL){
|
||||||
|
printf("fail to open X server display...\n");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
if(d == NULL){
|
if(d == NULL){
|
||||||
printf("fail to open X server display...\n");
|
printf("fail to open X server display for 1 minute...\n");
|
||||||
|
printf("Kintox11 is now exiting...\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
@@ -100,16 +112,15 @@ Window get_top_window(Display* d, Window start){
|
|||||||
unsigned int nchildren;
|
unsigned int nchildren;
|
||||||
Status s;
|
Status s;
|
||||||
|
|
||||||
// printf("getting top window ... \n");
|
while (parent != root && parent != 0) {
|
||||||
while (parent != root) {
|
|
||||||
w = parent;
|
w = parent;
|
||||||
s = XQueryTree(d, w, &root, &parent, &children, &nchildren); // see man
|
s = XQueryTree(d, w, &root, &parent, &children, &nchildren); // see man
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
XFree(children);
|
XFree(children);
|
||||||
|
|
||||||
if(xerror || w == 0){
|
if(xerror){
|
||||||
printf("fail\n");
|
printf("fail to get top window: %ld\n",w);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,7 +338,7 @@ int main(void){
|
|||||||
// printf("window:%#x name:%s\n", w, name);
|
// printf("window:%#x name:%s\n", w, name);
|
||||||
// printf("%s\n","1");
|
// printf("%s\n","1");
|
||||||
// printf("%s\n",str_window_class(d, w,prior_app));
|
// printf("%s\n",str_window_class(d, w,prior_app));
|
||||||
if(strcmp(current_app,prior_app)){
|
if(strcmp(current_app,prior_app) || !strcmp(current_app,"none")){
|
||||||
// printf("%s\n","2");
|
// printf("%s\n","2");
|
||||||
for(i = 0; i < arraylen; ++i){
|
for(i = 0; i < arraylen; ++i){
|
||||||
if(breakouter == 0){
|
if(breakouter == 0){
|
||||||
|
17
setup.py
17
setup.py
@@ -130,23 +130,28 @@ if(onetime):
|
|||||||
print("\nDynamic shortcut tweaks\n")
|
print("\nDynamic shortcut tweaks\n")
|
||||||
|
|
||||||
intents = [obj for obj in user_config['de'] if(obj['intent'] == "gui_term")]
|
intents = [obj for obj in user_config['de'] if(obj['intent'] == "gui_term")]
|
||||||
|
tweaks = []
|
||||||
|
tweaks_selected = []
|
||||||
|
|
||||||
for index, k in enumerate(intents):
|
for index, k in enumerate(intents):
|
||||||
print(color_arr[default-1] + bcolors.BOLD + str(index+1) + '. ' + k['name'] + bcolors.ENDC)
|
print(color_arr[default-1] + bcolors.BOLD + str(index+1) + '. ' + k['name'] + bcolors.ENDC)
|
||||||
print(bcolors.CYELLOW + 'Description: ' + k['description'] + bcolors.ENDC)
|
print(bcolors.CYELLOW + 'Description: ' + k['description'] + bcolors.ENDC)
|
||||||
print(bcolors.CYELLOW + 'run in gui mode: ' + k['run_gui'].replace(";", "\n") + bcolors.ENDC)
|
print(bcolors.CYELLOW + 'run in gui mode: ' + k['run_gui'].replace(";", "\n") + bcolors.ENDC)
|
||||||
print(bcolors.CYELLOW + 'run in terminal mode: ' + k['run_term'].replace(";", "\n") + bcolors.ENDC + '\n')
|
print(bcolors.CYELLOW + 'run in terminal mode: ' + k['run_term'].replace(";", "\n") + bcolors.ENDC + '\n')
|
||||||
|
tweaks.append(k['id'])
|
||||||
|
|
||||||
print(bcolors.CYELLOW + "Please enter your dynamic shortcut tweak(s) (eg 1 or 1 2 3 - leave blank to skip): " + bcolors.ENDC)
|
print(bcolors.CYELLOW + "Please enter your dynamic shortcut tweak(s) (eg 1 or 1 2 3 - leave blank to skip): " + bcolors.ENDC)
|
||||||
defaultde = [int(i) for i in input().split()]
|
defaultde = [int(i) for i in input().split()]
|
||||||
if len(defaultde) != 0:
|
|
||||||
# gui
|
|
||||||
user_config['config'][0]['de'] = defaultde
|
|
||||||
# term
|
|
||||||
user_config['config'][1]['de'] = defaultde
|
|
||||||
|
|
||||||
for d in defaultde:
|
for d in defaultde:
|
||||||
user_config['de'][d-1]['active'] = True
|
user_config['de'][tweaks[d-1]]['active'] = True
|
||||||
|
tweaks_selected.append(tweaks[d-1])
|
||||||
|
|
||||||
|
if len(defaultde) != 0:
|
||||||
|
# gui
|
||||||
|
user_config['config'][0]['de'] = tweaks_selected
|
||||||
|
# term
|
||||||
|
user_config['config'][1]['de'] = tweaks_selected
|
||||||
|
|
||||||
user_config['config'][0]['run'] = keyboardconfigs[defaultkb-1]['gui']
|
user_config['config'][0]['run'] = keyboardconfigs[defaultkb-1]['gui']
|
||||||
user_config['config'][1]['run'] = keyboardconfigs[defaultkb-1]['term']
|
user_config['config'][1]['run'] = keyboardconfigs[defaultkb-1]['term']
|
||||||
|
@@ -4,9 +4,6 @@ PartOf=graphical-session.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
#User={username}
|
|
||||||
#Group={username}
|
|
||||||
Environment=DISPLAY=:0
|
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=1
|
RestartSec=1
|
||||||
WorkingDirectory=/home/{username}/.config/kinto
|
WorkingDirectory=/home/{username}/.config/kinto
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
Name=Kinto
|
Name=Kinto
|
||||||
GenericName=Kinto
|
GenericName=Kinto
|
||||||
Comment=Make Linux Type Like it's a Mac
|
Comment=Make Linux Type Like it's a Mac
|
||||||
Exec=/bin/systemctrl --user start keyswap
|
Exec=/usr/bin/systemctl --user start keyswap
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
X-GNOME-Autostart-enabled=true
|
X-GNOME-Autostart-enabled=true
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
systemctl --user stop keyswap
|
systemctl --user stop keyswap
|
||||||
systemctl --user disable keyswap
|
systemctl --user disable keyswap
|
||||||
rm -rf ~/.config/autostart/keyswap.sh
|
rm -rf ~/.config/autostart/kinto.desktop
|
||||||
rm -rf ~/.config/kinto
|
rm -rf ~/.config/kinto
|
||||||
rm -rf ~/.xkb
|
rm -rf ~/.xkb
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user