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  }