Support special key combinations

This patch supports sending special key combinations through
RN-42's keyboard shorthand mode.

BUG=chromium:575551
TEST=Execute bluetooth_hid.py as follows:
1. Plug in an RN-42 kit to a chromebook or a Chameleon board
   with host-mode USB port.
2. Assume the bluetooth address of the dut is 00:12:34:56:78:90
   Open a virtual terminal tab in a chrome broswer.
3. Run the following command:
   python bluetooth_hid.py 00:12:34:56:78:90 "echo hello world"
4. Observe that it will print "hello world" for a few times.
   Then it will create a new chrome tab, navigate to Google page,
   search "hello world", navigate back to the previous Google page,
   and then switch back to the original virtual terminal tab.

Change-Id: Ibd0835278152eab1571caed076b1c12c3c978842
Reviewed-on: https://chromium-review.googlesource.com/330535
Commit-Ready: Shyh-In Hwang <josephsih@chromium.org>
Tested-by: Shyh-In Hwang <josephsih@chromium.org>
Reviewed-by: Shyh-In Hwang <josephsih@chromium.org>
diff --git a/chameleond/utils/bluetooth_hid.py b/chameleond/utils/bluetooth_hid.py
index 29dacbe..551867e 100644
--- a/chameleond/utils/bluetooth_hid.py
+++ b/chameleond/utils/bluetooth_hid.py
@@ -115,6 +115,8 @@
 
     Args:
       data: data to send to the remote host
+            data could be either a string of printable ASCII characters or
+            a special key combination.
     """
     # TODO(josephsih): should have a method to check the connection status.
     # Currently, once RN-42 is connected to a remote host, all characters
@@ -126,6 +128,22 @@
     self.SerialSendReceive(data, msg='BluetoothHID.Send')
     time.sleep(self.send_delay)
 
+  def SendKeyCombination(self, modifiers=None, keys=None):
+    """Send special key combinations to the remote host.
+
+    Args:
+      modifiers: a list of modifiers
+      keys: a list of scan codes of keys
+    """
+    press_codes = self.PressShorthandCodes(modifiers=modifiers, keys=keys)
+    release_codes = self.ReleaseShorthandCodes()
+    if press_codes and release_codes:
+      self.Send(press_codes)
+      self.Send(release_codes)
+    else:
+      logging.warn('modifers: %s and keys: %s are not valid', modifiers, keys)
+      return None
+
 
 def _UsageAndExit():
   """The usage of this module."""
@@ -158,9 +176,31 @@
   print 'Connecting to the remote address %s...' % remote_address
   try:
     if keyboard.ConnectToRemoteAddress(remote_address):
-      for i in range(1, 11):
+      # Send printable ASCII strings a few times.
+      for i in range(1, 4):
         print 'Sending "%s" for the %dth time...' % (chars, i)
         keyboard.Send(chars + ' ' + str(i))
+
+      # Demo special key combinations below.
+      print 'Create a new chrome tab.'
+      keyboard.SendKeyCombination(modifiers=[RN42.LEFT_CTRL],
+                                  keys=[RN42.SCAN_T])
+
+      print 'Navigate to Google page.'
+      keyboard.Send('www.google.com')
+      time.sleep(1)
+
+      print 'Search hello world.'
+      keyboard.Send('hello world')
+      time.sleep(1)
+
+      print 'Navigate back to the previous page.'
+      keyboard.SendKeyCombination(keys=[RN42.SCAN_F1])
+      time.sleep(1)
+
+      print 'Switch to the previous tab.'
+      keyboard.SendKeyCombination(modifiers=[RN42.LEFT_CTRL, RN42.LEFT_SHIFT],
+                                  keys=[RN42.SCAN_TAB])
     else:
       print 'Something is wrong. Not able to connect to the remote address.'
       print 'Have you already paired RN-42 with the remote host?'