Being spoiled by window management on both Linux and Mac, I want all the good things combined. Three-finger swipe to change desktop? Great. Alt+mouse anywhere to move/resize window? Much better than aiming at tiny GUI parts but do I really have to reach for both the keyboard and mouse? Four fingers on trackpad should move windows, right? After all, mouse feels evil being spoiled by Mac trackpad. So after a vain search for a system I could configure to respond really well, I wrote this little goody. And I absolutely love my window management now.
You need python3 with libraries evdev
and python-libxdo
. You also need to be in the input
group. And you need to make sure hacktrack
is run when you log in to your GUI. Here are the commands for Debian:
sudo apt-get install python3.12-venv python3-dev xdotool git
sudo gpasswd -a YOUR-OWN-USERNAME input
Log out and log back in.
git clone git@github.com:vaclavhanzl/hacktrack.git
cd hacktrack
python3 -m venv env
env/bin/pip3 install python-libxdo evdev
Verify that everything works:
env/bin/python3 hacktrack
Than make sure start-hacktrack
is run when you log in to your GUI. For example, with Xfce4, you may do it here:
Applications/Settings/Settings Manager, System, Session and Startup. Use full path to the script,
something like /home/......./hacktrack/start-hacktrack
.
For desktop changes, you will likely need to modify commands used in the hacktrack source according to your desktop setup.
You can alternatively clone the code using the https
variant:
git clone https://github.com/vaclavhanzl/hacktrack.git
To verify that you are in the input
group, do:
groups
and you should have a list containing this group, e.g.:
hanzl cdrom floppy sudo audio dip video plugdev netdev bluetooth lpadmin scanner input
^^^^^
If input
is not there, use the gpasswd
command mentioned above and log out and log in.
To test hacktrack, go to the cloned directory and try to run it directly from the command line:
cd hacktrack
env/bin/python3 hacktrack
Look for any errors you get. If you see any import problems, verify installation of libraries by running:
env/bin/python3
and at the python command prompt, try:
import evdev
from xdo import Xdo
Both should work without any error messages. If there are some complaints, make sure you did BOTH the apt-get
part of installation AND the pip3 install
one.
The Xdo
python library needs the apt
package xdotool
.
If you see something like:
PermissionError: [Errno 13] Permission denied: '/dev/input/by-id/usb-Apple_Inc._Magic_Trackpad_2_CC28192005HJ2Y1AM-if01-event-mouse'
you likely need the input
group permissions - see above and do not forget to log out and in.
This is an alpha stage project. Some more automatic installation is certainly due.
I tried whatever I found before writing the tool myself, of course. Rather surprisingly, the key decision which allowed me to make this code simple and ergonomic was to NOT use library like libinput which is there to help me. Instead, I get raw trackpad events directly from the kernel. Sounds scary but is actually very easy. The problem with the (great) libinput is that it does only the things it can do well. It is not a place for experiments. If you want to be on the edge with crazy ideas, you need your experimental code PLUS a hacked version of libinput. This forked hacked libinput gets quickly unmaintained and it clashes with the libinput in your system. On the other hand, working in parallel with libinput (and anything like libinput-gestures on top of it) is really hassle free.
Four fingers can move in many ways. The tool just computes "center of gravity" (average position) of all four fingers and as this average point moves, the window moves. Use your creativity to find out how to use it with your hands. For example:
Just spread/shrink 5 fingers touching the trackpad and you will certainly figure it out. But for the curious, the algorithm looks for a bounding rectangle which contains your touch points. Relative changes of this rectangle's width and height then change width and height of the window. Again, you can get creative in many ways:
All this is actually fun to experiment with, you will certainly find a way you like.
This one is actually just boring port of functionality I like on Mac. You can also get it easily with libinput-gestures so you may want to just disable it in hacktrack by changing this:
@event_eater
def three_finger_desktop_drag():
into this (comment out the decorator):
#@event_eater
def three_finger_desktop_drag():
If you want to use it, you need to match your desktop layout and the source code. It is no rocket science. My desktop is Xfce4 and I have a row of virtual desktops in a panel which appears when mouse pointer is at the lower edge of my display. When the pointer is elsewhere, the panel autohides. This part of the hacktrack source code forms the interface to my desktops:
def desk_show():
os.system("xfconf-query -c xfce4-panel -p /panels/panel-2/autohide-behavior -s 0")
def desk_hide(): # still shown if mouse at lower screen edge
os.system("xfconf-query -c xfce4-panel -p /panels/panel-2/autohide-behavior -s 2")
def desk_left(): # like swipe-left on Mac (windows move left, our view moves right)
os.system("xdotool key alt+ctrl+Right")
def desk_right():
os.system("xdotool key alt+ctrl+Left")
panel-2
to show/hide it. Your pannel can have different number.alt+ctrl+Right
and alt+ctrl+Left
to change desktops. You may need some other keys.Also, you may use other commands than xfconf-query
and xdotool
to send instructions to your desktop.
This one is really experimental and is disabled in the code:
#@event_eater
def abs_pos_mouse_by_tap():
Remove the #
to activate it. Also, unless your monitor happens to be 4K as the mine is, put the right size here:
desktop_range = ((0, 3840), (0, 2160)) # x, y
Then you can tap the trackpad (slightly less than what would make it to click) at any point and the mouse cursor will appear at the corresponding absolute position of your screen. It is a neat way to find your cursor (or in fact not to search for it but place it where you want it) but I did not like it as much as the other features.
This is why you came here, right? It is really easy. The @event_eater
decorator puts your procedure among those who recieve slightly cooked trackpad events (if you ever worked with mouse moving events, this is a similar thing). Try this:
@event_eater
def eater():
while True:
x = (yield)
print(x)
and look what is printed and than do something useful instead of the print. The code is full of examples of all the idioms you might need. Enjoy!
Your window environment may contain elements which technically could be moved/resized by hacktrack but you do not want it. Code tries to avoid moving these:
if str(name).startswith("b'Desktop'"):
# we are technically able to move this but do not want to
print("Avoided Desktop drag")
continue
and it works good enough for me but can be different for you.
For a lot more of similar wisdom, you may have look at libinput-gestures or even install it. It has similar dependencies so if you make it to work for you, quite likely your computer will be also ready for hacktrack by then.
You can discuss hacktrack in public here in Discussions.
If you want to tell me more personally that you love this or hate this, message @vaclavh@sigmoid.social
on Mastodon.