github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/machine/usb/hid/keyboard/keyboard.go (about) 1 package keyboard 2 3 import ( 4 "errors" 5 "machine" 6 "machine/usb/hid" 7 ) 8 9 // from usb-hid-keyboard.go 10 var ( 11 ErrInvalidCodepoint = errors.New("invalid Unicode codepoint") 12 ErrInvalidKeycode = errors.New("invalid keyboard keycode") 13 ErrInvalidUTF8 = errors.New("invalid UTF-8 encoding") 14 ErrKeypressMaximum = errors.New("maximum keypresses exceeded") 15 ) 16 17 var Keyboard *keyboard 18 19 // Keyboard represents a USB HID keyboard device with support for international 20 // layouts and various control, system, multimedia, and consumer keycodes. 21 // 22 // Keyboard implements the io.Writer interface that translates UTF-8 encoded 23 // byte strings into sequences of keypress events. 24 type keyboard struct { 25 // led holds the current state of all keyboard LEDs: 26 // 1=NumLock 2=CapsLock 4=ScrollLock 8=Compose 16=Kana 27 led uint8 28 29 // mod holds the current state of all keyboard modifier keys: 30 // 1=LeftCtrl 2=LeftShift 4=LeftAlt 8=LeftGUI 31 // 16=RightCtrl 32=RightShift 64=RightAlt 128=RightGUI 32 mod uint8 33 34 // key holds a list of all keyboard keys currently pressed. 35 key [hidKeyboardKeyCount]uint8 36 con [hidKeyboardConCount]uint16 37 sys [hidKeyboardSysCount]uint8 38 39 // decode holds the current state of the UTF-8 decoder. 40 decode decodeState 41 42 // wideChar holds high bits for the UTF-8 decoder. 43 wideChar uint16 44 45 buf *hid.RingBuffer 46 waitTxc bool 47 } 48 49 // decodeState represents a state in the UTF-8 decode state machine. 50 type decodeState uint8 51 52 // Constant enumerated values of type decodeState. 53 const ( 54 decodeReset decodeState = iota 55 decodeByte1 56 decodeByte2 57 decodeByte3 58 ) 59 60 func init() { 61 if Keyboard == nil { 62 Keyboard = newKeyboard() 63 hid.SetHandler(Keyboard) 64 } 65 } 66 67 // New returns the USB hid-keyboard port. 68 // Deprecated, better to just use Port() 69 func New() *keyboard { 70 return Port() 71 } 72 73 // Port returns the USB hid-keyboard port. 74 func Port() *keyboard { 75 return Keyboard 76 } 77 78 func newKeyboard() *keyboard { 79 return &keyboard{ 80 buf: hid.NewRingBuffer(), 81 } 82 } 83 84 func (kb *keyboard) TxHandler() bool { 85 kb.waitTxc = false 86 if b, ok := kb.buf.Get(); ok { 87 kb.waitTxc = true 88 hid.SendUSBPacket(b) 89 return true 90 } 91 return false 92 } 93 94 func (kb *keyboard) RxHandler(b []byte) bool { 95 if len(b) >= 2 && b[0] == 2 /* ReportID */ { 96 kb.led = b[1] 97 } 98 return false 99 } 100 101 func (kb *keyboard) tx(b []byte) { 102 if machine.USBDev.InitEndpointComplete { 103 if kb.waitTxc { 104 kb.buf.Put(b) 105 } else { 106 kb.waitTxc = true 107 hid.SendUSBPacket(b) 108 } 109 } 110 } 111 112 func (kb *keyboard) NumLockLed() bool { 113 return kb.led&1 != 0 114 } 115 116 func (kb *keyboard) CapsLockLed() bool { 117 return kb.led&2 != 0 118 } 119 120 func (kb *keyboard) ScrollLockLed() bool { 121 return kb.led&4 != 0 122 } 123 124 func (kb *keyboard) ready() bool { 125 return true 126 } 127 128 // Write transmits press-and-release key sequences for each Keycode translated 129 // from the given UTF-8 byte string. Write implements the io.Writer interface 130 // and conforms to all documented conventions for arguments and return values. 131 func (kb *keyboard) Write(b []byte) (n int, err error) { 132 for _, c := range b { 133 if err = kb.WriteByte(c); nil != err { 134 break 135 } 136 n += 1 137 } 138 return 139 } 140 141 // WriteByte processes a single byte from a UTF-8 byte string. This method is a 142 // stateful method with respect to the receiver Keyboard, meaning that its exact 143 // behavior will depend on the current state of its UTF-8 decode state machine: 144 // 145 // 1. If the given byte is a valid ASCII encoding (0-127), then a keypress 146 // sequence is immediately transmitted for the respective Keycode. 147 // 2. If the given byte represents the final byte in a multi-byte codepoint, 148 // then a keypress sequence is immediately transmitted by translating the 149 // multi-byte codepoint to its respective Keycode. 150 // 3. If the given byte appears to represent high bits for a multi-byte 151 // codepoint, then the bits are copied to the receiver's internal state 152 // machine buffer for use by a subsequent call to WriteByte() (or Write()) 153 // that completes the codepoint. 154 // 4. If the given byte is out of range, or contains illegal bits for the 155 // current state of the UTF-8 decoder, then the UTF-8 decode state machine 156 // is reset to its initial state. 157 // 158 // In cases 3 and 4, a keypress sequence is not generated and no data is 159 // transmitted. In case 3, additional bytes must be received via WriteByte() 160 // (or Write()) to complete or discard the current codepoint. 161 func (kb *keyboard) WriteByte(b byte) error { 162 switch { 163 case b < 0x80: 164 // 1-byte encoding (0x00-0x7F) 165 kb.decode = decodeByte1 166 return kb.write(uint16(b)) 167 168 case b < 0xC0: 169 // 2nd, 3rd, or 4th byte (0x80-0xBF) 170 b = Keycode(b).key() 171 switch kb.decode { 172 case decodeByte2: 173 kb.decode = decodeByte1 174 return kb.write(kb.wideChar | uint16(b)) 175 case decodeByte3: 176 kb.decode = decodeByte2 177 kb.wideChar |= uint16(b) << 6 178 } 179 180 case b < 0xE0: 181 // 2-byte encoding (0xC2-0xDF), or illegal byte 2 (0xC0-0xC1) 182 kb.decode = decodeByte2 183 kb.wideChar = uint16(b&0x1F) << 6 184 185 case b < 0xF0: 186 // 3-byte encoding (0xE0-0xEF) 187 kb.decode = decodeByte3 188 kb.wideChar = uint16(b&0x0F) << 12 189 190 default: 191 // 4-byte encoding unsupported (0xF0-0xF4), or illegal byte 4 (0xF5-0xFF) 192 kb.decode = decodeReset 193 return ErrInvalidUTF8 194 } 195 return nil 196 } 197 198 func (kb *keyboard) write(p uint16) error { 199 c := keycode(p) 200 if 0 == c { 201 return ErrInvalidCodepoint 202 } 203 if d := deadkey(c); 0 != d { 204 if err := kb.writeKeycode(d); nil != err { 205 return err 206 } 207 } 208 return kb.writeKeycode(c) 209 } 210 211 func (kb *keyboard) writeKeycode(c Keycode) error { 212 var b [9]byte 213 b[0] = 0x02 214 b[1] = c.mod() 215 b[2] = 0 216 b[3] = c.key() 217 b[4] = 0 218 b[5] = 0 219 b[6] = 0 220 b[7] = 0 221 b[8] = 0 222 if !kb.sendKey(false, b[:]) { 223 return hid.ErrHIDReportTransfer 224 } 225 226 b[1] = 0 227 b[3] = 0 228 if !kb.sendKey(false, b[:]) { 229 return hid.ErrHIDReportTransfer 230 } 231 return nil 232 } 233 234 // Press transmits a press-and-release sequence for the given Keycode, which 235 // simulates a discrete keypress event. 236 // 237 // The following values of Keycode are supported: 238 // 239 // 0x0020 - 0x007F ASCII (U+0020 to U+007F) [USES LAYOUT] 240 // 0x0080 - 0xC1FF Unicode (U+0080 to U+C1FF) [USES LAYOUT] 241 // 0xC200 - 0xDFFF UTF-8 packed (U+0080 to U+07FF) [USES LAYOUT] 242 // 0xE000 - 0xE0FF Modifier key (bitmap, 8 keys, Shift/Ctrl/Alt/GUI) 243 // 0xE200 - 0xE2FF System key (HID usage code, page 1) 244 // 0xE400 - 0xE7FF Media/Consumer key (HID usage code, page 12) 245 // 0xF000 - 0xFFFF Normal key (HID usage code, page 7) 246 func (kb *keyboard) Press(c Keycode) error { 247 if err := kb.Down(c); nil != err { 248 return err 249 } 250 return kb.Up(c) 251 } 252 253 func (kb *keyboard) sendKey(consumer bool, b []byte) bool { 254 kb.tx(b) 255 return true 256 } 257 258 func (kb *keyboard) keyboardSendKeys(consumer bool) bool { 259 var b [9]byte 260 261 if !consumer { 262 b[0] = 0x02 // REPORT_ID 263 b[1] = kb.mod 264 b[2] = 0x02 265 b[3] = kb.key[0] 266 b[4] = kb.key[1] 267 b[5] = kb.key[2] 268 b[6] = kb.key[3] 269 b[7] = kb.key[4] 270 b[8] = kb.key[5] 271 return kb.sendKey(consumer, b[:]) 272 273 } else { 274 b[0] = 0x03 // REPORT_ID 275 b[1] = uint8(kb.con[0]) 276 b[2] = uint8((kb.con[0] & 0x0300) >> 8) 277 278 return kb.sendKey(consumer, b[:3]) 279 } 280 } 281 282 // Down transmits a key-down event for the given Keycode. 283 // 284 // The host will interpret the key as being held down continuously until a 285 // corresponding key-up event is transmitted, e.g., via method Up(). 286 // 287 // See godoc comment on method Press() for details on what input is accepted and 288 // how it is interpreted. 289 func (kb *keyboard) Down(c Keycode) error { 290 var res uint8 291 msb := c >> 8 292 if msb >= 0xC2 { 293 if msb < 0xE0 { 294 c = ((msb & 0x1F) << 6) | Keycode(c.key()) 295 } else { 296 switch msb { 297 case 0xF0: 298 return kb.down(uint8(c), 0) 299 300 case 0xE0: 301 return kb.down(0, uint8(c)) 302 303 case 0xE2: 304 return kb.downSys(uint8(c)) 305 306 default: 307 if 0xE4 <= msb && msb <= 0xE7 { 308 return kb.downCon(uint16(c & 0x03FF)) 309 } 310 return ErrInvalidKeycode 311 } 312 } 313 } 314 c = keycode(uint16(c)) 315 if 0 == c { 316 return ErrInvalidCodepoint 317 } 318 if d := deadkey(c); 0 != d { 319 res = kb.mod 320 if 0 != res { 321 kb.mod = 0 322 kb.keyboardSendKeys(false) 323 } 324 kb.down(d.key(), d.mod()) 325 kb.up(d.key(), d.mod()) 326 } 327 return kb.down(c.key(), c.mod()|res) 328 } 329 330 func (kb *keyboard) down(key uint8, mod uint8) error { 331 send := false 332 if 0 != mod { 333 if kb.mod&mod != mod { 334 kb.mod |= mod 335 send = true 336 } 337 } 338 if 0 != key { 339 for _, k := range kb.key { 340 if k == key { 341 goto end 342 } 343 } 344 for i, k := range kb.key { 345 if 0 == k { 346 kb.key[i] = key 347 send = true 348 goto end 349 } 350 } 351 return ErrKeypressMaximum 352 } 353 end: 354 if send { 355 if !kb.keyboardSendKeys(false) { 356 return hid.ErrHIDReportTransfer 357 } 358 } 359 return nil 360 } 361 362 func (kb *keyboard) downCon(key uint16) error { 363 if 0 == key { 364 return ErrInvalidKeycode 365 } 366 for _, k := range kb.con { 367 if key == k { 368 return nil // already pressed 369 } 370 } 371 for i, k := range kb.con { 372 if 0 == k { 373 kb.con[i] = key 374 if !kb.keyboardSendKeys(true) { 375 return hid.ErrHIDReportTransfer 376 } 377 return nil 378 } 379 } 380 return ErrKeypressMaximum 381 } 382 383 func (kb *keyboard) downSys(key uint8) error { 384 if 0 == key { 385 return ErrInvalidKeycode 386 } 387 for _, k := range kb.sys { 388 if key == k { 389 return nil // already pressed 390 } 391 } 392 for i, k := range kb.sys { 393 if 0 == k { 394 kb.sys[i] = key 395 if !kb.keyboardSendKeys(true) { 396 return hid.ErrHIDReportTransfer 397 } 398 return nil 399 } 400 } 401 return ErrKeypressMaximum 402 } 403 404 // Up transmits a key-up event for the given Keycode. 405 // 406 // See godoc comment on method Press() for details on what input is accepted and 407 // how it is interpreted. 408 func (kb *keyboard) Up(c Keycode) error { 409 msb := c >> 8 410 if msb >= 0xC2 { 411 if msb < 0xE0 { 412 c = ((msb & 0x1F) << 6) | Keycode(c.key()) 413 } else { 414 switch msb { 415 case 0xF0: 416 return kb.up(uint8(c), 0) 417 418 case 0xE0: 419 return kb.up(0, uint8(c)) 420 421 case 0xE2: 422 return kb.upSys(uint8(c)) 423 424 default: 425 if 0xE4 <= msb && msb <= 0xE7 { 426 return kb.upCon(uint16(c & 0x03FF)) 427 } 428 return ErrInvalidKeycode 429 } 430 } 431 } 432 c = keycode(uint16(c)) 433 if 0 == c { 434 return ErrInvalidCodepoint 435 } 436 return kb.up(c.key(), c.mod()) 437 } 438 439 // Release transmits a key-up event for all keyboard keys currently pressed as 440 // if the user removed his/her hands from the keyboard entirely. 441 func (kb *keyboard) Release() error { 442 443 bits := uint16(kb.mod) 444 kb.mod = 0 445 for i, k := range kb.key { 446 bits |= uint16(k) 447 kb.key[i] = 0 448 } 449 if 0 != bits { 450 if !kb.keyboardSendKeys(false) { 451 return hid.ErrHIDReportTransfer 452 } 453 } 454 bits = 0 455 for i, k := range kb.con { 456 bits |= k 457 kb.con[i] = 0 458 } 459 for i, k := range kb.sys { 460 bits |= uint16(k) 461 kb.sys[i] = 0 462 } 463 if 0 != bits { 464 if !kb.keyboardSendKeys(true) { 465 return hid.ErrHIDReportTransfer 466 } 467 } 468 return nil 469 } 470 471 func (kb *keyboard) up(key uint8, mod uint8) error { 472 send := false 473 if 0 != mod { 474 if kb.mod&mod != 0 { 475 kb.mod &^= mod 476 send = true 477 } 478 } 479 if 0 != key { 480 for i, k := range kb.key { 481 if key == k { 482 kb.key[i] = 0 483 send = true 484 } 485 } 486 } 487 if send { 488 if !kb.keyboardSendKeys(false) { 489 return hid.ErrHIDReportTransfer 490 } 491 } 492 return nil 493 } 494 495 func (kb *keyboard) upCon(key uint16) error { 496 if 0 == key { 497 return ErrInvalidKeycode 498 } 499 for i, k := range kb.con { 500 if key == k { 501 kb.con[i] = 0 502 if !kb.keyboardSendKeys(true) { 503 return hid.ErrHIDReportTransfer 504 } 505 return nil 506 } 507 } 508 return nil 509 } 510 511 func (kb *keyboard) upSys(key uint8) error { 512 if 0 == key { 513 return ErrInvalidKeycode 514 } 515 for i, k := range kb.sys { 516 if key == k { 517 kb.sys[i] = 0 518 if !kb.keyboardSendKeys(true) { 519 return hid.ErrHIDReportTransfer 520 } 521 return nil 522 } 523 } 524 return nil 525 }