Skip to content

Instantly share code, notes, and snippets.

@khalid151
Created February 20, 2021 11:36
Show Gist options
  • Save khalid151/1c9450b5554b641504db5d949fda5964 to your computer and use it in GitHub Desktop.
Save khalid151/1c9450b5554b641504db5d949fda5964 to your computer and use it in GitHub Desktop.
Wrapper around `xdotool` and `xsetwacom` to toggle wacom tablet focus between different monitors and windows,
#!/bin/env python3
from subprocess import check_output as output
from subprocess import run
from os.path import exists
from subprocess import CalledProcessError
import argparse
import re
import sys
wacom_max_res = (44800, 29600) # Width, height
def status(new=None):
if new is not None:
with open('/tmp/wacom_focus_status', 'w') as f:
f.write(str(new))
else:
with open('/tmp/wacom_focus_status', 'r') as f:
return int(f.read())
def get_window_info(id=None):
try:
win_id = id if id is not None else output(['xdotool', 'getactivewindow']).decode()
except CalledProcessError:
sys.stderr.write("Could not find window\n")
exit(1)
info = output(['xdotool', 'getwindowgeometry', win_id]).decode()
frame = re.findall(r'\b(\d+)+\b', output(['xprop', '_NET_FRAME_EXTENTS', '-id', win_id]).decode())
pos = re.search(r'\b\d+,\d+\b', info).group(0).split(',')
geo = re.search(r'\b\d+x\d+\b', info).group(0).split('x')
if frame == []:
frame = [0, 0, 0, 0]
return {
'x': int(pos[0]),# - int(frame[0]),
'y': int(pos[1]) - int(frame[2]),
'w': int(geo[0]) - int(frame[1]),
'h': int(geo[1]) - int(frame[3]),
}
def map_to_area(x, y, w, h):
if wacom_max_res[0]/wacom_max_res[1] < w/h:
width = wacom_max_res[0]
height = int(width * h/w)
else:
height = wacom_max_res[1]
width = int(height * w/h)
center_x = int((wacom_max_res[0]-width)/2)
center_y = int((wacom_max_res[1]-height)/2)
cmd_area = lambda dev: ['xsetwacom', '--set', f'Wacom Intuos Pro M Pen {dev}', 'Area', str(center_x), str(center_y), str(width+center_x), str(height+center_y)]
cmd_map = lambda dev: ['xsetwacom', '--set', f'Wacom Intuos Pro M Pen {dev}', 'MapToOutput', f'{w}x{h}+{x}+{y}']
run(cmd_area('stylus'))
run(cmd_area('eraser'))
run(cmd_map('stylus'))
run(cmd_map('eraser'))
def get_monitors_res(filter=None):
monitors = output(['xrandr', '--listactivemonitors']).decode().strip().split('\n')[1:]
mons = []
for mon in monitors:
res = re.findall(r'(\d+)/\d+', mon)
pos = re.findall(r'\+(\d+)', mon)
mons.append({
'x': int(pos[0]),
'y': int(pos[1]),
'w': int(res[0]),
'h': int(res[1]),
'name': re.findall(r'\s(\w+-*\d*)$', mon)[0]
})
if filter is not None:
for m in mons:
if m['name'] == filter:
return m
return None
return mons
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-c', '--current-window', action='store_true', help='Map to currently focused window')
parser.add_argument('-t', '--toggle', action='store_true', help='Toggle between monitors and active window')
parser.add_argument('-w', '--window', type=str, help='Map to window ID')
parser.add_argument('-m', '--monitor', type=str, help='Map to monitor')
parser.add_argument('-l', '--list-monitors', action='store_true', help='List active monitors')
area = None
args = parser.parse_args()
if args.toggle:
if not exists('/tmp/wacom_focus_status'):
status(0)
state = status()
monitors = get_monitors_res()
if state == 0:
area = get_window_info()
state += 1
status(state)
area = get_window_info()
else:
area = monitors[state-1]
state += 1
if state > len(monitors):
status(0)
else:
status(state)
elif args.current_window:
area = get_window_info()
elif args.window:
area = get_window_info(args.window)
elif args.monitor:
if re.match(r'\d+', args.monitor):
try:
area = get_monitors_res()[int(args.monitor)]
except IndexError:
sys.stderr.write("Monitor not found. Checked with --list-monitors?\n")
exit(1)
else:
area = get_monitors_res(args.monitor)
if area is None:
sys.stderr.write("Could not find monitor. Checked --list-monitors?\n")
exit(1)
elif args.list_monitors:
for i,m in enumerate(get_monitors_res()):
print(f"{i}: {m['name']} {m['w']}x{m['h']}")
if area is not None:
map_to_area(area['x'], area['y'], area['w'], area['h'])
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment