Proof of concept script to disable the touchpad while typing
#1
I've just quickly made the following script for python, only tested with python3, on the stock Mate pinebook install.
Not sure if other installs move around the xinput device for the touchpad (else replace the 8 with the right number)

This script disables the touchpad of the pinebook for 0.5 second whenever a key is pressed, any key, including ctrl/shift/alt/mod.  So it's not perfect and cannot be use for shift/ctrl+click very effectively yet. But the script could be modified for that.

Note that if you google for the touchpad problem, you will find a lot of mentions for "syndaemon", which doesn't work (and exits without a message) The "synclient" command however will tell you why, because our touchpad isn't showing up as a touchpad but as an emulated mouse.
Hench this hacky script.

And I've just typed this post without a single problem while the script is running. Figured I share this ASAP, as the very sensitive touch pad is at the top of the list of things that people find annoying.

Code:
import threading
import time
import os

class TouchpadHack:
    def __init__(self):
        self.__disabled = False
        self.__condition = threading.Condition()
        self.__disabled_until_time = time.monotonic()
        
        threading.Thread(target=self.timeoutThread).start()
    
    def timeoutThread(self):
        while True:
            with self.__condition:
                self.__condition.wait()
            os.system("xinput disable 8")
            print("disable")
            while time.monotonic() < self.__disabled_until_time:
                time.sleep(self.__disabled_until_time - time.monotonic())
            os.system("xinput enable 8")
            print("enable")

    def inputReadThread(self):
        f = open("/dev/input/event2", "rb")
        while True:
            # We read events here from the keyboard and then just ignore them.
            # The only thing we care about is that an event happens.
            event = f.read(100)
            with self.__condition:
                self.__condition.notify()
                self.__disabled_until_time = time.monotonic() + 0.5

TouchpadHack().inputReadThread()
#2
Will make sure to try it out first thing tomorrow and relay feedback.
You can find me on IRC, Discord and Twitter


#3
With the stuff I had laying around from a different project, I enhanced it a bit, it's a bit more complex now, but it should allow shift/ctrl/alt + click now. And be better protected against different order of hardware initialization.


Code:
import threading
import time
import os
import struct
import fcntl
import subprocess

# ioctl to get the device name of /dev/input/event*
EVIOCGNAME = 0x82004506
EVIOCGBIT = 0x81fe4520

# Format for the linux /dev/input/event* events.
#   tv_sec, tv_usec, type, code, value
EVENT_FMT = "llHHi"

EV_SYN = 0x00
EV_KEY = 0x01
EV_REL = 0x02
EV_ABS = 0x03
EV_MSC = 0x04
EV_SW  = 0x05
EV_LED = 0x11
EV_SND = 0x12
EV_REP = 0x14
EV_FF  = 0x15
EV_PWR = 0x16
EV_FF_STATUS = 0x17

KEY_RESERVED = 0
KEY_ESC = 1
KEY_1 = 2
KEY_2 = 3
KEY_3 = 4
KEY_4 = 5
KEY_5 = 6
KEY_6 = 7
KEY_7 = 8
KEY_8 = 9
KEY_9 = 10
KEY_0 = 11
KEY_MINUS = 12
KEY_EQUAL = 13
KEY_BACKSPACE = 14
KEY_TAB = 15
KEY_Q = 16
KEY_W = 17
KEY_E = 18
KEY_R = 19
KEY_T = 20
KEY_Y = 21
KEY_U = 22
KEY_I = 23
KEY_O = 24
KEY_P = 25
KEY_LEFTBRACE = 26
KEY_RIGHTBRACE = 27
KEY_ENTER = 28
KEY_LEFTCTRL = 29
KEY_A = 30
KEY_S = 31
KEY_D = 32
KEY_F = 33
KEY_G = 34
KEY_H = 35
KEY_J = 36
KEY_K = 37
KEY_L = 38
KEY_SEMICOLON = 39
KEY_APOSTROPHE = 40
KEY_GRAVE = 41
KEY_LEFTSHIFT = 42
KEY_BACKSLASH = 43
KEY_Z = 44
KEY_X = 45
KEY_C = 46
KEY_V = 47
KEY_B = 48
KEY_N = 49
KEY_M = 50
KEY_COMMA = 51
KEY_DOT = 52
KEY_SLASH = 53
KEY_RIGHTSHIFT = 54
KEY_KPASTERISK = 55
KEY_LEFTALT = 56
KEY_SPACE = 57
KEY_CAPSLOCK = 58
KEY_F1 = 59
KEY_F2 = 60
KEY_F3 = 61
KEY_F4 = 62
KEY_F5 = 63
KEY_F6 = 64
KEY_F7 = 65
KEY_F8 = 66
KEY_F9 = 67
KEY_F10 = 68
KEY_NUMLOCK = 69
KEY_SCROLLLOCK = 70
KEY_KP7 = 71
KEY_KP8 = 72
KEY_KP9 = 73
KEY_KPMINUS = 74
KEY_KP4 = 75
KEY_KP5 = 76
KEY_KP6 = 77
KEY_KPPLUS = 78
KEY_KP1 = 79
KEY_KP2 = 80
KEY_KP3 = 81
KEY_KP0 = 82
KEY_KPDOT = 83

KEY_ZENKAKUHANKAKU = 85
KEY_102ND = 86
KEY_F11 = 87
KEY_F12 = 88
KEY_RO = 89
KEY_KATAKANA = 90
KEY_HIRAGANA = 91
KEY_HENKAN = 92
KEY_KATAKANAHIRAGANA = 93
KEY_MUHENKAN = 94
KEY_KPJPCOMMA = 95
KEY_KPENTER = 96
KEY_RIGHTCTRL = 97
KEY_KPSLASH = 98
KEY_SYSRQ = 99
KEY_RIGHTALT = 100
KEY_LINEFEED = 101
KEY_HOME = 102
KEY_UP = 103
KEY_PAGEUP = 104
KEY_LEFT = 105
KEY_RIGHT = 106
KEY_END = 107
KEY_DOWN = 108
KEY_PAGEDOWN = 109
KEY_INSERT = 110
KEY_DELETE = 111
KEY_MACRO = 112
KEY_MUTE = 113
KEY_VOLUMEDOWN = 114
KEY_VOLUMEUP = 115
KEY_POWER = 116 # SC System Power Down
KEY_KPEQUAL = 117
KEY_KPPLUSMINUS = 118
KEY_PAUSE = 119
KEY_SCALE = 120 # AL Compiz Scale (Expose)

KEY_KPCOMMA = 121
KEY_HANGEUL = 122
KEY_HANGUEL = KEY_HANGEUL
KEY_HANJA = 123
KEY_YEN = 124
KEY_LEFTMETA = 125
KEY_RIGHTMETA = 126
KEY_COMPOSE = 127

KEY_STOP = 128 # AC Stop
KEY_AGAIN = 129
KEY_PROPS = 130 # AC Properties
KEY_UNDO = 131 # AC Undo
KEY_FRONT = 132
KEY_COPY = 133 # AC Copy
KEY_OPEN = 134 # AC Open
KEY_PASTE = 135 # AC Paste
KEY_FIND = 136 # AC Search
KEY_CUT = 137 # AC Cut
KEY_HELP = 138 # AL Integrated Help Center
KEY_MENU = 139 # Menu (show menu)
KEY_CALC = 140 # AL Calculator
KEY_SETUP = 141
KEY_SLEEP = 142 # SC System Sleep
KEY_WAKEUP = 143 # System Wake Up
KEY_FILE = 144 # AL Local Machine Browser
KEY_SENDFILE = 145
KEY_DELETEFILE = 146
KEY_XFER = 147
KEY_PROG1 = 148
KEY_PROG2 = 149
KEY_WWW = 150 # AL Internet Browser
KEY_MSDOS = 151
KEY_COFFEE = 152 # AL Terminal Lock/Screensaver
KEY_SCREENLOCK = KEY_COFFEE
KEY_ROTATE_DISPLAY = 153 # Display orientation for e.g. tablets
KEY_DIRECTION = KEY_ROTATE_DISPLAY
KEY_CYCLEWINDOWS = 154
KEY_MAIL = 155
KEY_BOOKMARKS = 156 # AC Bookmarks
KEY_COMPUTER = 157
KEY_BACK = 158 # AC Back
KEY_FORWARD = 159 # AC Forward
KEY_CLOSECD = 160
KEY_EJECTCD = 161
KEY_EJECTCLOSECD = 162
KEY_NEXTSONG = 163
KEY_PLAYPAUSE = 164
KEY_PREVIOUSSONG = 165
KEY_STOPCD = 166
KEY_RECORD = 167
KEY_REWIND = 168
KEY_PHONE = 169 # Media Select Telephone
KEY_ISO = 170
KEY_CONFIG = 171 # AL Consumer Control Configuration
KEY_HOMEPAGE = 172 # AC Home
KEY_REFRESH = 173 # AC Refresh
KEY_EXIT = 174 # AC Exit
KEY_MOVE = 175
KEY_EDIT = 176
KEY_SCROLLUP = 177
KEY_SCROLLDOWN = 178
KEY_KPLEFTPAREN = 179
KEY_KPRIGHTPAREN = 180
KEY_NEW = 181 # AC New
KEY_REDO = 182 # AC Redo/Repeat

KEY_F13 = 183
KEY_F14 = 184
KEY_F15 = 185
KEY_F16 = 186
KEY_F17 = 187
KEY_F18 = 188
KEY_F19 = 189
KEY_F20 = 190
KEY_F21 = 191
KEY_F22 = 192
KEY_F23 = 193
KEY_F24 = 194

KEY_PLAYCD = 200
KEY_PAUSECD = 201
KEY_PROG3 = 202
KEY_PROG4 = 203
KEY_DASHBOARD = 204 # AL Dashboard
KEY_SUSPEND = 205
KEY_CLOSE = 206 # AC Close
KEY_PLAY = 207
KEY_FASTFORWARD = 208
KEY_BASSBOOST = 209
KEY_PRINT = 210 # AC Print
KEY_HP = 211
KEY_CAMERA = 212
KEY_SOUND = 213
KEY_QUESTION = 214
KEY_EMAIL = 215
KEY_CHAT = 216
KEY_SEARCH = 217
KEY_CONNECT = 218
KEY_FINANCE = 219 # AL Checkbook/Finance
KEY_SPORT = 220
KEY_SHOP = 221
KEY_ALTERASE = 222
KEY_CANCEL = 223 # AC Cancel
KEY_BRIGHTNESSDOWN = 224
KEY_BRIGHTNESSUP = 225
KEY_MEDIA = 226

KEY_SWITCHVIDEOMODE = 227 # Cycle between available video outputs (Monitor/LCD/TV-out/etc)
KEY_KBDILLUMTOGGLE = 228
KEY_KBDILLUMDOWN = 229
KEY_KBDILLUMUP = 230

KEY_SEND = 231 # AC Send
KEY_REPLY = 232 # AC Reply
KEY_FORWARDMAIL = 233 # AC Forward Msg
KEY_SAVE = 234 # AC Save
KEY_DOCUMENTS = 235

KEY_BATTERY = 236

KEY_BLUETOOTH = 237
KEY_WLAN = 238
KEY_UWB = 239

KEY_UNKNOWN = 240

KEY_VIDEO_NEXT = 241 # drive next video source
KEY_VIDEO_PREV = 242 # drive previous video source
KEY_BRIGHTNESS_CYCLE = 243 # brightness up, after max is min
KEY_BRIGHTNESS_AUTO = 244 # Set Auto Brightness: manual, brightness control is off, rely on ambient
KEY_BRIGHTNESS_ZERO = KEY_BRIGHTNESS_AUTO
KEY_DISPLAY_OFF = 245 # display device to off state

KEY_WWAN = 246 # Wireless WAN (LTE, UMTS, GSM, etc.)
KEY_WIMAX = KEY_WWAN
KEY_RFKILL = 247 # Key that controls all radios

KEY_MICMUTE = 248 # Mute / unmute the microphone


class TouchpadHack:
   def __init__(self):
       self.__disabled = False
       self.__condition = threading.Condition()
       self.__disabled_until_time = time.monotonic()
       self.__running = True
       
       self.__disable_timeout = 0.5
       self.__timeout_thread = threading.Thread(target=self.timeoutThread, daemon=True)

   def findXInputDeviceNumber(self):
       res = subprocess.run(["/usr/bin/xinput", "list"], stdout=subprocess.PIPE).stdout
       for line in res.split(b"\n"):
           if b"pointer" in line and b"HAILUCK" in line:
               line = line[line.find(b"id=")+3:]
               line = line[:line.find(b"\t")]
               return int(line)
       return None
   
   def timeoutThread(self):
       device_number = self.findXInputDeviceNumber()
       while self.__running:
           with self.__condition:
               self.__condition.wait()
           os.system("xinput disable %d" % (device_number))
           print("disable")
           while time.monotonic() < self.__disabled_until_time and self.__running:
               time.sleep(self.__disabled_until_time - time.monotonic())
           os.system("xinput enable %d" % (device_number))
           print("enable")

   def inputReadThread(self):
       self.__timeout_thread.start()

       # Search for the first Pinebook keyboard entry. The first seems to be the keyboard, the 2nd the mouse.
       for event_path in sorted(os.listdir("/dev/input")):
           if not event_path.startswith("event"):
               continue
           event_path = os.path.join("/dev/input", event_path)
           f = open(event_path, "rb")
           input_device_name = bytearray(512)
           fcntl.ioctl(f, EVIOCGNAME, input_device_name, True)
           input_device_name = input_device_name[:input_device_name.find(b"\0")].decode("utf-8")
           if input_device_name == "HAILUCK CO.,LTD USB KEYBOARD":
               break
           f.close()

       try:
           while True:
               # We read events here from the keyboard and then just ignore them.
               # The only thing we care about is that an event happens.
               event = f.read(struct.calcsize(EVENT_FMT))
               tv_sec, tv_usec, etype, code, value = struct.unpack(EVENT_FMT, event)
               if etype == EV_KEY and self.isDisableKey(code):
                   self.initiateOrUpdateDisable()
       except KeyboardInterrupt:
           self.__running = False
           print("Shutting down")
       with self.__condition:
           self.__condition.notify()
       self.__timeout_thread.join()

   def isDisableKey(self, code):
       # Don't react to modifier keys
       if code == KEY_LEFTALT or code == KEY_RIGHTALT:
           return False
       if code == KEY_LEFTCTRL or code == KEY_RIGHTCTRL:
           return False
       if code == KEY_LEFTSHIFT or code == KEY_RIGHTSHIFT:
           return False
       if code == KEY_LEFTMETA or code == KEY_RIGHTMETA:
           return False
       return True

   def initiateOrUpdateDisable(self):
       with self.__condition:
           self.__condition.notify()
           self.__disabled_until_time = time.monotonic() + self.__disable_timeout

TouchpadHack().inputReadThread()
#4
This is really great!!!

I'm able to type without triggering nearly as many stray clicks now.

Thank you!

If you get an error about time.monotonic(), run it with python3 instead of python.

Could be nice to set up a github repo Smile
#5
finally got around to trying it, and it works really well I must say Smile good job

edit: suggestions on how to best run it at startup ?
You can find me on IRC, Discord and Twitter


#6
You would need to run in in your X session, so most likely a proper file in ~/.config/autostart would do it. But I haven't looked into those details yet.
#7
(08-21-2017, 11:25 AM)daid Wrote: You would need to run in in your X session, so most likely a proper file in ~/.config/autostart would do it. But I haven't looked into those details yet.

Was the first thing I did - didn't work however. Perhaps I did something wrong.
You can find me on IRC, Discord and Twitter


#8
Running it in a terminal for now, look's good! Will be testing it some more! Smile

Thanks!
#9
(08-21-2017, 06:44 AM)Luke Wrote: finally got around to trying it, and it works really well I must say Smile good job

edit: suggestions on how to best run it at startup ?

I made a wrapper shell script that just starts it with
Code:
sudo python3 PATH/touchpadsleep.py
 (my user account has NOPASSWD in sudoers) 

and added that shell script in
System>Preferences>Personal>Startup
#10
(08-25-2017, 10:05 AM)combs Wrote:
(08-21-2017, 06:44 AM)Luke Wrote: finally got around to trying it, and it works really well I must say Smile good job

edit: suggestions on how to best run it at startup ?

I made a wrapper shell script that just starts it with
Code:
sudo python3 PATH/touchpadsleep.py
 (my user account has NOPASSWD in sudoers) 

and added that shell script in
System>Preferences>Personal>Startup

Ah. Yes, I tried that too - but didn't think of setting no password for my account ... Thanks for sharing this, although I still would like to keep my password for a variety or reasons.
You can find me on IRC, Discord and Twitter




Possibly Related Threads…
Thread Author Replies Views Last Post
  How to enable touchpad natural scrolling? plumlis 3 7,125 07-19-2020, 02:46 PM
Last Post: Martin Gruber
  Disable touchpad tap to click? colin.faulkingham 25 40,019 04-27-2020, 07:31 PM
Last Post: ab1jx
Sad touchpad edges scrolling kurai021 11 15,484 07-09-2017, 05:56 PM
Last Post: Luke

Forum Jump:


Users browsing this thread: 6 Guest(s)