Last active
January 4, 2016 14:59
-
-
Save thenoviceoof/8637497 to your computer and use it in GitHub Desktop.
Keyboard Mouse
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# - A first approximation of using the keyboard as a trackpad | |
# - It uses curses/Xlib for input and mouse interaction, so if you don't | |
# have those you're going to have a bad time | |
# - This is only a proof of concept, sniffing X for keystrokes and | |
# finding out how to seamlessly pop in and out of | |
# keyboard-as-trackpad-mode is left as an exercise to the reader | |
# - It turns out this isn't a very good control scheme, given the | |
# limited vertical resolution (4-6 rows vs. ~12 columns), and that | |
# it additionally suffers from all the problems inherent in | |
# acceleration based control schemes | |
# - You will have to edit KEYBOARD_MAP to suit your own keyboard: I | |
# use a dvorak layout, so it is unlikely to fit your | |
# layout. Creating a program to automatically create the map from a | |
# photo of a keyboard is left as an exercise to the reader | |
# | |
# "THE BEER-WARE LICENSE" (Revision 42): | |
# <thenoviceoof> wrote this file. As long as you retain this notice | |
# you can do whatever you want with this stuff. If we meet some day, | |
# and you think this stuff is worth it, you can buy me a beer in | |
# return | |
# - thenoviceoof | |
import curses | |
import math | |
import time | |
import traceback | |
import Xlib | |
from Xlib import display | |
DISPLAY = display.Display() | |
def move_mouse_x(x,y): | |
DISPLAY.warp_pointer(x,y) | |
DISPLAY.sync() | |
def dist(a, b): | |
return ((a[0]-b[0])**2 + (a[1]-b[1])**2)**0.5 | |
def drag(dx,dy): | |
v = (dx**2 + dy**2)**0.5 | |
ang = math.atan2(dy,dx) | |
v *= 0.9 | |
# threshold the velocity | |
if v < 0.5: | |
v = 0 | |
dx = v * math.cos(ang) | |
dy = v * math.sin(ang) | |
return dx,dy | |
KEYBOARD_MAP = { | |
'1': (-0.3,-1), | |
'2': (0.6,-1), | |
'3': (1.6,-1), | |
'4': (2.6,-1), | |
'5': (3.6,-1), | |
'6': (4.6,-1), | |
'7': (5.6,-1), | |
'8': (6.6,-1), | |
'9': (7.6,-1), | |
'0': (8.6,-1), | |
'[': (9.6,-1), | |
']': (10.6,-1), | |
'\'': (0,0), | |
',': (1,0), | |
'.': (2,0), | |
'p': (3,0), | |
'y': (4,0), | |
'f': (5,0), | |
'g': (6,0), | |
'c': (7,0), | |
'r': (8,0), | |
'l': (9,0), | |
'/': (10,0), | |
'=': (11,0), | |
'a': (0.3,1), | |
'o': (1.3,1), | |
'e': (2.3,1), | |
'u': (3.3,1), | |
'i': (4.3,1), | |
'd': (5.3,1), | |
'h': (6.3,1), | |
't': (7.3,1), | |
'n': (8.3,1), | |
's': (9.3,1), | |
'-': (10.3,1), | |
';': (0.6,2), | |
'q': (1.6,2), | |
'j': (2.6,2), | |
'k': (3.6,2), | |
'x': (4.6,2), | |
'b': (5.6,2), | |
'm': (6.6,2), | |
'w': (7.6,2), | |
'v': (8.6,2), | |
'z': (9.6,2), | |
} | |
def main(): | |
# velocity | |
dx = 0 | |
dy = 0 | |
# previous keyboard position for acceleration | |
prev = None | |
prev_time = None | |
# set up curses | |
stdscr = curses.initscr() | |
curses.cbreak() | |
stdscr.nodelay(1) | |
char = None | |
while 1: | |
# grab keystrokes | |
char = stdscr.getch() | |
# turn them into acceleration | |
if char != -1 and chr(char) in KEYBOARD_MAP: | |
t = time.time() | |
char = chr(char) | |
x,y = KEYBOARD_MAP[char] | |
if prev and dist(prev, (x,y)) > 1.5: | |
# assume this is the user picking up and moving their | |
# finger | |
dx, dy = 0, 0 | |
elif prev: | |
# accelerate them over that away | |
dx += (x - prev[0]) / (t - prev_time) | |
dy += (y - prev[1]) / (t - prev_time) | |
prev = (x,y) | |
prev_time = t | |
# move the mouse according to the velocity | |
move_mouse_x(dx,dy) | |
# decelerate the movement | |
dx,dy = drag(dx,dy) | |
time.sleep(0.02) | |
if __name__ == '__main__': | |
try: | |
main() | |
except Exception, e: | |
# clean up after curses | |
curses.nocbreak() | |
curses.endwin() | |
# re-raising an exception is annoyingly opaque | |
traceback.print_exc() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment