blob: f23be3f45160854edee1b409d1846f7353b99546 [file] [log] [blame]
Joseph Hwang5d0dc642016-01-19 10:21:12 +08001# Copyright 2016 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""This module provides emulation of bluetooth HID devices."""
6
Joseph Hwangd3784cb2016-03-06 21:57:39 +08007import argparse
Joseph Hwang5d0dc642016-01-19 10:21:12 +08008import logging
9import sys
10import time
11
Alexander Lentce006df2017-08-17 17:22:24 -070012from bluetooth_peripheral_kit import PeripheralKit
13from bluetooth_rn42 import RN42
14from bluetooth_rn42 import RN42Exception
Joseph Hwang5d0dc642016-01-19 10:21:12 +080015
16
17class BluetoothHIDException(Exception):
18 """A dummpy exception class for Bluetooth HID class."""
19 pass
20
21
Alexander Lent7cbd1592017-08-08 20:12:02 -070022class BluetoothHID(object):
Joseph Hwang9f0e0242016-06-22 12:50:20 +080023 """A base bluetooth HID emulator class using RN-42 evaluation kit.
24
25 Note: every public member method should
26 return True or a non-None object if successful;
27 return False or Raise an exception otherwise.
28 """
Joseph Hwang5d0dc642016-01-19 10:21:12 +080029
Alexander Lentce006df2017-08-17 17:22:24 -070030 # TODO(josephsih): Find better way to use constants other than PeripheralKit
Joseph Hwangd13e5e72016-05-30 18:57:35 +080031 TMP_PIN_CODE = '0000' # A temporary pin code
Joseph Hwang5d0dc642016-01-19 10:21:12 +080032
33 SEND_DELAY_SECS = 0.2 # Need to sleep for a short while otherwise
34 # the bits may get lost during transmission.
Joseph Hwangd13e5e72016-05-30 18:57:35 +080035 INIT_SLEEP_SECS = 5 # Sleep after initialization for stabilization.
Joseph Hwang5d0dc642016-01-19 10:21:12 +080036
Alexander Lent7cbd1592017-08-08 20:12:02 -070037 def __init__(self, device_type, authentication_mode, kit_impl,
Joseph Hwang5d0dc642016-01-19 10:21:12 +080038 send_delay=SEND_DELAY_SECS):
39 """Initialization of BluetoothHID
40
41 Args:
42 device_type: the device type for emulation
43 authentication_mode: the authentication mode
Alexander Lent7cbd1592017-08-08 20:12:02 -070044 kit_impl: the implementation of a peripheral kit to be instantiated
Joseph Hwang5d0dc642016-01-19 10:21:12 +080045 send_delay: wait a while after sending data
46 """
Alexander Lent7cbd1592017-08-08 20:12:02 -070047 self._kit = kit_impl()
Joseph Hwang5d0dc642016-01-19 10:21:12 +080048 self.device_type = device_type
Joseph Hwangc1edeff2016-06-08 15:38:14 +080049 self.authentication_mode = authentication_mode
Joseph Hwang5d0dc642016-01-19 10:21:12 +080050 self.send_delay = send_delay
51
Alexander Lent980519b2017-08-25 18:38:07 -070052 # TODO(crbug.com/764055): Remove the use of __getattr__ after a refactor of
53 # this class to only expose kit APIs explicitly.
Alexander Lent7cbd1592017-08-08 20:12:02 -070054 def __getattr__(self, name):
55 """Gets the attribute of name from the owned peripheral kit instance
56
57 Allows calling methods (or getting attributes in general) on this class or
58 its subclasses that resolve to methods defined on the kit implementation.
59
60 Args:
61 name: The name of the attribute to be found.
62
63 Returns:
64 The attribute of the kit with given name, if it exists.
65 (This is the default behavior and kits should follow it.)
66
67 Raises:
68 AttributeError if the attribute is not found.
69 (This is the default behavior and kits should follow it.)
70 """
Alexander Lentd7356bc2017-09-11 20:16:18 -070071 if name.startswith("Mouse"):
72 error = "Kit API is not public. Use public API from BluetoothHIDMouse."
73 raise AttributeError(error)
Alexander Lent7cbd1592017-08-08 20:12:02 -070074 return getattr(self._kit, name)
75
Joseph Hwangd13e5e72016-05-30 18:57:35 +080076 def Init(self, factory_reset=True):
77 """Initialize the chip correctly.
Joseph Hwang5d0dc642016-01-19 10:21:12 +080078
Joseph Hwangd13e5e72016-05-30 18:57:35 +080079 Initialize the chip with proper HID register values.
Joseph Hwang5d0dc642016-01-19 10:21:12 +080080
Joseph Hwangd13e5e72016-05-30 18:57:35 +080081 Args:
82 factory_reset: True if a factory reset is needed.
83 False if we only want to reconnect the serial device.
84 """
85 # Create a new serial device every time since the serial driver
86 # on chameleon board is not very stable.
Alexander Lentce006df2017-08-17 17:22:24 -070087 result = self.CreateSerialDevice()
Joseph Hwang5d0dc642016-01-19 10:21:12 +080088
Joseph Hwangd13e5e72016-05-30 18:57:35 +080089 if factory_reset:
Alexander Lentbc790282017-08-23 15:04:12 -070090 # Enter command mode to issue commands.
91 # This must happen first, so that other commands work
Alexander Lentce006df2017-08-17 17:22:24 -070092 result = self.EnterCommandMode() and result
Alexander Lentbc790282017-08-23 15:04:12 -070093
Joseph Hwangd13e5e72016-05-30 18:57:35 +080094 # Do a factory reset to make sure it is in a known initial state.
95 # Do the factory reset before proceeding to set parameters below.
Alexander Lentce006df2017-08-17 17:22:24 -070096 result = self.FactoryReset() and result
Joseph Hwang5d0dc642016-01-19 10:21:12 +080097
Joseph Hwangd13e5e72016-05-30 18:57:35 +080098 # Set HID as the service profile.
Alexander Lentce006df2017-08-17 17:22:24 -070099 result = self.SetServiceProfileHID() and result
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800100
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800101 # Set the HID device type.
Alexander Lentce006df2017-08-17 17:22:24 -0700102 result = self.SetHIDType(self.device_type) and result
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800103
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800104 # Set the default class of service.
Alexander Lentce006df2017-08-17 17:22:24 -0700105 result = self.SetDefaultClassOfService() and result
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800106
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800107 # Set the class of device (CoD) according to the hid device type.
Alexander Lentce006df2017-08-17 17:22:24 -0700108 result = self.SetClassOfDevice(self.device_type) and result
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800109
110 # Set authentication to the specified mode.
Alexander Lentce006df2017-08-17 17:22:24 -0700111 result = self.SetAuthenticationMode(self.authentication_mode) and result
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800112
113 # Set RN-42 to work as a slave.
Alexander Lentce006df2017-08-17 17:22:24 -0700114 result = self.SetSlaveMode() and result
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800115
Alexander Lentedd8d562017-08-17 17:23:58 -0700116 # Set a temporary pin code for testing purpose.
117 # Only do this when we want to use a pin code.
118 if self.authentication_mode == PeripheralKit.PIN_CODE_MODE:
119 result = self.SetPinCode(self.TMP_PIN_CODE) and result
120
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800121 # Enable the connection status message so that we could get the message
122 # of connection/disconnection status.
Alexander Lentce006df2017-08-17 17:22:24 -0700123 result = self.EnableConnectionStatusMessage() and result
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800124
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800125 # Reboot so that the configurations above take effect.
Alexander Lentce006df2017-08-17 17:22:24 -0700126 result = self.Reboot() and result
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800127
128 # Enter command mode again after reboot.
Alexander Lentce006df2017-08-17 17:22:24 -0700129 result = self.EnterCommandMode() and result
Joseph Hwangd13e5e72016-05-30 18:57:35 +0800130
131 time.sleep(self.INIT_SLEEP_SECS)
132
133 logging.info('A bluetooth HID "%s" device is connected.', self.device_type)
Alexander Lentce006df2017-08-17 17:22:24 -0700134 return result
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800135
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800136
137class BluetoothHIDKeyboard(BluetoothHID):
138 """A bluetooth HID keyboard emulator class."""
139
Alexander Lent7cbd1592017-08-08 20:12:02 -0700140 def __init__(self, authentication_mode, kit_impl):
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800141 """Initialization of BluetoothHIDKeyboard
142
143 Args:
144 authentication_mode: the authentication mode
Alexander Lent7cbd1592017-08-08 20:12:02 -0700145 kit_impl: the implementation of a Bluetooth HID peripheral kit to use
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800146 """
Alexander Lent7cbd1592017-08-08 20:12:02 -0700147 super(BluetoothHIDKeyboard, self).__init__(
Alexander Lentce006df2017-08-17 17:22:24 -0700148 PeripheralKit.KEYBOARD, authentication_mode, kit_impl)
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800149
150 def Send(self, data):
151 """Send data to the remote host.
152
153 Args:
154 data: data to send to the remote host
Joseph Hwangcb5623b2016-02-17 18:56:34 +0800155 data could be either a string of printable ASCII characters or
156 a special key combination.
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800157 """
158 # TODO(josephsih): should have a method to check the connection status.
159 # Currently, once RN-42 is connected to a remote host, all characters
160 # except chr(0) transmitted through the serial port are interpreted
161 # as characters to send to the remote host.
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800162 logging.debug('HID device sending %r...', data)
163 self.SerialSendReceive(data, msg='BluetoothHID.Send')
164 time.sleep(self.send_delay)
165
Joseph Hwangcb5623b2016-02-17 18:56:34 +0800166 def SendKeyCombination(self, modifiers=None, keys=None):
167 """Send special key combinations to the remote host.
168
169 Args:
170 modifiers: a list of modifiers
171 keys: a list of scan codes of keys
172 """
173 press_codes = self.PressShorthandCodes(modifiers=modifiers, keys=keys)
174 release_codes = self.ReleaseShorthandCodes()
175 if press_codes and release_codes:
176 self.Send(press_codes)
177 self.Send(release_codes)
178 else:
179 logging.warn('modifers: %s and keys: %s are not valid', modifiers, keys)
180 return None
181
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800182
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800183class BluetoothHIDMouse(BluetoothHID):
184 """A bluetooth HID mouse emulator class."""
185
Alexander Lentd7356bc2017-09-11 20:16:18 -0700186 # Max and min values for HID mouse report values
187 HID_MAX_REPORT_VALUE = 127
188 HID_MIN_REPORT_VALUE = -127
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800189
Alexander Lent7cbd1592017-08-08 20:12:02 -0700190 def __init__(self, authentication_mode, kit_impl):
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800191 """Initialization of BluetoothHIDMouse
192
193 Args:
194 authentication_mode: the authentication mode
Alexander Lent7cbd1592017-08-08 20:12:02 -0700195 kit_impl: the implementation of a Bluetooth HID peripheral kit to use
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800196 """
Alexander Lent7cbd1592017-08-08 20:12:02 -0700197 super(BluetoothHIDMouse, self).__init__(
Alexander Lentce006df2017-08-17 17:22:24 -0700198 PeripheralKit.MOUSE, authentication_mode, kit_impl)
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800199
Alexander Lentd7356bc2017-09-11 20:16:18 -0700200 def _EnsureHIDValueInRange(self, value):
201 """Ensures given value is in the range [-127,127] (inclusive).
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800202
203 Args:
Alexander Lentd7356bc2017-09-11 20:16:18 -0700204 value: The value that should be checked.
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800205
Alexander Lentd7356bc2017-09-11 20:16:18 -0700206 Raises:
207 BluetoothHIDException if value is outside of the acceptable range.
208 """
209 if value < self.HID_MIN_REPORT_VALUE or value > self.HID_MAX_REPORT_VALUE:
210 error = "Value %s is outside of acceptable range [-127,127]." % value
211 logging.error(error)
212 raise BluetoothHIDException(error)
213
214 def Move(self, delta_x=0, delta_y=0):
215 """Move the mouse (delta_x, delta_y) steps.
216
217 If buttons are being pressed, they will stay pressed during this operation.
218 This move is relative to the current position by the HID standard.
219 Valid step values must be in the range [-127,127].
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800220
221 Args:
Alexander Lentd7356bc2017-09-11 20:16:18 -0700222 delta_x: The number of steps to move horizontally.
223 Negative values move left, positive values move right.
224 delta_y: The number of steps to move vertically.
225 Negative values move up, positive values move down.
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800226
Alexander Lentd7356bc2017-09-11 20:16:18 -0700227 Raises:
228 BluetoothHIDException if a given delta is not in [-127,127].
229 """
230 self._EnsureHIDValueInRange(delta_x)
231 self._EnsureHIDValueInRange(delta_y)
232 self._kit.MouseMove(delta_x, delta_y)
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800233 time.sleep(self.send_delay)
234
Alexander Lentd7356bc2017-09-11 20:16:18 -0700235 def _PressLeftButton(self):
236 """Press the left button"""
237 self._kit.MousePressButtons({PeripheralKit.MOUSE_BUTTON_LEFT})
238 time.sleep(self.send_delay)
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800239
Alexander Lentd7356bc2017-09-11 20:16:18 -0700240 def _PressRightButton(self):
241 """Press the right button"""
242 self._kit.MousePressButtons({PeripheralKit.MOUSE_BUTTON_RIGHT})
243 time.sleep(self.send_delay)
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800244
Alexander Lentd7356bc2017-09-11 20:16:18 -0700245 def _ReleaseAllButtons(self):
246 """Press the right button"""
247 self._kit.MouseReleaseAllButtons()
248 time.sleep(self.send_delay)
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800249
250 def LeftClick(self):
251 """Make a left click."""
Alexander Lentd7356bc2017-09-11 20:16:18 -0700252 self._PressLeftButton()
253 self._ReleaseAllButtons()
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800254
255 def RightClick(self):
256 """Make a right click."""
Alexander Lentd7356bc2017-09-11 20:16:18 -0700257 self._PressRightButton()
258 self._ReleaseAllButtons()
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800259
260 def ClickAndDrag(self, delta_x=0, delta_y=0):
Alexander Lentd7356bc2017-09-11 20:16:18 -0700261 """Left click, drag (delta_x, delta_y) steps, and release.
262
263 This move is relative to the current position by the HID standard.
264 Valid step values must be in the range [-127,127].
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800265
266 Args:
Alexander Lentd7356bc2017-09-11 20:16:18 -0700267 delta_x: The number of steps to move horizontally.
268 Negative values move left, positive values move right.
269 delta_y: The number of steps to move vertically.
270 Negative values move up, positive values move down.
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800271
Alexander Lentd7356bc2017-09-11 20:16:18 -0700272 Raises:
273 BluetoothHIDException if a given delta is not in [-127,127].
274 """
275 self._EnsureHIDValueInRange(delta_x)
276 self._EnsureHIDValueInRange(delta_y)
277 self._PressLeftButton()
278 self.Move(delta_x, delta_y)
279 self._ReleaseAllButtons()
280
281 def Scroll(self, steps):
282 """Scroll the mouse wheel steps number of steps.
283
284 Buttons currently pressed will stay pressed during this operation.
285 Valid step values must be in the range [-127,127].
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800286
287 Args:
Alexander Lentd7356bc2017-09-11 20:16:18 -0700288 steps: The number of steps to scroll the wheel.
289 With traditional scrolling:
290 Negative values scroll down, positive values scroll up.
291 With reversed (formerly "Australian") scrolling this is reversed.
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800292 """
Alexander Lentd7356bc2017-09-11 20:16:18 -0700293 self._EnsureHIDValueInRange(steps)
294 self._kit.MouseScroll(steps)
295 time.sleep(self.send_delay)
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800296
297
298def DemoBluetoothHIDKeyboard(remote_address, chars):
299 """A simple demo of acting as a HID keyboard.
300
301 This simple demo works only after the HID device has already paired
302 with the remote device such that a link key has been exchanged. Then
303 the HID device could connect directly to the remote host without
304 pin code and sends the message.
305
306 A full flow would be letting a remote host pair with the HID device
307 with the pin code of the HID device. Thereafter, either the host or
308 the HID device could request to connect. This is out of the scope of
309 this simple demo.
310
311 Args:
312 remote_address: the bluetooth address of the target remote device
313 chars: the characters to send
314 """
315 print 'Creating an emulated bluetooth keyboard...'
Alexander Lentce006df2017-08-17 17:22:24 -0700316 # TODO(josephsih): Refactor test code to remove need for RN42 import
317 keyboard = BluetoothHIDKeyboard(PeripheralKit.PIN_CODE_MODE, RN42)
Joseph Hwangc1edeff2016-06-08 15:38:14 +0800318 keyboard.Init()
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800319
320 print 'Connecting to the remote address %s...' % remote_address
321 try:
322 if keyboard.ConnectToRemoteAddress(remote_address):
Joseph Hwangcb5623b2016-02-17 18:56:34 +0800323 # Send printable ASCII strings a few times.
324 for i in range(1, 4):
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800325 print 'Sending "%s" for the %dth time...' % (chars, i)
326 keyboard.Send(chars + ' ' + str(i))
Joseph Hwangcb5623b2016-02-17 18:56:34 +0800327
328 # Demo special key combinations below.
329 print 'Create a new chrome tab.'
330 keyboard.SendKeyCombination(modifiers=[RN42.LEFT_CTRL],
331 keys=[RN42.SCAN_T])
332
333 print 'Navigate to Google page.'
334 keyboard.Send('www.google.com')
335 time.sleep(1)
336
337 print 'Search hello world.'
338 keyboard.Send('hello world')
339 time.sleep(1)
340
341 print 'Navigate back to the previous page.'
342 keyboard.SendKeyCombination(keys=[RN42.SCAN_F1])
343 time.sleep(1)
344
345 print 'Switch to the previous tab.'
346 keyboard.SendKeyCombination(modifiers=[RN42.LEFT_CTRL, RN42.LEFT_SHIFT],
347 keys=[RN42.SCAN_TAB])
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800348 else:
349 print 'Something is wrong. Not able to connect to the remote address.'
350 print 'Have you already paired RN-42 with the remote host?'
351 finally:
352 print 'Disconnecting...'
353 keyboard.Disconnect()
354
355 print 'Closing the keyboard...'
356 keyboard.Close()
357
358
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800359def DemoBluetoothHIDMouse(remote_address):
360 """A simple demo of acting as a HID mouse.
361
362 Args:
363 remote_address: the bluetooth address of the target remote device
364 """
365 print 'Creating an emulated bluetooth mouse...'
Alexander Lentce006df2017-08-17 17:22:24 -0700366 # TODO(josephsih): Refactor test code to remove need for RN42 import
367 mouse = BluetoothHIDMouse(PeripheralKit.PIN_CODE_MODE, RN42)
Joseph Hwangc1edeff2016-06-08 15:38:14 +0800368 mouse.Init()
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800369
Joseph Hwang24ed76a2016-05-27 13:20:48 +0800370 connected = False
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800371 print 'Connecting to the remote address %s...' % remote_address
372 try:
373 if mouse.ConnectToRemoteAddress(remote_address):
Joseph Hwang24ed76a2016-05-27 13:20:48 +0800374 connected = True
375
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800376 print 'Click and drag horizontally.'
377 mouse.ClickAndDrag(delta_x=100)
378 time.sleep(1)
379
380 print 'Make a right click.'
381 mouse.RightClick()
382 time.sleep(1)
383
384 print 'Move the cursor upper left.'
385 mouse.Move(delta_x=-30, delta_y=-40)
386 time.sleep(1)
387
388 print 'Make a left click.'
389 mouse.LeftClick()
390 time.sleep(1)
391
392 print 'Move the cursor left.'
393 mouse.Move(delta_x=-100)
394 time.sleep(1)
395
396 print 'Move the cursor up.'
397 mouse.Move(delta_y=-90)
398 time.sleep(1)
399
400 print 'Move the cursor down right.'
401 mouse.Move(delta_x=100, delta_y=90)
402 time.sleep(1)
403
404 print 'Scroll in one direction.'
405 mouse.Scroll(-80)
406 time.sleep(1)
407
408 print 'Scroll in the opposite direction.'
409 mouse.Scroll(100)
410 else:
411 print 'Something is wrong. Not able to connect to the remote address.'
412 finally:
Joseph Hwang24ed76a2016-05-27 13:20:48 +0800413 if connected:
414 print 'Disconnecting...'
415 try:
416 mouse.Disconnect()
Alexander Lentce006df2017-08-17 17:22:24 -0700417 # TODO(josephsih): Refactor test code to remove need for RN42 import
Joseph Hwang24ed76a2016-05-27 13:20:48 +0800418 except RN42Exception:
419 # RN-42 may have already disconnected.
420 pass
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800421
422 print 'Closing the mouse...'
423 mouse.Close()
424
425
426def _Parse():
427 """Parse the command line options."""
428 prog = sys.argv[0]
429 example_usage = ('Example:\n' +
430 ' python %s keyboard 00:11:22:33:44:55\n' % prog +
431 ' python %s mouse 00:11:22:33:44:55\n'% prog)
432 parser = argparse.ArgumentParser(
433 description='Emulate a HID device.\n' + example_usage,
434 formatter_class=argparse.RawTextHelpFormatter)
435 parser.add_argument('device',
436 choices=['keyboard', 'mouse'],
437 help='the device type to emulate')
438 parser.add_argument('remote_host_address',
439 help='the remote host address')
440 parser.add_argument('-c', '--chars_to_send',
441 default='echo hello world',
442 help='characters to send to the remote host')
443 args = parser.parse_args()
444
445 if len(args.remote_host_address.replace(':', '')) != 12:
446 print '"%s" is not a valid bluetooth address.' % args.remote_host_address
447 exit(1)
448
449 print ('Emulate a %s and connect to remote host at %s' %
450 (args.device, args.remote_host_address))
451 return args
452
453
454def Demo():
455 """Make demonstrations about how to use the HID emulation classes."""
456 args = _Parse()
457 device = args.device.lower()
458 if device == 'keyboard':
459 DemoBluetoothHIDKeyboard(args.remote_host_address, args.chars_to_send)
460 elif device == 'mouse':
461 DemoBluetoothHIDMouse(args.remote_host_address)
462 else:
463 args.print_help()
464
465
Joseph Hwang5d0dc642016-01-19 10:21:12 +0800466if __name__ == '__main__':
Joseph Hwangd3784cb2016-03-06 21:57:39 +0800467 Demo()