Skip to content

Instantly share code, notes, and snippets.

@ryancdotorg
Created October 10, 2022 17:40
Show Gist options
  • Save ryancdotorg/d3d259be87a910c062a91eea489dd352 to your computer and use it in GitHub Desktop.
Save ryancdotorg/d3d259be87a910c062a91eea489dd352 to your computer and use it in GitHub Desktop.
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