Files
ThinkpadX1Yoga_files/home/bin/tapioca/tapioca.py
T
2018-10-03 21:39:51 +02:00

310 lines
11 KiB
Python
Executable File

#!/usr/bin/python
import evdev
import subprocess
from decimal import Decimal
import time
import os
import ConfigParser
from collections import OrderedDict
from threading import Timer, Thread
from pymouse import PyMouse
import argparse
import sys
import math
# todo
# long press should not work on two finger long press
# implement three finger tap
# implement swipes
mouse = PyMouse()
app_name = "tapioca"
config_folder = os.path.join(os.path.expanduser("~"), '.config', app_name)
config_file = app_name + ".conf"
full_config_file_path = os.path.join(config_folder, config_file)
Config = ConfigParser.ConfigParser(allow_no_value=True)
parser = argparse.ArgumentParser(
description=app_name + " enables right click on linux touchscreen devices.")
parser.add_argument(
"--device", help="Specify name of your touch panel make" \
" (can be found out by running xinput command).")
args = parser.parse_args()
# print(args.device)
# do not edit these settings, all settings should be changed in .conf file
# in user section
default_section = "Default Settings"
user_section = "User Settings"
default_settings = OrderedDict([
('; Touch panel make (run xinput command in terminal)', None),
('touch_panel', ""),
('; Minimum long press time in seconds, e.g - 0.5, 1.2', None),
('minimum_long_press_time', 1.5),
('; Right click methods, possible values - xdotool, pymouse', None),
('right_click_method', 'xdotool'),
('; Long press behavior, possible values - pc (menu appears after finger lift),' \
' smartphone (no finger lift required, menu flickers once)', None),
('long_press_behavior', 'pc'),
('; Long press, possible values - 1 (True), 0 (False)', None),
('enable_long_press', 1),
('; Two finger tap, possible values - 1 (True), 0 (False)', None),
('enable_two_finger_tap', 1)
])
def setconfig():
try:
if os.stat(full_config_file_path).st_size > 0:
file_empty = False
else:
file_empty = True
except OSError:
pass
if not os.path.exists(config_folder):
os.makedirs(config_folder)
if not os.path.exists(full_config_file_path) or file_empty == True:
with open(full_config_file_path, "w+") as f:
Config.add_section(default_section)
Config.set(
default_section, '; !!!! do not edit, change settings in user section !!!!')
for k, v in default_settings.items():
if v == None:
Config.set(default_section, k)
else:
Config.set(default_section, k, v)
Config.add_section(user_section)
Config.set(user_section, '; change settings below')
for k, v in default_settings.items():
if v == None:
Config.set(user_section, k)
else:
Config.set(user_section, k, v)
Config.write(f)
if args.device != None:
with open(full_config_file_path, "w") as b:
Config.set(user_section, "touch_panel", args.device)
Config.write(b)
try:
setconfig()
except KeyboardInterrupt:
sys.exit(1)
Config.read(full_config_file_path)
try:
touch_panel = Config.get(user_section, "touch_panel")
except:
try:
touch_panel = Config.get(default_section, "touch_panel")
except:
touch_panel = default_settings['touch_panel']
try:
minimum_long_press_time = float(Config.get(
user_section, "minimum_long_press_time"))
except:
try:
minimum_long_press_time = float(Config.get(
default_section, "minimum_long_press_time"))
except:
minimum_long_press_time = default_settings['minimum_long_press_time']
try:
right_click_method = Config.get(user_section, "right_click_method")
except:
try:
right_click_method = Config.get(default_section, "right_click_method")
except:
right_click_method = default_settings['right_click_method']
try:
long_press_behavior = Config.get(user_section, "long_press_behavior")
except:
try:
long_press_behavior = Config.get(
default_section, "long_press_behavior")
except:
long_press_behavior = default_settings['long_press_behavior']
try:
enable_long_press = Config.getboolean(user_section, "enable_long_press")
except:
try:
enable_long_press = Config.getboolean(
default_section, "enable_long_press")
except:
enable_long_press = default_settings['enable_long_press']
try:
enable_two_finger_tap = Config.getboolean(
user_section, "enable_two_finger_tap")
except:
try:
enable_two_finger_tap = Config.getboolean(
default_section, "enable_two_finger_tap")
except:
enable_two_finger_tap = default_settings['enable_two_finger_tap']
lift_time = None
touch_time = None
touch_x = 0
touch_y = 0
finger0_time = None
finger1_time = None
finger2_time = None
abs_touch_time = None
abs_lift_time = None
no_device_found = True
long_press_done = False
dev_abs_x = 0
dev_abs_y = 0
def rclick():
if right_click_method == "xdotool":
# proc = subprocess.Popen("eval $(xdotool getmouselocation --shell) && echo $X $Y", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell = True ).communicate()
# print proc[0]
# p = proc[0].strip('\n')
# xc = int(p.partition(' ')[0])
# yc = int(p.partition(' ')[2])
# print xc, yc
# subprocess.Popen(["xdotool", "mousemove", "--sync", str(xc), str(yc)], shell = False)
subprocess.Popen(["xdotool", "click", "3"], stdout=subprocess.PIPE)
elif right_click_method == "pymouse":
mouse.click(mouse.position()[0], mouse.position()[1], 2)
def dummy(time):
pass
while True:
try:
devices = [evdev.InputDevice(fn) for fn in evdev.list_devices()]
for device in devices:
# print(device.fn, device.name, device.phys)
# print device.name
if (device.name == touch_panel):
input_node = device.fn
no_device_found = False
if no_device_found == True:
print "No touch input detected."
print "Please make sure you have entered correct touch panel name in user settings."
print "Quitting in 10 seconds."
time.sleep(10)
quit()
device = evdev.InputDevice(input_node)
# print device
# print device.capabilities(verbose=True)
# print device.active_keys(verbose=True)
for event in device.read_loop():
try:
# print(evdev.util.categorize(event))
if event.type == 3: # absolute axis event
if event.code == 0:
dev_abs_x = event.value
elif event.code == 1:
dev_abs_y = event.value
elif event.type == 1: # key event
#print(evdev.util.categorize(event))
#print event.code
pass
else:
#print(evdev.util.categorize(event))
#print event.type
pass
if event.code == 321 and event.value == 0:
print "stylus tool rubber click"
rclick()
if event.code == 330 and event.value == 1:
touch_time = Decimal(str(event.sec) + "." + str(event.usec))
touch_x = dev_abs_x
touch_y = dev_abs_y
# print touch_time, " (", touch_x, ", ", touch_y, ")"
t = Timer(minimum_long_press_time, dummy, [touch_time])
t.daemon = True
t.start()
if event.code == 330 and event.value == 0:
lift_time = Decimal(str(event.sec) + "." + str(event.usec))
# print lift_time
else:
lift_time = None
if event.code == 47 and event.value == 0:
finger0_time = Decimal(str(event.sec) + "." + str(event.usec))
# print finger0_time
if event.code == 47 and event.value == 1:
finger1_time = Decimal(str(event.sec) + "." + str(event.usec))
# print finger1_time
if event.code == 47 and event.value == 2:
finger2_time = Decimal(str(event.sec) + "." + str(event.usec))
# print finger2_time
if event.code == 57 and event.value > -1:
abs_touch_time = Decimal(str(event.sec) + "." + str(event.usec))
# print abs_touch_time
t = Timer(minimum_long_press_time, dummy, [abs_touch_time])
t.daemon = True
t.start()
if event.code == 57 and event.value == -1:
abs_lift_time = Decimal(str(event.sec) + "." + str(event.usec))
# print abs_lift_time
else:
abs_lift_time = None
if touch_time != None and lift_time == None and long_press_behavior == "smartphone":
if t.is_alive() == False and long_press_done == False:
if enable_long_press == True:
touch_distance = math.sqrt((touch_x-dev_abs_x)**2+(touch_y-dev_abs_y)**2)
# print "touch distance: ", touch_distance
if touch_distance < 200:
print "smartphone long press"
rclick()
long_press_done = True
t.cancel()
t.join()
if touch_time != None and lift_time != None and enable_long_press == True:
diff = lift_time - touch_time
# print diff
if diff >= minimum_long_press_time and long_press_behavior == "pc":
print "pc long press"
rclick()
if event.code == 330 and event.value == 0:
if long_press_done == True and long_press_behavior == "smartphone":
rclick()
long_press_done = False
touch_time = None
if finger0_time != None and finger1_time != None and enable_two_finger_tap == True:
if event.code == 330 and event.value == 0:
if finger0_time == finger1_time:
print "Two finger tap"
rclick()
except (KeyboardInterrupt, SystemExit):
raise
except:
pass
except (KeyboardInterrupt, SystemExit):
raise
except:
pass