blob: aeb465113857ff68ca3cd451cc397106cbb655b9 [file] [log] [blame]
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Class to control and interact with USBKM232 USB keyboard emulator."""
import serial
import sys
import time
VERSION = "0.0.1"
class usbkm232Error(Exception):
"""Exception class for usbkm232."""
class usbkm232(object):
"""usbkm232 Class."""
MAX_RSP_RETRIES = 10
USB_QUEUE_DEPTH = 6
CLEAR = '\x38'
KEYS = {
#row 1
'`': 1,
'1': 2,
'2': 3,
'3': 4,
'4': 5,
'5': 6,
'6': 7,
'7': 8,
'8': 9,
'9': 10,
'0': 11,
'-': 12,
'=': 13,
'<undef1>': 14,
'<backspace>': 15,
'<tab>': 16,
'q': 17,
'w': 18,
'e': 19,
'r': 20,
't': 21,
'y': 22,
'u': 23,
'i': 24,
'o': 25,
'p': 26,
'[': 27,
']': 28,
'\\': 29,
# row 2
'<capslock>': 30,
'a': 31,
's': 32,
'd': 33,
'f': 34,
'g': 35,
'h': 36,
'j': 37,
'k': 38,
'l': 39,
';': 40,
'\'': 41,
'<undef2>': 42,
'<enter>': 43,
# row 3
'<lshift>': 44,
'<undef3>': 45,
'z': 46,
'x': 47,
'c': 48,
'v': 49,
'b': 50,
'n': 51,
'm': 52,
',': 53,
'.': 54,
'/': 55,
'[clear]': 56,
'<rshift>': 57,
# row 4
'<lctrl>': 58,
'<undef5>': 59,
'<lalt>': 60,
' ': 61,
'<ralt>': 62,
'<undef6>': 63,
'<rctrl>': 64,
'<undef7>': 65,
'<mouse_left>': 66,
'<mouse_right>': 67,
'<mouse_up>': 68,
'<mouse_down>': 69,
'<lwin>': 70,
'<rwin>': 71,
'<win apl>': 72,
'<mouse_lbtn_press>': 73,
'<mouse_rbtn_press>': 74,
'<insert>': 75,
'<delete>': 76,
'<mouse_mbtn_press>': 77,
'<undef16>': 78,
'<larrow>': 79,
'<home>': 80,
'<end>': 81,
'<undef23>': 82,
'<uparrow>': 83,
'<downarrow>': 84,
'<pgup>': 85,
'<pgdown>': 86,
'<mouse_scr_up>': 87,
'<mouse_scr_down>': 88,
'<rarrow>': 89,
# numpad
'<numlock>': 90,
'<num7>': 91,
'<num4>': 92,
'<num1>': 93,
'<undef27>': 94,
'<num/>': 95,
'<num8>': 96,
'<num5>': 97,
'<num2>': 98,
'<num0>': 99,
'<num*>': 100,
'<num9>': 101,
'<num6>': 102,
'<num3>': 103,
'<num.>': 104,
'<num->': 105,
'<num+>': 106,
'<numenter>': 107,
'<undef28>': 108,
'<mouse_slow>': 109,
# row 0
'<esc>': 110,
'<mouse_fast>': 111,
'<f1>': 112,
'<f2>': 113,
'<f3>': 114,
'<f4>': 115,
'<f5>': 116,
'<f6>': 117,
'<f7>': 118,
'<f8>': 119,
'<f9>': 120,
'<f10>': 121,
'<f11>': 122,
'<f12>': 123,
'<prtscr>': 124,
'<scrllk>': 125,
'<pause/brk>': 126,
}
def __init__(self, serial_device):
"""Constructor for usbkm232 class."""
self.serial = serial.Serial(serial_device, 9600, timeout=0.1)
self.serial.setInterCharTimeout(0.5)
self.serial.setTimeout(0.5)
self.serial.setWriteTimeout(0.5)
def _press(self, press_ch):
"""Encode and return character to press using usbkm232.
Args:
press_ch: character to press
Returns:
Proper encoding to send to the uart side of the usbkm232 to create the
desired key press.
"""
return '%c' % self.KEYS[press_ch]
def _release(self, release_ch):
"""Encode and return character to release using usbkm232.
This value is simply the _press_ value + 128
Args:
release_ch: character to release
Returns:
Proper encoding to send to the uart side of the usbkm232 to create the
desired key release.
"""
return '%c' % (self.KEYS[release_ch] | 0x80)
def _rsp(self, orig_ch):
"""Check response after sending character to usbkm232.
The response is the one's complement of the value sent. This method
blocks until proper response is received.
Args:
orig_ch: original character sent.
Raises:
usbkm232Error: if response was incorrect or timed out
"""
count = 0
rsp = self.serial.read(1)
while (len(rsp) != 1 or ord(orig_ch) != (~ord(rsp) & 0xff)) \
and count < self.MAX_RSP_RETRIES:
rsp = self.serial.read(1)
print "re-read rsp"
count += 1
if count == self.MAX_RSP_RETRIES:
raise Usbkm232Error("Failed to get correct response from usbkm232")
print "usbkm232: response [-] = \\0%03o 0x%02x" % (ord(rsp), ord(rsp))
def _write(self, mylist, check=False, clear=True):
"""Write list of commands to usbkm232.
Args:
mylist: list of encoded commands to send to the uart side of the
usbkm232
check: boolean determines whether response from usbkm232 should be
checked.
clear: boolean determines whether keytroke clear should be sent at end
of the sequence.
"""
# TODO(tbroch): USB queue depth is 6 might be more efficient to write
# more than just one make/break
for i, write_ch in enumerate(mylist):
print "usbkm232: writing [%d] = \\0%03o 0x%02x" % \
(i, ord(write_ch), ord(write_ch))
self.serial.write(write_ch)
if check:
self._rsp(write_ch)
time.sleep(.05)
if clear:
print "usbkm232: clearing keystrokes"
self.serial.write(self.CLEAR)
if check:
self._rsp(self.CLEAR)
def writestr(self, mystr):
"""Write string to usbkm232.
Args:
mystr: string to send across the usbkm232
"""
rlist = []
for write_ch in mystr:
rlist.append(self._press(write_ch))
rlist.append(self._release(write_ch))
self._write(rlist)
def ctrl_d(self):
"""Press and release ctrl-d sequence."""
self._write([self._press('<lctrl>'), self._press('d')])
def ctrl_u(self):
"""Press and release ctrl-u sequence."""
self._write([self._press('<lctrl>'), self._press('u')])
def enter(self):
"""Press and release enter"""
self._write([self._press('<enter>')])
def space(self):
"""."""
self._write([self._press(' ')])
def tab(self):
"""Press and release tab"""
self._write([self._press('<tab>')])
def close(self):
"""Close usbkm232 device."""
self.serial.close()
def main():
"""Test method."""
if len(sys.argv) != 2:
print "-E- USAGE: %s <device of uart>"
sys.exit(-1)
kbd = usbkm232(sys.argv[1])
try:
while True:
user_input = raw_input("Enter string to type: ")
kbd.writestr(user_input)
except KeyboardInterrupt:
kbd.close()
sys.exit(0)
if __name__ == "__main__":
main()