Added tapioca

This commit is contained in:
2018-10-03 21:39:51 +02:00
parent ab49ee4cee
commit 6b01a0b0cc
4 changed files with 381 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
#!/bin/bash
SCRIPTPATH=`realpath $0`
cd `dirname $SCRIPTPATH`/tapioca
python tapioca.py --device "" > /dev/null
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 nitg16
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+46
View File
@@ -0,0 +1,46 @@
# Tapioca
Tapioca enables right click on linux touchscreen devices using technologies like python-evedev, pymouse (PyUserInput) and xdotool.
# Available Gestures
Long press right click and two finger tap right click.
# Installation
Tapioca has been tested to work on Ubuntu 17.04. Run commands below to install dependencies.
sudo apt install python-evdev xinput xdotool python-pip
sudo pip install PyUserInput
Download Tapioca from [here](https://github.com/nitg16/tapioca/archive/master.zip) and extract to a folder.
# Running Tapioca
Find out your touch panel make by running `xinput` command.
Now run the command below to launch Tapioca.
sudo python tapioca.py --device ""
Add the name of your touch panel make within the quotes.
# Configuring Tapioca
`tapioca.conf` file is located in `~/.config/tapioca/` folder.
It is automatically created when you run Tapioca for the first time. Your device name is also automatically added to the config file if you use the command mentioned above to run the application.
You can edit settings in `User Settings` in config file. All config options are well commented.
**It is highly recommended that you review config file at least once.**
# Wayland support?
Not possible as of now.
# Credits
* All the developers behind Linux kernel, python-evdev, PyUserInput, pymouse, xdotool and xinput.
* [Python-Touchscreen-RightClick](https://github.com/Zyell/Python-Touchscreen-RightClick)
+309
View File
@@ -0,0 +1,309 @@
#!/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