Skip to content

Commit bc69ac9

Browse files
committed
Add ability to move diagonally on virtual desktop
See the comments added about configuring this in libinput-gestures.conf. This is an enhancement added to address issue #224.
1 parent dcdc33b commit bc69ac9

File tree

7 files changed

+982
-242
lines changed

7 files changed

+982
-242
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1-
README.html
21
.idea/
32
.vscode/
3+
README.html
4+
*.pyc
5+
__pycache__
6+
*~

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@ uninstall:
2727
@./libinput-gestures-setup -d "$(DESTDIR)" uninstall
2828

2929
check:
30-
flake8 libinput-gestures
30+
flake8 libinput-gestures internal internal-test
3131
shellcheck $(SHELLCHECK_OPTS) libinput-gestures-setup list-version-hashes
3232

3333
doc: $(DOCOUT)
3434

3535
$(DOCOUT): $(DOC)
3636
markdown $< >$@
3737

38+
test:
39+
@./internal-test
40+
3841
clean:
3942
rm -rf $(DOCOUT)

README.md

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,23 @@ reading ..
7979

8080
The default gestures are in `/etc/libinput-gestures.conf`. If you want
8181
to create your own custom gestures then copy that file to
82-
`~/.config/libinput-gestures.conf` and edit it. The available gestures
83-
are:
84-
85-
- swipe up (e.g. map to GNOME/KDE/etc move to next workspace)
86-
- swipe down (e.g map to GNOME/KDE/etc move to prev workspace)
87-
- swipe left (e.g. map to Web browser go forward)
88-
- swipe right (e.g. map to Web browser go back)
89-
- pinch in (e.g. map to GNOME open/close overview)
90-
- pinch out (e.g. map to GNOME open/close overview)
82+
`~/.config/libinput-gestures.conf` and edit it. There are many examples
83+
and options described in that file. The available gestures are:
84+
85+
|Gesture |Example Mapping |
86+
|------- |--------------- |
87+
|`swipe up` |GNOME/KDE/etc move to next workspace |
88+
|`swipe down` |GNOME/KDE/etc move to prev workspace |
89+
|`swipe left` |Web browser go forward |
90+
|`swipe right` |Web browser go back |
91+
|`swipe left_up` |Jump to next open web browser tab |
92+
|`swipe left_down` |Jump to previous open web browser tab |
93+
|`swipe right_up` |Close current web browser tab |
94+
|`swipe right_down` |Reopen and jump to last closed web browser tab |
95+
|`pinch in` |GNOME open/close overview |
96+
|`pinch out` |GNOME open/close overview |
97+
|`pinch clockwise` ||
98+
|`pinch anticlockwise` ||
9199

92100
NOTE: If you don't use "natural" scrolling direction for your touchpad
93101
then you may want to swap the default left/right and up/down
@@ -223,12 +231,12 @@ configuration file but you can enable extended gestures which augment
223231
the gestures listed above in CONFIGURATION. See the commented out
224232
examples in `libinput-gestures.conf`.
225233

226-
- swipe right_up (e.g. jump to next open browser tab)
227-
- swipe left_up (e.g. jump to previous open browser tab)
228-
- swipe left_down (e.g. close current browser tab)
229-
- swipe right_down (e.g. reopen and jump to last closed browser tab)
230-
- pinch clockwise
231-
- pinch anticlockwise
234+
- `swipe right_up` (e.g. jump to next open browser tab)
235+
- `swipe left_up` (e.g. jump to previous open browser tab)
236+
- `swipe left_down` (e.g. close current browser tab)
237+
- `swipe right_down` (e.g. reopen and jump to last closed browser tab)
238+
- `pinch clockwise`
239+
- `pinch anticlockwise`
232240

233241
So instead of just configuring the usual swipe up/down and left/right
234242
each at 90 degrees separation, you can add the above extra 4 swipes to

internal

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#!/usr/bin/env python3
2+
'Command line program to exercise/test/debug the _internal command.'
3+
# Mark Blakeney, Oct 2019
4+
import sys, importlib, argparse
5+
from pathlib import Path
6+
7+
CMD = '_internal'
8+
GESTURE = 'swipe'
9+
PROG = Path(sys.argv[0]).resolve()
10+
NAME = Path.cwd().name
11+
CACHE = Path.home() / '.cache' / PROG.name
12+
13+
def import_path(path, add_to_path=False):
14+
'Import given module path'
15+
modname = Path(path).stem.replace('-', '_')
16+
spec = importlib.util.spec_from_loader(modname,
17+
importlib.machinery.SourceFileLoader(modname, path))
18+
module = importlib.util.module_from_spec(spec)
19+
spec.loader.exec_module(module)
20+
if add_to_path:
21+
sys.modules[modname] = module
22+
return module
23+
24+
opt = argparse.ArgumentParser(description=__doc__)
25+
opt.add_argument('-c', '--conffile',
26+
help='alternative configuration file')
27+
opt.add_argument('-i', '--initial', type=int,
28+
help='initial desktop')
29+
opt.add_argument('-C', '--cols', type=int, default=1,
30+
help='number of columns')
31+
opt.add_argument('-t', '--text', action='store_true',
32+
help='output desktop change in text')
33+
opt.add_argument('-n', '--nocache', action='store_true',
34+
help='do not use cache')
35+
opt.add_argument('num', type=int,
36+
help='number of desktops')
37+
opt.add_argument('action', nargs='?',
38+
help='action to perform')
39+
opt.add_argument('-d', '--display', type=int,
40+
help=argparse.SUPPRESS)
41+
opt.add_argument('-s', '--set', type=int, help=argparse.SUPPRESS)
42+
args = opt.parse_args()
43+
44+
def showgrid(pos, num, cols):
45+
print()
46+
for i in range(num):
47+
end = '\n' if (i % cols) == (cols - 1) else ''
48+
if i == pos:
49+
print(' {:02} '.format(i), end=end)
50+
else:
51+
print(' ** ', end=end)
52+
if end != '\n':
53+
print()
54+
55+
if args.set is not None:
56+
print(args.set)
57+
sys.exit(0)
58+
59+
if args.display is not None:
60+
for i in range(args.num):
61+
print('{} {} -'.format(i, '*' if i == args.display else '-'))
62+
sys.exit(0)
63+
64+
if args.initial is None:
65+
if args.nocache:
66+
opt.error('Initial value must be specified')
67+
if not CACHE.exists():
68+
opt.error('Need initial desktop specified')
69+
start = int(CACHE.read_text().strip())
70+
else:
71+
start = args.initial
72+
73+
lg = import_path(NAME)
74+
icmd = lg.internal_commands[CMD]
75+
76+
icmd.CMDLIST = '{} -d {} {}'.format(PROG, start, args.num).split()
77+
icmd.CMDSET = '{} {} -s'.format(PROG, args.num).split()
78+
79+
lg.read_conf(args.conffile, NAME + '.conf')
80+
motions = lg.handlers[GESTURE.upper()].motions
81+
actions = {k: v for k, v in motions.items() if isinstance(v, icmd)}
82+
83+
if not args.action or args.action not in actions:
84+
opt.error('action must be one of {}'.format(list(actions.keys())))
85+
86+
cmd = motions[args.action]
87+
print('Command "{} {} is "{}"'.format(GESTURE, args.action, cmd))
88+
res = cmd.run(block=True)
89+
90+
if res:
91+
end = int(res.strip())
92+
if not args.nocache:
93+
CACHE.write_text(str(end))
94+
else:
95+
end = start
96+
97+
if end < 0 or end >= args.num:
98+
sys.exit('Desktop change from {} to {}, out of range 0 to <{}!'.format(
99+
start, end, args.num))
100+
101+
if args.text:
102+
if start != end:
103+
print('Desktop change from {} to {}'.format(start, end))
104+
else:
105+
print('No change')
106+
else:
107+
showgrid(start, args.num, args.cols)
108+
showgrid(end, args.num, args.cols)

0 commit comments

Comments
 (0)