/ adafruit_hid / keyboard_layout_us.py
keyboard_layout_us.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2017 Dan Halbert
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  #
 23  
 24  """
 25  `adafruit_hid.keyboard_layout_us.KeyboardLayoutUS`
 26  =======================================================
 27  
 28  * Author(s): Dan Halbert
 29  """
 30  
 31  from .keycode import Keycode
 32  
 33  
 34  class KeyboardLayoutUS:
 35      """Map ASCII characters to appropriate keypresses on a standard US PC keyboard.
 36  
 37      Non-ASCII characters and most control characters will raise an exception.
 38      """
 39  
 40      # The ASCII_TO_KEYCODE bytes object is used as a table to maps ASCII 0-127
 41      # to the corresponding # keycode on a US 104-key keyboard.
 42      # The user should not normally need to use this table,
 43      # but it is not marked as private.
 44      #
 45      # Because the table only goes to 127, we use the top bit of each byte (ox80) to indicate
 46      # that the shift key should be pressed. So any values 0x{8,9,a,b}* are shifted characters.
 47      #
 48      # The Python compiler will concatenate all these bytes literals into a single bytes object.
 49      # Micropython/CircuitPython will store the resulting bytes constant in flash memory
 50      # if it's in a .mpy file, so it doesn't use up valuable RAM.
 51      #
 52      # \x00 entries have no keyboard key and so won't be sent.
 53      SHIFT_FLAG = 0x80
 54      ASCII_TO_KEYCODE = (
 55          b"\x00"  # NUL
 56          b"\x00"  # SOH
 57          b"\x00"  # STX
 58          b"\x00"  # ETX
 59          b"\x00"  # EOT
 60          b"\x00"  # ENQ
 61          b"\x00"  # ACK
 62          b"\x00"  # BEL \a
 63          b"\x2a"  # BS BACKSPACE \b (called DELETE in the usb.org document)
 64          b"\x2b"  # TAB \t
 65          b"\x28"  # LF \n (called Return or ENTER in the usb.org document)
 66          b"\x00"  # VT \v
 67          b"\x00"  # FF \f
 68          b"\x00"  # CR \r
 69          b"\x00"  # SO
 70          b"\x00"  # SI
 71          b"\x00"  # DLE
 72          b"\x00"  # DC1
 73          b"\x00"  # DC2
 74          b"\x00"  # DC3
 75          b"\x00"  # DC4
 76          b"\x00"  # NAK
 77          b"\x00"  # SYN
 78          b"\x00"  # ETB
 79          b"\x00"  # CAN
 80          b"\x00"  # EM
 81          b"\x00"  # SUB
 82          b"\x29"  # ESC
 83          b"\x00"  # FS
 84          b"\x00"  # GS
 85          b"\x00"  # RS
 86          b"\x00"  # US
 87          b"\x2c"  # SPACE
 88          b"\x9e"  # ! x1e|SHIFT_FLAG (shift 1)
 89          b"\xb4"  # " x34|SHIFT_FLAG (shift ')
 90          b"\xa0"  # # x20|SHIFT_FLAG (shift 3)
 91          b"\xa1"  # $ x21|SHIFT_FLAG (shift 4)
 92          b"\xa2"  # % x22|SHIFT_FLAG (shift 5)
 93          b"\xa4"  # & x24|SHIFT_FLAG (shift 7)
 94          b"\x34"  # '
 95          b"\xa6"  # ( x26|SHIFT_FLAG (shift 9)
 96          b"\xa7"  # ) x27|SHIFT_FLAG (shift 0)
 97          b"\xa5"  # * x25|SHIFT_FLAG (shift 8)
 98          b"\xae"  # + x2e|SHIFT_FLAG (shift =)
 99          b"\x36"  # ,
100          b"\x2d"  # -
101          b"\x37"  # .
102          b"\x38"  # /
103          b"\x27"  # 0
104          b"\x1e"  # 1
105          b"\x1f"  # 2
106          b"\x20"  # 3
107          b"\x21"  # 4
108          b"\x22"  # 5
109          b"\x23"  # 6
110          b"\x24"  # 7
111          b"\x25"  # 8
112          b"\x26"  # 9
113          b"\xb3"  # : x33|SHIFT_FLAG (shift ;)
114          b"\x33"  # ;
115          b"\xb6"  # < x36|SHIFT_FLAG (shift ,)
116          b"\x2e"  # =
117          b"\xb7"  # > x37|SHIFT_FLAG (shift .)
118          b"\xb8"  # ? x38|SHIFT_FLAG (shift /)
119          b"\x9f"  # @ x1f|SHIFT_FLAG (shift 2)
120          b"\x84"  # A x04|SHIFT_FLAG (shift a)
121          b"\x85"  # B x05|SHIFT_FLAG (etc.)
122          b"\x86"  # C x06|SHIFT_FLAG
123          b"\x87"  # D x07|SHIFT_FLAG
124          b"\x88"  # E x08|SHIFT_FLAG
125          b"\x89"  # F x09|SHIFT_FLAG
126          b"\x8a"  # G x0a|SHIFT_FLAG
127          b"\x8b"  # H x0b|SHIFT_FLAG
128          b"\x8c"  # I x0c|SHIFT_FLAG
129          b"\x8d"  # J x0d|SHIFT_FLAG
130          b"\x8e"  # K x0e|SHIFT_FLAG
131          b"\x8f"  # L x0f|SHIFT_FLAG
132          b"\x90"  # M x10|SHIFT_FLAG
133          b"\x91"  # N x11|SHIFT_FLAG
134          b"\x92"  # O x12|SHIFT_FLAG
135          b"\x93"  # P x13|SHIFT_FLAG
136          b"\x94"  # Q x14|SHIFT_FLAG
137          b"\x95"  # R x15|SHIFT_FLAG
138          b"\x96"  # S x16|SHIFT_FLAG
139          b"\x97"  # T x17|SHIFT_FLAG
140          b"\x98"  # U x18|SHIFT_FLAG
141          b"\x99"  # V x19|SHIFT_FLAG
142          b"\x9a"  # W x1a|SHIFT_FLAG
143          b"\x9b"  # X x1b|SHIFT_FLAG
144          b"\x9c"  # Y x1c|SHIFT_FLAG
145          b"\x9d"  # Z x1d|SHIFT_FLAG
146          b"\x2f"  # [
147          b"\x31"  # \ backslash
148          b"\x30"  # ]
149          b"\xa3"  # ^ x23|SHIFT_FLAG (shift 6)
150          b"\xad"  # _ x2d|SHIFT_FLAG (shift -)
151          b"\x35"  # `
152          b"\x04"  # a
153          b"\x05"  # b
154          b"\x06"  # c
155          b"\x07"  # d
156          b"\x08"  # e
157          b"\x09"  # f
158          b"\x0a"  # g
159          b"\x0b"  # h
160          b"\x0c"  # i
161          b"\x0d"  # j
162          b"\x0e"  # k
163          b"\x0f"  # l
164          b"\x10"  # m
165          b"\x11"  # n
166          b"\x12"  # o
167          b"\x13"  # p
168          b"\x14"  # q
169          b"\x15"  # r
170          b"\x16"  # s
171          b"\x17"  # t
172          b"\x18"  # u
173          b"\x19"  # v
174          b"\x1a"  # w
175          b"\x1b"  # x
176          b"\x1c"  # y
177          b"\x1d"  # z
178          b"\xaf"  # { x2f|SHIFT_FLAG (shift [)
179          b"\xb1"  # | x31|SHIFT_FLAG (shift \)
180          b"\xb0"  # } x30|SHIFT_FLAG (shift ])
181          b"\xb5"  # ~ x35|SHIFT_FLAG (shift `)
182          b"\x4c"  # DEL DELETE (called Forward Delete in usb.org document)
183      )
184  
185      def __init__(self, keyboard):
186          """Specify the layout for the given keyboard.
187  
188          :param keyboard: a Keyboard object. Write characters to this keyboard when requested.
189  
190          Example::
191  
192              kbd = Keyboard(usb_hid.devices)
193              layout = KeyboardLayoutUS(kbd)
194          """
195  
196          self.keyboard = keyboard
197  
198      def write(self, string):
199          """Type the string by pressing and releasing keys on my keyboard.
200  
201          :param string: A string of ASCII characters.
202          :raises ValueError: if any of the characters are not ASCII or have no keycode
203              (such as some control characters).
204  
205          Example::
206  
207              # Write abc followed by Enter to the keyboard
208              layout.write('abc\\n')
209          """
210          for char in string:
211              keycode = self._char_to_keycode(char)
212              # If this is a shifted char, clear the SHIFT flag and press the SHIFT key.
213              if keycode & self.SHIFT_FLAG:
214                  keycode &= ~self.SHIFT_FLAG
215                  self.keyboard.press(Keycode.SHIFT)
216              self.keyboard.press(keycode)
217              self.keyboard.release_all()
218  
219      def keycodes(self, char):
220          """Return a tuple of keycodes needed to type the given character.
221  
222          :param char: A single ASCII character in a string.
223          :type char: str of length one.
224          :returns: tuple of Keycode keycodes.
225          :raises ValueError: if ``char`` is not ASCII or there is no keycode for it.
226  
227          Examples::
228  
229              # Returns (Keycode.TAB,)
230              keycodes('\t')
231              # Returns (Keycode.A,)
232              keycode('a')
233              # Returns (Keycode.SHIFT, Keycode.A)
234              keycode('A')
235              # Raises ValueError because it's a accented e and is not ASCII
236              keycode('é')
237          """
238          keycode = self._char_to_keycode(char)
239          if keycode & self.SHIFT_FLAG:
240              return (Keycode.SHIFT, keycode & ~self.SHIFT_FLAG)
241  
242          return (keycode,)
243  
244      def _char_to_keycode(self, char):
245          """Return the HID keycode for the given ASCII character, with the SHIFT_FLAG possibly set.
246  
247          If the character requires pressing the Shift key, the SHIFT_FLAG bit is set.
248          You must clear this bit before passing the keycode in a USB report.
249          """
250          char_val = ord(char)
251          if char_val > 128:
252              raise ValueError("Not an ASCII character.")
253          keycode = self.ASCII_TO_KEYCODE[char_val]
254          if keycode == 0:
255              raise ValueError("No keycode available for character.")
256          return keycode