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
import os | |
import numbers | |
import binascii | |
from struct import pack, unpack | |
from twisted.internet import abstract, interfaces, reactor, fdesc, task | |
KEYCODES = { | |
"\n": (0x28, 0), | |
"\x1b": (0x29, 0), | |
"\x08": (0x2a, 0), | |
"\x7f": (0x4c, 0), | |
"\t": (0x2b, 0), | |
" ": (0x2c, 0), | |
"-": (0x2d, 0), | |
"_": (0x2d, 2), | |
"=": (0x2e, 0), | |
"+": (0x2e, 2), | |
"[": (0x2f, 0), | |
"{": (0x2f, 2), | |
"]": (0x30, 0), | |
"}": (0x30, 2), | |
"\\": (0x31, 0), | |
"|": (0x31, 2), | |
";": (0x33, 0), | |
":": (0x33, 2), | |
"'": (0x34, 0), | |
"\"": (0x34, 2), | |
"`": (0x35, 0), | |
"~": (0x35, 2), | |
",": (0x36, 0), | |
"<": (0x36, 2), | |
".": (0x37, 0), | |
">": (0x37, 2), | |
"/": (0x38, 0), | |
"?": (0x38, 2), | |
# symbols are a little messy | |
"!": (0x1e, 2), | |
"@": (0x1f, 2), | |
"#": (0x20, 2), | |
"$": (0x21, 2), | |
"%": (0x22, 2), | |
"^": (0x23, 2), | |
"&": (0x24, 2), | |
"*": (0x25, 2), | |
"(": (0x26, 2), | |
")": (0x27, 2), | |
# 0 is out of order with respect to ascii | |
"0": (0x27, 0), | |
} | |
# aliases | |
KEYCODES["enter"] = KEYCODES["return"] = KEYCODES["\n"] | |
KEYCODES["escape"] = KEYCODES["esc"] = KEYCODES["\x1b"] | |
KEYCODES["backspace"] = KEYCODES["bksp"] = KEYCODES["\x08"] | |
KEYCODES["delete"] = KEYCODES["del"] = KEYCODES["\x7f"] | |
KEYCODES["tab"] = KEYCODES["\t"] | |
KEYCODES["space"] = KEYCODES[" "] | |
# letters | |
for i in xrange(0x04, 0x1e): | |
KEYCODES[chr(i+93)] = (i, 0) | |
KEYCODES[chr(i+61)] = (i, 2) | |
# numbers 1-9 | |
for i in xrange(0x1e, 0x27): | |
KEYCODES[chr(i+19)] = (i, 0) | |
class HIDGadget(abstract.FileDescriptor): | |
def __init__(self, reactor=None): | |
abstract.FileDescriptor.__init__(self, reactor=reactor) | |
self.fp = open('/dev/hidg0', 'r+') | |
self.fileno = self.fp.fileno | |
self.startReading() | |
l = task.LoopingCall(self.everySecond) | |
l.start(1.0) | |
def mouseMove(self, x, y): | |
self.write(pack("BBbb", 2, 0, x, y)) | |
def mouseJiggle(self, x, y): | |
self.mouseMove(x, y) | |
self.mouseMove(-x, -y) | |
#task.deferLater(reactor, 0.01, self.mouseMove, -x, -y) | |
def dataJiggle(self, data): | |
for c in data: | |
n = ord(c) | |
bits = [(n>>x)&1 for x in xrange(7,-1,-1)] | |
quats = [(n>>x)&3 for x in xrange(6,-1,-2)] | |
for quat in quats: | |
if quat == 0: | |
self.mouseJiggle( 0, -4) | |
elif quat == 1: | |
self.mouseJiggle( 4, 0) | |
elif quat == 2: | |
self.mouseJiggle( 0, 4) | |
else: | |
self.mouseJiggle(-4, 0) | |
def kbdReport(self, mods=0, keys=[]): | |
report = pack("BBB", 1, mods, 0) | |
report += ''.join([chr(c) for c in keys]).ljust(6, "\0") | |
self.write(report) | |
def typeStuff(self, stuff): | |
while len(stuff) > 0: | |
thing = stuff.pop(0) | |
if isinstance(thing, basestring): | |
self.typeString(thing) | |
elif isinstance(thing, numbers.Real): | |
thing = min(thing, 60) | |
task.deferLater(reactor, thing, self.typeStuff, stuff) | |
elif isinstance(thing, (list, tuple)): | |
self.kbdReport(thing[0], thing[1]) | |
def typeString(self, s): | |
keyLast = None | |
for c in s: | |
if c in KEYCODES: | |
k = KEYCODES[c] | |
if k[0] == keyLast: | |
self.kbdReport() | |
self.kbdReport(k[1], [k[0]]) | |
keyLast = k[0] | |
self.kbdReport() | |
def typeStringFast(self, s): | |
keysLast = [] | |
keysCurr = [] | |
modsCurr = 0 | |
keys = "" | |
#print "typeString: " + s | |
for c in s: | |
if c in KEYCODES: | |
k = KEYCODES[c] | |
if k[0] in keysLast: | |
#print "typeString: key in last report '" + c + "'" | |
# send rest | |
self.kbdReport() | |
keysLast = [] | |
if modsCurr != k[1]: | |
#print "typeString: mods changed '" + c + "'" | |
if len(keysCurr) > 0: | |
#print "typeString: flushing buffer" | |
#print "typeString: send '" + keys + "'" | |
self.kbdReport(modsCurr, keysCurr) | |
keysLast = keysCurr | |
# hacky... | |
if k[0] in keysLast: | |
#print "typeString: key in last report '" + c + "'" | |
# send rest | |
self.kbdReport() | |
keysLast = [] | |
modsCurr = k[1] | |
keysCurr = [k[0]] | |
keys = c | |
elif k[0] in keysCurr: | |
# print "typeString: duplicate key '" + c + "'" | |
# send current keys | |
# print "typeString: send '" + keys + "'" | |
self.kbdReport(modsCurr, keysCurr) | |
# send rest | |
self.kbdReport() | |
keysLast = [] | |
keysCurr = [k[0]] | |
keys = c | |
elif len(keysCurr) == 6: | |
#print "typeString: report full '" + c + "'" | |
#print "typeString: send '" + keys + "'" | |
self.kbdReport(modsCurr, keysCurr) | |
keysLast = keysCurr | |
keysCurr = [k[0]] | |
keys = c | |
else: | |
keysCurr.append(k[0]) | |
keys += c | |
# send the last of the keys if needed | |
if len(keysCurr) > 0: | |
#print "typeString: send '" + keys + "'" | |
self.kbdReport(modsCurr, keysCurr) | |
# clear key state | |
self.kbdReport() | |
def everySecond(self): | |
#self.mouseJiggle(5, 0) | |
pass | |
def write(self, data): | |
print "write: " + binascii.hexlify(data) | |
#return | |
try: | |
# the hid gadget needs 8 byte writes | |
for offset in xrange(0, len(data), 8): | |
self.fp.write(data[offset:offset+8]) | |
self.fp.flush() | |
except IOError as e: | |
print "I/O error({0}): {1}".format(e.errno, e.strerror) | |
def doRead(self): | |
# horrible hack | |
fdesc.setNonBlocking(self.fp) | |
buf = self.fp.read() | |
fdesc.setBlocking(self.fp) | |
print 'read: ' + binascii.hexlify(buf) | |
self.write("\x02\x00\x10\x10") | |
def doWrite(self): | |
print 'doWrite' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment