PK!4u} linux-touchpad/__init__.pyimport uvloop uvloop.install() PK!S>>linux-touchpad/__main__.pyfrom .main import main if __name__ == '__main__': main() PK!ttlinux-touchpad/lock.pyimport os from contextlib import suppress from .process import kill class LockExistsError(Exception): pass class Lock: path, _ = os.path.split(__file__) _lock = os.path.join(path, '.lock') def __init__(self): if self.islocked(): lockpid = self.getpid() kill(lockpid) self.cleanup() def __enter__(self): self.create_lock() return self def __exit__(self, *args): self.cleanup() def create_lock(self): with open(Lock._lock, 'w+') as fp: fp.write(str(os.getpid())) def cleanup(self): with suppress(FileNotFoundError): os.remove(self._lock) @staticmethod def islocked() -> bool: return os.path.exists(Lock._lock) @staticmethod def getpid(): with open(Lock._lock) as fp: return int(fp.read()) PK!;linux-touchpad/main.pyimport os import asyncio as aio import signal import argparse from .lock import Lock, LockExistsError from .touchpad import SIGTOGGLE, watch_devices from .process import handler def start(): try: with Lock(): signal.signal(signal.SIGTERM, handler) signal.signal(SIGTOGGLE, handler) aio.run(watch_devices()) except LockExistsError: pass def signal_toggle(): pid = Lock.getpid() os.kill(pid, SIGTOGGLE) def signal_kill(): pid = Lock.getpid() os.kill(pid, signal.SIGTERM) def main(): choices = { 'start': start, 'toggle': signal_toggle, 'kill': signal_kill } parser = argparse.ArgumentParser( prog="linux-touchpad", description="Auto disable touchpad when mouse is detected." ) parser.add_argument('command', choices=choices) args = parser.parse_args() command = choices[args.command] command() if __name__ == '__main__': main() PK!vlinux-touchpad/process.pyimport os from contextlib import suppress from . import touchpad as tp def handler(signum, frame): if signum == tp.SIGTOGGLE: tp.toggle() else: tp.kill() def kill(ps): with suppress(ProcessLookupError): os.kill(ps, 9) PK!Za))linux-touchpad/touchpad.pyimport re import subprocess as subp import signal import asyncio as aio from operator import itemgetter from typing import Coroutine SIGTOGGLE = signal.SIGUSR1 DEVICE_RE = re.compile(r'(\w.+\b(?=\W.+id))(?:.+id=)(\d+)') ENABLED_RE = re.compile(r'(?:Device Enabled.*\t)(1)') toggled = False running = True def toggle(): global toggled toggled = not toggled def kill(): global running running = False async def run(command: list) -> str: ps = await aio.create_subprocess_exec(*command, stdout=subp.PIPE) raw = await ps.stdout.read() return raw.decode() async def get_devices() -> dict: rawout = await run(['xinput', 'list']) out = re.findall(DEVICE_RE, rawout) props = await aio.gather(*(parse_props(name, id) for name, id in out)) mice = filter(itemgetter('is_mouse'), props) return {mouse.pop('name'): mouse for mouse in mice} async def parse_props(device: str, device_id: str) -> bool: rawout = await run(['xinput', 'list-props', device_id]) props = { 'name': device if 'touchpad' not in device.casefold() else 'touchpad', 'id': device_id, 'is_enabled': bool(re.search(ENABLED_RE, rawout)), 'is_mouse': bool(re.search('Accel Speed', rawout)), } return props async def disable_device(device_id): await run(['xinput', 'disable', device_id]) async def enable_device(device_id): await run(['xinput', 'enable', device_id]) async def get_action() -> Coroutine: global toggled devices = await get_devices() touchpad = devices.pop('touchpad') mouse_exists = len(devices) > 1 touchpad_enabled = touchpad['is_enabled'] touchpad_id = touchpad['id'] if (toggled or not mouse_exists) and not touchpad_enabled: return enable_device(touchpad_id) elif mouse_exists and touchpad_enabled and not toggled: return disable_device(touchpad_id) else: return aio.sleep(0) async def watch_devices(): global running while running: action = await get_action() await aio.gather(action, aio.sleep(1)) PK!Q77&linux_touchpad-0.1.5.dist-info/LICENSE The MIT License (MIT) Copyright (c) 2019 Noah Corona 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. PK!HڽTU$linux_touchpad-0.1.5.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HV2#w~'linux_touchpad-0.1.5.dist-info/METADATAUmoDbHFkE+Jwj; =5ά_&j|흗gyfϸ4VhqBiأQ&}Yr$pᝎ2aJ"H^9]u 8[a!C,f用pt WUr;8a)*K.7 ZH'ՄIhҦf&[͋%’ O?hŭ^:vyaF2Nإ֊@Á$w\T[;w\^BpU`% O'_jx>Uw%KoQwɏ2 Z]'piLkWhS#*G.r\h*j7%m2]+FDyb~]eEJsZK)7hID |ReJ<~ 36nj-{K\.Y}>(!Jʻ?^꺎K6ԔoapИ5-)b`RpȭDa-hԼ 1rt \FhÉ.tǰ(ȠgY'F{X)ZWZE vƫ 4Wq[lꍄί%`xw2 bMڵ_A-ʹGW  I;EP3)W"Br+QM`]jv-'Sht4{_FKl-$?u_jgo6e(u{Qd?f>E~@D°C>R(w[ {Np W'@$'UJGai21`!D0[$ tQZ28pͽt@XuWH޲霻R:og~)=v(w|՞lA<;^,!Duf<ig0E`K{2^aaO\lV,48?җa>i xOn3ZKeGkQ6/وA6tw+ ,\*sòPK!HWŰ$%linux_touchpad-0.1.5.dist-info/RECORDɒ0{? ؆nQYqI! ;SSSV9g&\G;!=!uHnNjR8EVY]øZ6,d%#Q܇ƞ"?߆1U]`}cq_wy:&';NdU?`Zx~Shw=.<3yckcr!Eͣq:Γ(G9VUv$vdfqƥ0ec>Xlinux-touchpad/__main__.pyPK!ttlinux-touchpad/lock.pyPK!;vlinux-touchpad/main.pyPK!vlinux-touchpad/process.pyPK!Za)) linux-touchpad/touchpad.pyPK!Q77&#linux_touchpad-0.1.5.dist-info/LICENSEPK!HڽTU$linux_touchpad-0.1.5.dist-info/WHEELPK!HV2#w~'4linux_touchpad-0.1.5.dist-info/METADATAPK!HWŰ$%llinux_touchpad-0.1.5.dist-info/RECORDPK