samd21,samd51,nrf52840: add support for USBHID (keyboard / mouse)
Этот коммит содержится в:
родитель
2c93a4085c
коммит
1b2e764835
13 изменённых файлов: 1510 добавлений и 479 удалений
9
Makefile
9
Makefile
|
@ -414,6 +414,10 @@ smoketest:
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test simulated boards on play.tinygo.org
|
# test simulated boards on play.tinygo.org
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||||
|
@ -555,6 +559,11 @@ endif
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
# test usbhid
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/hid-keyboard
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/hid-keyboard
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
ifneq ($(STM32), 0)
|
ifneq ($(STM32), 0)
|
||||||
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
|
21
src/examples/hid-keyboard/main.go
Обычный файл
21
src/examples/hid-keyboard/main.go
Обычный файл
|
@ -0,0 +1,21 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"machine/usb/hid/keyboard"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
button := machine.BUTTON
|
||||||
|
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
|
kb := keyboard.New()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !button.Get() {
|
||||||
|
kb.Write([]byte("tinygo"))
|
||||||
|
time.Sleep(200 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
src/examples/hid-mouse/main.go
Обычный файл
37
src/examples/hid-mouse/main.go
Обычный файл
|
@ -0,0 +1,37 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine"
|
||||||
|
"machine/usb/hid/mouse"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
button := machine.BUTTON
|
||||||
|
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
|
mouse := mouse.New()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if !button.Get() {
|
||||||
|
for j := 0; j < 5; j++ {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
mouse.Move(1, 0)
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
mouse.Move(0, 1)
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
mouse.Move(-1, -1)
|
||||||
|
time.Sleep(1 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1747,6 +1747,7 @@ type USBCDC struct {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
USB = &USBCDC{Buffer: NewRingBuffer()}
|
USB = &USBCDC{Buffer: NewRingBuffer()}
|
||||||
|
waitHidTxc bool
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -1999,6 +2000,9 @@ func handleUSB(intr interrupt.Interrupt) {
|
||||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||||
USB.Flush()
|
USB.Flush()
|
||||||
// if you want to blink LED showing traffic, this would be the place...
|
// if you want to blink LED showing traffic, this would be the place...
|
||||||
|
if hidCallback != nil && !waitHidTxc {
|
||||||
|
hidCallback()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Endpoint 0 Setup interrupt
|
// Endpoint 0 Setup interrupt
|
||||||
|
@ -2021,6 +2025,9 @@ func handleUSB(intr interrupt.Interrupt) {
|
||||||
// Class Interface Requests
|
// Class Interface Requests
|
||||||
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
||||||
ok = cdcSetup(setup)
|
ok = cdcSetup(setup)
|
||||||
|
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
|
||||||
|
sendZlp()
|
||||||
|
ok = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2059,6 +2066,9 @@ func handleUSB(intr interrupt.Interrupt) {
|
||||||
if i == usb_CDC_ENDPOINT_IN {
|
if i == usb_CDC_ENDPOINT_IN {
|
||||||
USB.waitTxc = false
|
USB.waitTxc = false
|
||||||
}
|
}
|
||||||
|
case usb_HID_ENDPOINT_IN:
|
||||||
|
setEPINTFLAG(i, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||||
|
waitHidTxc = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2156,7 +2166,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendUSBPacket(0, buf)
|
sendUSBPacket(0, buf, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_CLEAR_FEATURE:
|
case usb_CLEAR_FEATURE:
|
||||||
|
@ -2212,7 +2222,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
|
|
||||||
case usb_GET_CONFIGURATION:
|
case usb_GET_CONFIGURATION:
|
||||||
buff := []byte{usbConfiguration}
|
buff := []byte{usbConfiguration}
|
||||||
sendUSBPacket(0, buff)
|
sendUSBPacket(0, buff, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_SET_CONFIGURATION:
|
case usb_SET_CONFIGURATION:
|
||||||
|
@ -2229,6 +2239,11 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
// Enable interrupt for CDC data messages from host
|
// Enable interrupt for CDC data messages from host
|
||||||
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0)
|
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_EPINTENSET_TRCPT0)
|
||||||
|
|
||||||
|
// Enable interrupt for HID messages from host
|
||||||
|
if hidCallback != nil {
|
||||||
|
setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_EPINTENSET_TRCPT1)
|
||||||
|
}
|
||||||
|
|
||||||
sendZlp()
|
sendZlp()
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
|
@ -2237,7 +2252,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
|
|
||||||
case usb_GET_INTERFACE:
|
case usb_GET_INTERFACE:
|
||||||
buff := []byte{usbSetInterface}
|
buff := []byte{usbSetInterface}
|
||||||
sendUSBPacket(0, buff)
|
sendUSBPacket(0, buff, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_SET_INTERFACE:
|
case usb_SET_INTERFACE:
|
||||||
|
@ -2263,7 +2278,7 @@ func cdcSetup(setup usbSetup) bool {
|
||||||
b[5] = byte(usbLineInfo.bParityType)
|
b[5] = byte(usbLineInfo.bParityType)
|
||||||
b[6] = byte(usbLineInfo.bDataBits)
|
b[6] = byte(usbLineInfo.bDataBits)
|
||||||
|
|
||||||
sendUSBPacket(0, b[:])
|
sendUSBPacket(0, b[:], setup.wLength)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2306,9 +2321,31 @@ func cdcSetup(setup usbSetup) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
|
||||||
|
func SendUSBHIDPacket(ep uint32, data []byte) bool {
|
||||||
|
if waitHidTxc {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
sendUSBPacket(ep, data, 0)
|
||||||
|
|
||||||
|
// clear transfer complete flag
|
||||||
|
setEPINTFLAG(ep, sam.USB_DEVICE_EPINTFLAG_TRCPT1)
|
||||||
|
|
||||||
|
// send data by setting bank ready
|
||||||
|
setEPSTATUSSET(ep, sam.USB_DEVICE_EPSTATUSSET_BK1RDY)
|
||||||
|
|
||||||
|
waitHidTxc = true
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func sendUSBPacket(ep uint32, data []byte) {
|
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||||
copy(udd_ep_in_cache_buffer[ep][:], data)
|
l := uint16(len(data))
|
||||||
|
if 0 < maxsize && maxsize < l {
|
||||||
|
l = maxsize
|
||||||
|
}
|
||||||
|
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||||
|
|
||||||
// Set endpoint address for sending data
|
// Set endpoint address for sending data
|
||||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||||
|
@ -2318,7 +2355,7 @@ func sendUSBPacket(ep uint32, data []byte) {
|
||||||
|
|
||||||
// set byte count, which is total number of bytes to be sent
|
// set byte count, which is total number of bytes to be sent
|
||||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
|
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||||
|
|
|
@ -1988,6 +1988,7 @@ type USBCDC struct {
|
||||||
var (
|
var (
|
||||||
// USB is a USB CDC interface.
|
// USB is a USB CDC interface.
|
||||||
USB = &USBCDC{Buffer: NewRingBuffer()}
|
USB = &USBCDC{Buffer: NewRingBuffer()}
|
||||||
|
waitHidTxc bool
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -2241,6 +2242,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
|
||||||
// Start of frame
|
// Start of frame
|
||||||
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
if (flags & sam.USB_DEVICE_INTFLAG_SOF) > 0 {
|
||||||
USB.Flush()
|
USB.Flush()
|
||||||
|
if hidCallback != nil && !waitHidTxc {
|
||||||
|
hidCallback()
|
||||||
|
}
|
||||||
// if you want to blink LED showing traffic, this would be the place...
|
// if you want to blink LED showing traffic, this would be the place...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2264,6 +2268,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
|
||||||
// Class Interface Requests
|
// Class Interface Requests
|
||||||
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
||||||
ok = cdcSetup(setup)
|
ok = cdcSetup(setup)
|
||||||
|
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
|
||||||
|
sendZlp()
|
||||||
|
ok = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2302,6 +2309,9 @@ func handleUSBIRQ(interrupt.Interrupt) {
|
||||||
if i == usb_CDC_ENDPOINT_IN {
|
if i == usb_CDC_ENDPOINT_IN {
|
||||||
USB.waitTxc = false
|
USB.waitTxc = false
|
||||||
}
|
}
|
||||||
|
case usb_HID_ENDPOINT_IN:
|
||||||
|
setEPINTFLAG(i, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||||
|
waitHidTxc = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2399,7 +2409,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendUSBPacket(0, buf)
|
sendUSBPacket(0, buf, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_CLEAR_FEATURE:
|
case usb_CLEAR_FEATURE:
|
||||||
|
@ -2455,7 +2465,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
|
|
||||||
case usb_GET_CONFIGURATION:
|
case usb_GET_CONFIGURATION:
|
||||||
buff := []byte{usbConfiguration}
|
buff := []byte{usbConfiguration}
|
||||||
sendUSBPacket(0, buff)
|
sendUSBPacket(0, buff, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_SET_CONFIGURATION:
|
case usb_SET_CONFIGURATION:
|
||||||
|
@ -2472,6 +2482,11 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
// Enable interrupt for CDC data messages from host
|
// Enable interrupt for CDC data messages from host
|
||||||
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
|
setEPINTENSET(usb_CDC_ENDPOINT_OUT, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT0)
|
||||||
|
|
||||||
|
// Enable interrupt for HID messages from host
|
||||||
|
if hidCallback != nil {
|
||||||
|
setEPINTENSET(usb_HID_ENDPOINT_IN, sam.USB_DEVICE_ENDPOINT_EPINTENSET_TRCPT1)
|
||||||
|
}
|
||||||
|
|
||||||
sendZlp()
|
sendZlp()
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
|
@ -2480,7 +2495,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
|
|
||||||
case usb_GET_INTERFACE:
|
case usb_GET_INTERFACE:
|
||||||
buff := []byte{usbSetInterface}
|
buff := []byte{usbSetInterface}
|
||||||
sendUSBPacket(0, buff)
|
sendUSBPacket(0, buff, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_SET_INTERFACE:
|
case usb_SET_INTERFACE:
|
||||||
|
@ -2506,7 +2521,7 @@ func cdcSetup(setup usbSetup) bool {
|
||||||
b[5] = byte(usbLineInfo.bParityType)
|
b[5] = byte(usbLineInfo.bParityType)
|
||||||
b[6] = byte(usbLineInfo.bDataBits)
|
b[6] = byte(usbLineInfo.bDataBits)
|
||||||
|
|
||||||
sendUSBPacket(0, b[:])
|
sendUSBPacket(0, b[:], setup.wLength)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2549,9 +2564,32 @@ func cdcSetup(setup usbSetup) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
|
||||||
|
func SendUSBHIDPacket(ep uint32, data []byte) bool {
|
||||||
|
if waitHidTxc {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sendUSBPacket(ep, data, 0)
|
||||||
|
|
||||||
|
// clear transfer complete flag
|
||||||
|
setEPINTFLAG(ep, sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1)
|
||||||
|
|
||||||
|
// send data by setting bank ready
|
||||||
|
setEPSTATUSSET(ep, sam.USB_DEVICE_ENDPOINT_EPSTATUSSET_BK1RDY)
|
||||||
|
|
||||||
|
waitHidTxc = true
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func sendUSBPacket(ep uint32, data []byte) {
|
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||||
copy(udd_ep_in_cache_buffer[ep][:], data)
|
l := uint16(len(data))
|
||||||
|
if 0 < maxsize && maxsize < l {
|
||||||
|
l = maxsize
|
||||||
|
}
|
||||||
|
copy(udd_ep_in_cache_buffer[ep][:], data[:l])
|
||||||
|
|
||||||
// Set endpoint address for sending data
|
// Set endpoint address for sending data
|
||||||
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
usbEndpointDescriptors[ep].DeviceDescBank[1].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_in_cache_buffer[ep]))))
|
||||||
|
@ -2561,7 +2599,7 @@ func sendUSBPacket(ep uint32, data []byte) {
|
||||||
|
|
||||||
// set byte count, which is total number of bytes to be sent
|
// set byte count, which is total number of bytes to be sent
|
||||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||||
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
|
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits((uint32(l) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||||
|
|
|
@ -123,6 +123,7 @@ func (usbcdc *USBCDC) RTS() bool {
|
||||||
var (
|
var (
|
||||||
USB = &_USB
|
USB = &_USB
|
||||||
_USB = USBCDC{Buffer: NewRingBuffer()}
|
_USB = USBCDC{Buffer: NewRingBuffer()}
|
||||||
|
waitHidTxc bool
|
||||||
|
|
||||||
usbEndpointDescriptors [8]usbDeviceDescriptor
|
usbEndpointDescriptors [8]usbDeviceDescriptor
|
||||||
|
|
||||||
|
@ -201,6 +202,9 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||||
if nrf.USBD.EVENTS_SOF.Get() == 1 {
|
if nrf.USBD.EVENTS_SOF.Get() == 1 {
|
||||||
nrf.USBD.EVENTS_SOF.Set(0)
|
nrf.USBD.EVENTS_SOF.Set(0)
|
||||||
usbcdc.Flush()
|
usbcdc.Flush()
|
||||||
|
if hidCallback != nil && !waitHidTxc {
|
||||||
|
hidCallback()
|
||||||
|
}
|
||||||
// if you want to blink LED showing traffic, this would be the place...
|
// if you want to blink LED showing traffic, this would be the place...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,6 +266,9 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||||
} else {
|
} else {
|
||||||
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
if setup.wIndex == usb_CDC_ACM_INTERFACE {
|
||||||
ok = cdcSetup(setup)
|
ok = cdcSetup(setup)
|
||||||
|
} else if setup.bmRequestType == usb_SET_REPORT_TYPE && setup.bRequest == usb_SET_IDLE {
|
||||||
|
sendZlp()
|
||||||
|
ok = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,6 +304,8 @@ func (usbcdc *USBCDC) handleInterrupt(interrupt.Interrupt) {
|
||||||
usbcdc.waitTxc = false
|
usbcdc.waitTxc = false
|
||||||
exitCriticalSection()
|
exitCriticalSection()
|
||||||
}
|
}
|
||||||
|
case usb_HID_ENDPOINT_IN:
|
||||||
|
waitHidTxc = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -378,7 +387,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendUSBPacket(0, buf)
|
sendUSBPacket(0, buf, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_CLEAR_FEATURE:
|
case usb_CLEAR_FEATURE:
|
||||||
|
@ -412,7 +421,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
|
|
||||||
case usb_GET_CONFIGURATION:
|
case usb_GET_CONFIGURATION:
|
||||||
buff := []byte{usbConfiguration}
|
buff := []byte{usbConfiguration}
|
||||||
sendUSBPacket(0, buff)
|
sendUSBPacket(0, buff, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_SET_CONFIGURATION:
|
case usb_SET_CONFIGURATION:
|
||||||
|
@ -422,6 +431,11 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
initEndpoint(uint32(i), endPoints[i])
|
initEndpoint(uint32(i), endPoints[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable interrupt for HID messages from host
|
||||||
|
if hidCallback != nil {
|
||||||
|
nrf.USBD.INTENSET.Set(nrf.USBD_INTENSET_ENDEPOUT0 << usb_HID_ENDPOINT_IN)
|
||||||
|
}
|
||||||
|
|
||||||
usbConfiguration = setup.wValueL
|
usbConfiguration = setup.wValueL
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
|
@ -430,7 +444,7 @@ func handleStandardSetup(setup usbSetup) bool {
|
||||||
|
|
||||||
case usb_GET_INTERFACE:
|
case usb_GET_INTERFACE:
|
||||||
buff := []byte{usbSetInterface}
|
buff := []byte{usbSetInterface}
|
||||||
sendUSBPacket(0, buff)
|
sendUSBPacket(0, buff, setup.wLength)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
case usb_SET_INTERFACE:
|
case usb_SET_INTERFACE:
|
||||||
|
@ -456,7 +470,7 @@ func cdcSetup(setup usbSetup) bool {
|
||||||
b[5] = byte(usbLineInfo.bParityType)
|
b[5] = byte(usbLineInfo.bParityType)
|
||||||
b[6] = byte(usbLineInfo.bDataBits)
|
b[6] = byte(usbLineInfo.bDataBits)
|
||||||
|
|
||||||
sendUSBPacket(0, b[:])
|
sendUSBPacket(0, b[:], setup.wLength)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -482,10 +496,29 @@ func cdcSetup(setup usbSetup) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendUSBHIDPacket sends a packet for USBHID (interrupt / in).
|
||||||
|
func SendUSBHIDPacket(ep uint32, data []byte) bool {
|
||||||
|
if waitHidTxc {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
sendUSBPacket(ep, data, 0)
|
||||||
|
|
||||||
|
// clear transfer complete flag
|
||||||
|
nrf.USBD.INTENCLR.Set(nrf.USBD_INTENCLR_ENDEPOUT0 << 4)
|
||||||
|
|
||||||
|
waitHidTxc = true
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func sendUSBPacket(ep uint32, data []byte) {
|
func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||||
count := len(data)
|
count := len(data)
|
||||||
copy(udd_ep_in_cache_buffer[ep][:], data)
|
if 0 < int(maxsize) && int(maxsize) < count {
|
||||||
|
count = int(maxsize)
|
||||||
|
}
|
||||||
|
copy(udd_ep_in_cache_buffer[ep][:], data[:count])
|
||||||
if ep == 0 && count > usbEndpointPacketSize {
|
if ep == 0 && count > usbEndpointPacketSize {
|
||||||
sendOnEP0DATADONE.ptr = &udd_ep_in_cache_buffer[ep][usbEndpointPacketSize]
|
sendOnEP0DATADONE.ptr = &udd_ep_in_cache_buffer[ep][usbEndpointPacketSize]
|
||||||
sendOnEP0DATADONE.count = count - usbEndpointPacketSize
|
sendOnEP0DATADONE.count = count - usbEndpointPacketSize
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
const deviceDescriptorSize = 18
|
var usbDescriptor = descriptorCDC
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty")
|
errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty")
|
||||||
|
@ -17,397 +17,6 @@ var (
|
||||||
errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read")
|
errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read")
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeviceDescriptor implements the USB standard device descriptor.
|
|
||||||
//
|
|
||||||
// Table 9-8. Standard Device Descriptor
|
|
||||||
// bLength, bDescriptorType, bcdUSB, bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0,
|
|
||||||
// idVendor, idProduct, bcdDevice, iManufacturer, iProduct, iSerialNumber, bNumConfigurations */
|
|
||||||
//
|
|
||||||
type DeviceDescriptor struct {
|
|
||||||
bLength uint8 // 18
|
|
||||||
bDescriptorType uint8 // 1 USB_DEVICE_DESCRIPTOR_TYPE
|
|
||||||
bcdUSB uint16 // 0x200
|
|
||||||
bDeviceClass uint8
|
|
||||||
bDeviceSubClass uint8
|
|
||||||
bDeviceProtocol uint8
|
|
||||||
bMaxPacketSize0 uint8 // Packet 0
|
|
||||||
idVendor uint16
|
|
||||||
idProduct uint16
|
|
||||||
bcdDevice uint16 // 0x100
|
|
||||||
iManufacturer uint8
|
|
||||||
iProduct uint8
|
|
||||||
iSerialNumber uint8
|
|
||||||
bNumConfigurations uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDeviceDescriptor returns a USB DeviceDescriptor.
|
|
||||||
func NewDeviceDescriptor(class, subClass, proto, packetSize0 uint8, vid, pid, version uint16, im, ip, is, configs uint8) DeviceDescriptor {
|
|
||||||
return DeviceDescriptor{deviceDescriptorSize, 1, 0x200, class, subClass, proto, packetSize0, vid, pid, version, im, ip, is, configs}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns DeviceDescriptor data
|
|
||||||
func (d DeviceDescriptor) Bytes() [deviceDescriptorSize]byte {
|
|
||||||
var b [deviceDescriptorSize]byte
|
|
||||||
b[0] = byte(d.bLength)
|
|
||||||
b[1] = byte(d.bDescriptorType)
|
|
||||||
b[2] = byte(d.bcdUSB)
|
|
||||||
b[3] = byte(d.bcdUSB >> 8)
|
|
||||||
b[4] = byte(d.bDeviceClass)
|
|
||||||
b[5] = byte(d.bDeviceSubClass)
|
|
||||||
b[6] = byte(d.bDeviceProtocol)
|
|
||||||
b[7] = byte(d.bMaxPacketSize0)
|
|
||||||
b[8] = byte(d.idVendor)
|
|
||||||
b[9] = byte(d.idVendor >> 8)
|
|
||||||
b[10] = byte(d.idProduct)
|
|
||||||
b[11] = byte(d.idProduct >> 8)
|
|
||||||
b[12] = byte(d.bcdDevice)
|
|
||||||
b[13] = byte(d.bcdDevice >> 8)
|
|
||||||
b[14] = byte(d.iManufacturer)
|
|
||||||
b[15] = byte(d.iProduct)
|
|
||||||
b[16] = byte(d.iSerialNumber)
|
|
||||||
b[17] = byte(d.bNumConfigurations)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const configDescriptorSize = 9
|
|
||||||
|
|
||||||
// ConfigDescriptor implements the standard USB configuration descriptor.
|
|
||||||
//
|
|
||||||
// Table 9-10. Standard Configuration Descriptor
|
|
||||||
// bLength, bDescriptorType, wTotalLength, bNumInterfaces, bConfigurationValue, iConfiguration
|
|
||||||
// bmAttributes, bMaxPower
|
|
||||||
//
|
|
||||||
type ConfigDescriptor struct {
|
|
||||||
bLength uint8 // 9
|
|
||||||
bDescriptorType uint8 // 2
|
|
||||||
wTotalLength uint16 // total length
|
|
||||||
bNumInterfaces uint8
|
|
||||||
bConfigurationValue uint8
|
|
||||||
iConfiguration uint8
|
|
||||||
bmAttributes uint8
|
|
||||||
bMaxPower uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConfigDescriptor returns a new USB ConfigDescriptor.
|
|
||||||
func NewConfigDescriptor(totalLength uint16, interfaces uint8) ConfigDescriptor {
|
|
||||||
return ConfigDescriptor{configDescriptorSize, 2, totalLength, interfaces, 1, 0, usb_CONFIG_BUS_POWERED | usb_CONFIG_REMOTE_WAKEUP, 50}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns ConfigDescriptor data.
|
|
||||||
func (d ConfigDescriptor) Bytes() [configDescriptorSize]byte {
|
|
||||||
var b [configDescriptorSize]byte
|
|
||||||
b[0] = byte(d.bLength)
|
|
||||||
b[1] = byte(d.bDescriptorType)
|
|
||||||
b[2] = byte(d.wTotalLength)
|
|
||||||
b[3] = byte(d.wTotalLength >> 8)
|
|
||||||
b[4] = byte(d.bNumInterfaces)
|
|
||||||
b[5] = byte(d.bConfigurationValue)
|
|
||||||
b[6] = byte(d.iConfiguration)
|
|
||||||
b[7] = byte(d.bmAttributes)
|
|
||||||
b[8] = byte(d.bMaxPower)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const interfaceDescriptorSize = 9
|
|
||||||
|
|
||||||
// InterfaceDescriptor implements the standard USB interface descriptor.
|
|
||||||
//
|
|
||||||
// Table 9-12. Standard Interface Descriptor
|
|
||||||
// bLength, bDescriptorType, bInterfaceNumber, bAlternateSetting, bNumEndpoints, bInterfaceClass,
|
|
||||||
// bInterfaceSubClass, bInterfaceProtocol, iInterface
|
|
||||||
//
|
|
||||||
type InterfaceDescriptor struct {
|
|
||||||
bLength uint8 // 9
|
|
||||||
bDescriptorType uint8 // 4
|
|
||||||
bInterfaceNumber uint8
|
|
||||||
bAlternateSetting uint8
|
|
||||||
bNumEndpoints uint8
|
|
||||||
bInterfaceClass uint8
|
|
||||||
bInterfaceSubClass uint8
|
|
||||||
bInterfaceProtocol uint8
|
|
||||||
iInterface uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewInterfaceDescriptor returns a new USB InterfaceDescriptor.
|
|
||||||
func NewInterfaceDescriptor(n, numEndpoints, class, subClass, protocol uint8) InterfaceDescriptor {
|
|
||||||
return InterfaceDescriptor{interfaceDescriptorSize, 4, n, 0, numEndpoints, class, subClass, protocol, 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns InterfaceDescriptor data.
|
|
||||||
func (d InterfaceDescriptor) Bytes() [interfaceDescriptorSize]byte {
|
|
||||||
var b [interfaceDescriptorSize]byte
|
|
||||||
b[0] = byte(d.bLength)
|
|
||||||
b[1] = byte(d.bDescriptorType)
|
|
||||||
b[2] = byte(d.bInterfaceNumber)
|
|
||||||
b[3] = byte(d.bAlternateSetting)
|
|
||||||
b[4] = byte(d.bNumEndpoints)
|
|
||||||
b[5] = byte(d.bInterfaceClass)
|
|
||||||
b[6] = byte(d.bInterfaceSubClass)
|
|
||||||
b[7] = byte(d.bInterfaceProtocol)
|
|
||||||
b[8] = byte(d.iInterface)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const endpointDescriptorSize = 7
|
|
||||||
|
|
||||||
// EndpointDescriptor implements the standard USB endpoint descriptor.
|
|
||||||
//
|
|
||||||
// Table 9-13. Standard Endpoint Descriptor
|
|
||||||
// bLength, bDescriptorType, bEndpointAddress, bmAttributes, wMaxPacketSize, bInterval
|
|
||||||
//
|
|
||||||
type EndpointDescriptor struct {
|
|
||||||
bLength uint8 // 7
|
|
||||||
bDescriptorType uint8 // 5
|
|
||||||
bEndpointAddress uint8
|
|
||||||
bmAttributes uint8
|
|
||||||
wMaxPacketSize uint16
|
|
||||||
bInterval uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEndpointDescriptor returns a new USB EndpointDescriptor.
|
|
||||||
func NewEndpointDescriptor(addr, attr uint8, packetSize uint16, interval uint8) EndpointDescriptor {
|
|
||||||
return EndpointDescriptor{endpointDescriptorSize, 5, addr, attr, packetSize, interval}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns EndpointDescriptor data.
|
|
||||||
func (d EndpointDescriptor) Bytes() [endpointDescriptorSize]byte {
|
|
||||||
var b [endpointDescriptorSize]byte
|
|
||||||
b[0] = byte(d.bLength)
|
|
||||||
b[1] = byte(d.bDescriptorType)
|
|
||||||
b[2] = byte(d.bEndpointAddress)
|
|
||||||
b[3] = byte(d.bmAttributes)
|
|
||||||
b[4] = byte(d.wMaxPacketSize)
|
|
||||||
b[5] = byte(d.wMaxPacketSize >> 8)
|
|
||||||
b[6] = byte(d.bInterval)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const iadDescriptorSize = 8
|
|
||||||
|
|
||||||
// IADDescriptor is an Interface Association Descriptor, which is used
|
|
||||||
// to bind 2 interfaces together in CDC composite device.
|
|
||||||
//
|
|
||||||
// Standard Interface Association Descriptor:
|
|
||||||
// bLength, bDescriptorType, bFirstInterface, bInterfaceCount, bFunctionClass, bFunctionSubClass,
|
|
||||||
// bFunctionProtocol, iFunction
|
|
||||||
//
|
|
||||||
type IADDescriptor struct {
|
|
||||||
bLength uint8 // 8
|
|
||||||
bDescriptorType uint8 // 11
|
|
||||||
bFirstInterface uint8
|
|
||||||
bInterfaceCount uint8
|
|
||||||
bFunctionClass uint8
|
|
||||||
bFunctionSubClass uint8
|
|
||||||
bFunctionProtocol uint8
|
|
||||||
iFunction uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewIADDescriptor returns a new USB IADDescriptor.
|
|
||||||
func NewIADDescriptor(firstInterface, count, class, subClass, protocol uint8) IADDescriptor {
|
|
||||||
return IADDescriptor{iadDescriptorSize, 11, firstInterface, count, class, subClass, protocol, 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns IADDescriptor data.
|
|
||||||
func (d IADDescriptor) Bytes() [iadDescriptorSize]byte {
|
|
||||||
var b [iadDescriptorSize]byte
|
|
||||||
b[0] = byte(d.bLength)
|
|
||||||
b[1] = byte(d.bDescriptorType)
|
|
||||||
b[2] = byte(d.bFirstInterface)
|
|
||||||
b[3] = byte(d.bInterfaceCount)
|
|
||||||
b[4] = byte(d.bFunctionClass)
|
|
||||||
b[5] = byte(d.bFunctionSubClass)
|
|
||||||
b[6] = byte(d.bFunctionProtocol)
|
|
||||||
b[7] = byte(d.iFunction)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const cdcCSInterfaceDescriptorSize = 5
|
|
||||||
|
|
||||||
// CDCCSInterfaceDescriptor is a CDC CS interface descriptor.
|
|
||||||
type CDCCSInterfaceDescriptor struct {
|
|
||||||
len uint8 // 5
|
|
||||||
dtype uint8 // 0x24
|
|
||||||
subtype uint8
|
|
||||||
d0 uint8
|
|
||||||
d1 uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCDCCSInterfaceDescriptor returns a new USB CDCCSInterfaceDescriptor.
|
|
||||||
func NewCDCCSInterfaceDescriptor(subtype, d0, d1 uint8) CDCCSInterfaceDescriptor {
|
|
||||||
return CDCCSInterfaceDescriptor{cdcCSInterfaceDescriptorSize, 0x24, subtype, d0, d1}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns CDCCSInterfaceDescriptor data.
|
|
||||||
func (d CDCCSInterfaceDescriptor) Bytes() [cdcCSInterfaceDescriptorSize]byte {
|
|
||||||
var b [cdcCSInterfaceDescriptorSize]byte
|
|
||||||
b[0] = byte(d.len)
|
|
||||||
b[1] = byte(d.dtype)
|
|
||||||
b[2] = byte(d.subtype)
|
|
||||||
b[3] = byte(d.d0)
|
|
||||||
b[4] = byte(d.d1)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const cmFunctionalDescriptorSize = 5
|
|
||||||
|
|
||||||
// CMFunctionalDescriptor is the functional descriptor general format.
|
|
||||||
type CMFunctionalDescriptor struct {
|
|
||||||
bFunctionLength uint8
|
|
||||||
bDescriptorType uint8 // 0x24
|
|
||||||
bDescriptorSubtype uint8 // 1
|
|
||||||
bmCapabilities uint8
|
|
||||||
bDataInterface uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCMFunctionalDescriptor returns a new USB CMFunctionalDescriptor.
|
|
||||||
func NewCMFunctionalDescriptor(subtype, d0, d1 uint8) CMFunctionalDescriptor {
|
|
||||||
return CMFunctionalDescriptor{5, 0x24, subtype, d0, d1}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns the CMFunctionalDescriptor data.
|
|
||||||
func (d CMFunctionalDescriptor) Bytes() [cmFunctionalDescriptorSize]byte {
|
|
||||||
var b [cmFunctionalDescriptorSize]byte
|
|
||||||
b[0] = byte(d.bFunctionLength)
|
|
||||||
b[1] = byte(d.bDescriptorType)
|
|
||||||
b[2] = byte(d.bDescriptorSubtype)
|
|
||||||
b[3] = byte(d.bmCapabilities)
|
|
||||||
b[4] = byte(d.bDescriptorSubtype)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
const acmFunctionalDescriptorSize = 4
|
|
||||||
|
|
||||||
// ACMFunctionalDescriptor is a Abstract Control Model (ACM) USB descriptor.
|
|
||||||
type ACMFunctionalDescriptor struct {
|
|
||||||
len uint8
|
|
||||||
dtype uint8 // 0x24
|
|
||||||
subtype uint8 // 1
|
|
||||||
bmCapabilities uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewACMFunctionalDescriptor returns a new USB ACMFunctionalDescriptor.
|
|
||||||
func NewACMFunctionalDescriptor(subtype, d0 uint8) ACMFunctionalDescriptor {
|
|
||||||
return ACMFunctionalDescriptor{4, 0x24, subtype, d0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bytes returns the ACMFunctionalDescriptor data.
|
|
||||||
func (d ACMFunctionalDescriptor) Bytes() [acmFunctionalDescriptorSize]byte {
|
|
||||||
var b [acmFunctionalDescriptorSize]byte
|
|
||||||
b[0] = byte(d.len)
|
|
||||||
b[1] = byte(d.dtype)
|
|
||||||
b[2] = byte(d.subtype)
|
|
||||||
b[3] = byte(d.bmCapabilities)
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// CDCDescriptor is the Communication Device Class (CDC) descriptor.
|
|
||||||
type CDCDescriptor struct {
|
|
||||||
// IAD
|
|
||||||
iad IADDescriptor // Only needed on compound device
|
|
||||||
|
|
||||||
// Control
|
|
||||||
cif InterfaceDescriptor
|
|
||||||
header CDCCSInterfaceDescriptor
|
|
||||||
|
|
||||||
// CDC control
|
|
||||||
controlManagement ACMFunctionalDescriptor // ACM
|
|
||||||
functionalDescriptor CDCCSInterfaceDescriptor // CDC_UNION
|
|
||||||
callManagement CMFunctionalDescriptor // Call Management
|
|
||||||
cifin EndpointDescriptor
|
|
||||||
|
|
||||||
// CDC Data
|
|
||||||
dif InterfaceDescriptor
|
|
||||||
in EndpointDescriptor
|
|
||||||
out EndpointDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCDCDescriptor(i IADDescriptor, c InterfaceDescriptor,
|
|
||||||
h CDCCSInterfaceDescriptor,
|
|
||||||
cm ACMFunctionalDescriptor,
|
|
||||||
fd CDCCSInterfaceDescriptor,
|
|
||||||
callm CMFunctionalDescriptor,
|
|
||||||
ci EndpointDescriptor,
|
|
||||||
di InterfaceDescriptor,
|
|
||||||
outp EndpointDescriptor,
|
|
||||||
inp EndpointDescriptor) CDCDescriptor {
|
|
||||||
return CDCDescriptor{iad: i,
|
|
||||||
cif: c,
|
|
||||||
header: h,
|
|
||||||
controlManagement: cm,
|
|
||||||
functionalDescriptor: fd,
|
|
||||||
callManagement: callm,
|
|
||||||
cifin: ci,
|
|
||||||
dif: di,
|
|
||||||
in: inp,
|
|
||||||
out: outp}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cdcSize = iadDescriptorSize +
|
|
||||||
interfaceDescriptorSize +
|
|
||||||
cdcCSInterfaceDescriptorSize +
|
|
||||||
acmFunctionalDescriptorSize +
|
|
||||||
cdcCSInterfaceDescriptorSize +
|
|
||||||
cmFunctionalDescriptorSize +
|
|
||||||
endpointDescriptorSize +
|
|
||||||
interfaceDescriptorSize +
|
|
||||||
endpointDescriptorSize +
|
|
||||||
endpointDescriptorSize
|
|
||||||
|
|
||||||
// Bytes returns CDCDescriptor data.
|
|
||||||
func (d CDCDescriptor) Bytes() [cdcSize]byte {
|
|
||||||
var b [cdcSize]byte
|
|
||||||
offset := 0
|
|
||||||
|
|
||||||
iad := d.iad.Bytes()
|
|
||||||
copy(b[offset:], iad[:])
|
|
||||||
offset += len(iad)
|
|
||||||
|
|
||||||
cif := d.cif.Bytes()
|
|
||||||
copy(b[offset:], cif[:])
|
|
||||||
offset += len(cif)
|
|
||||||
|
|
||||||
header := d.header.Bytes()
|
|
||||||
copy(b[offset:], header[:])
|
|
||||||
offset += len(header)
|
|
||||||
|
|
||||||
controlManagement := d.controlManagement.Bytes()
|
|
||||||
copy(b[offset:], controlManagement[:])
|
|
||||||
offset += len(controlManagement)
|
|
||||||
|
|
||||||
functionalDescriptor := d.functionalDescriptor.Bytes()
|
|
||||||
copy(b[offset:], functionalDescriptor[:])
|
|
||||||
offset += len(functionalDescriptor)
|
|
||||||
|
|
||||||
callManagement := d.callManagement.Bytes()
|
|
||||||
copy(b[offset:], callManagement[:])
|
|
||||||
offset += len(callManagement)
|
|
||||||
|
|
||||||
cifin := d.cifin.Bytes()
|
|
||||||
copy(b[offset:], cifin[:])
|
|
||||||
offset += len(cifin)
|
|
||||||
|
|
||||||
dif := d.dif.Bytes()
|
|
||||||
copy(b[offset:], dif[:])
|
|
||||||
offset += len(dif)
|
|
||||||
|
|
||||||
out := d.out.Bytes()
|
|
||||||
copy(b[offset:], out[:])
|
|
||||||
offset += len(out)
|
|
||||||
|
|
||||||
in := d.in.Bytes()
|
|
||||||
copy(b[offset:], in[:])
|
|
||||||
offset += len(in)
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// MSCDescriptor is not used yet.
|
|
||||||
type MSCDescriptor struct {
|
|
||||||
msc InterfaceDescriptor
|
|
||||||
in EndpointDescriptor
|
|
||||||
out EndpointDescriptor
|
|
||||||
}
|
|
||||||
|
|
||||||
const cdcLineInfoSize = 7
|
const cdcLineInfoSize = 7
|
||||||
|
|
||||||
type cdcLineInfo struct {
|
type cdcLineInfo struct {
|
||||||
|
@ -455,6 +64,8 @@ const (
|
||||||
usb_ENDPOINT_DESCRIPTOR_TYPE = 5
|
usb_ENDPOINT_DESCRIPTOR_TYPE = 5
|
||||||
usb_DEVICE_QUALIFIER = 6
|
usb_DEVICE_QUALIFIER = 6
|
||||||
usb_OTHER_SPEED_CONFIGURATION = 7
|
usb_OTHER_SPEED_CONFIGURATION = 7
|
||||||
|
usb_SET_REPORT_TYPE = 33
|
||||||
|
usb_HID_REPORT_TYPE = 34
|
||||||
|
|
||||||
usbEndpointOut = 0x00
|
usbEndpointOut = 0x00
|
||||||
usbEndpointIn = 0x80
|
usbEndpointIn = 0x80
|
||||||
|
@ -474,6 +85,9 @@ const (
|
||||||
usb_GET_INTERFACE = 10
|
usb_GET_INTERFACE = 10
|
||||||
usb_SET_INTERFACE = 11
|
usb_SET_INTERFACE = 11
|
||||||
|
|
||||||
|
// non standard requests
|
||||||
|
usb_SET_IDLE = 10
|
||||||
|
|
||||||
usb_DEVICE_CLASS_COMMUNICATIONS = 0x02
|
usb_DEVICE_CLASS_COMMUNICATIONS = 0x02
|
||||||
usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03
|
usb_DEVICE_CLASS_HUMAN_INTERFACE = 0x03
|
||||||
usb_DEVICE_CLASS_STORAGE = 0x08
|
usb_DEVICE_CLASS_STORAGE = 0x08
|
||||||
|
@ -488,9 +102,12 @@ const (
|
||||||
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
|
usb_CDC_ACM_INTERFACE = 0 // CDC ACM
|
||||||
usb_CDC_DATA_INTERFACE = 1 // CDC Data
|
usb_CDC_DATA_INTERFACE = 1 // CDC Data
|
||||||
usb_CDC_FIRST_ENDPOINT = 1
|
usb_CDC_FIRST_ENDPOINT = 1
|
||||||
|
|
||||||
|
// Endpoint
|
||||||
usb_CDC_ENDPOINT_ACM = 1
|
usb_CDC_ENDPOINT_ACM = 1
|
||||||
usb_CDC_ENDPOINT_OUT = 2
|
usb_CDC_ENDPOINT_OUT = 2
|
||||||
usb_CDC_ENDPOINT_IN = 3
|
usb_CDC_ENDPOINT_IN = 3
|
||||||
|
usb_HID_ENDPOINT_IN = 4
|
||||||
|
|
||||||
// bmRequestType
|
// bmRequestType
|
||||||
usb_REQUEST_HOSTTODEVICE = 0x00
|
usb_REQUEST_HOSTTODEVICE = 0x00
|
||||||
|
@ -661,40 +278,43 @@ func (usbcdc *USBCDC) Receive(data byte) {
|
||||||
func sendDescriptor(setup usbSetup) {
|
func sendDescriptor(setup usbSetup) {
|
||||||
switch setup.wValueH {
|
switch setup.wValueH {
|
||||||
case usb_CONFIGURATION_DESCRIPTOR_TYPE:
|
case usb_CONFIGURATION_DESCRIPTOR_TYPE:
|
||||||
sendConfiguration(setup)
|
sendUSBPacket(0, usbDescriptor.Configuration, setup.wLength)
|
||||||
return
|
return
|
||||||
case usb_DEVICE_DESCRIPTOR_TYPE:
|
case usb_DEVICE_DESCRIPTOR_TYPE:
|
||||||
// composite descriptor
|
// composite descriptor
|
||||||
dd := NewDeviceDescriptor(0xef, 0x02, 0x01, 64, usb_VID, usb_PID, 0x100, usb_IMANUFACTURER, usb_IPRODUCT, usb_ISERIAL, 1)
|
usbDescriptor.Configure(usb_VID, usb_PID)
|
||||||
l := deviceDescriptorSize
|
sendUSBPacket(0, usbDescriptor.Device, setup.wLength)
|
||||||
if setup.wLength < deviceDescriptorSize {
|
|
||||||
l = int(setup.wLength)
|
|
||||||
}
|
|
||||||
buf := dd.Bytes()
|
|
||||||
sendUSBPacket(0, buf[:l])
|
|
||||||
return
|
return
|
||||||
|
|
||||||
case usb_STRING_DESCRIPTOR_TYPE:
|
case usb_STRING_DESCRIPTOR_TYPE:
|
||||||
switch setup.wValueL {
|
switch setup.wValueL {
|
||||||
case 0:
|
case 0:
|
||||||
b := []byte{0x04, 0x03, 0x09, 0x04}
|
b := []byte{0x04, 0x03, 0x09, 0x04}
|
||||||
sendUSBPacket(0, b)
|
sendUSBPacket(0, b, setup.wLength)
|
||||||
|
|
||||||
case usb_IPRODUCT:
|
case usb_IPRODUCT:
|
||||||
b := make([]byte, (len(usb_STRING_PRODUCT)<<1)+2)
|
b := make([]byte, (len(usb_STRING_PRODUCT)<<1)+2)
|
||||||
strToUTF16LEDescriptor(usb_STRING_PRODUCT, b)
|
strToUTF16LEDescriptor(usb_STRING_PRODUCT, b)
|
||||||
sendUSBPacket(0, b)
|
sendUSBPacket(0, b, setup.wLength)
|
||||||
|
|
||||||
case usb_IMANUFACTURER:
|
case usb_IMANUFACTURER:
|
||||||
b := make([]byte, (len(usb_STRING_MANUFACTURER)<<1)+2)
|
b := make([]byte, (len(usb_STRING_MANUFACTURER)<<1)+2)
|
||||||
strToUTF16LEDescriptor(usb_STRING_MANUFACTURER, b)
|
strToUTF16LEDescriptor(usb_STRING_MANUFACTURER, b)
|
||||||
sendUSBPacket(0, b)
|
sendUSBPacket(0, b, setup.wLength)
|
||||||
|
|
||||||
case usb_ISERIAL:
|
case usb_ISERIAL:
|
||||||
// TODO: allow returning a product serial number
|
// TODO: allow returning a product serial number
|
||||||
sendZlp()
|
sendZlp()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
case usb_HID_REPORT_TYPE:
|
||||||
|
if h, ok := usbDescriptor.HID[setup.wIndex]; ok {
|
||||||
|
sendUSBPacket(0, h, setup.wLength)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case usb_DEVICE_QUALIFIER:
|
||||||
|
// skip
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
// do not know how to handle this message, so return zero
|
// do not know how to handle this message, so return zero
|
||||||
|
@ -702,54 +322,17 @@ func sendDescriptor(setup usbSetup) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendConfiguration creates and sends the configuration packet to the host.
|
// EnableHID enables HID. This function must be executed from the init().
|
||||||
func sendConfiguration(setup usbSetup) {
|
func EnableHID(callback func()) {
|
||||||
if setup.wLength == 9 {
|
usbDescriptor = descriptorCDCHID
|
||||||
sz := uint16(configDescriptorSize + cdcSize)
|
endPoints = []uint32{usb_ENDPOINT_TYPE_CONTROL,
|
||||||
config := NewConfigDescriptor(sz, 2)
|
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn),
|
||||||
configBuf := config.Bytes()
|
(usb_ENDPOINT_TYPE_BULK | usbEndpointOut),
|
||||||
sendUSBPacket(0, configBuf[:])
|
(usb_ENDPOINT_TYPE_BULK | usbEndpointIn),
|
||||||
} else {
|
(usb_ENDPOINT_TYPE_INTERRUPT | usbEndpointIn)}
|
||||||
iad := NewIADDescriptor(0, 2, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
|
|
||||||
|
|
||||||
cif := NewInterfaceDescriptor(usb_CDC_ACM_INTERFACE, 1, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
|
hidCallback = callback
|
||||||
|
|
||||||
header := NewCDCCSInterfaceDescriptor(usb_CDC_HEADER, usb_CDC_V1_10&0xFF, (usb_CDC_V1_10>>8)&0x0FF)
|
|
||||||
|
|
||||||
controlManagement := NewACMFunctionalDescriptor(usb_CDC_ABSTRACT_CONTROL_MANAGEMENT, 6)
|
|
||||||
|
|
||||||
functionalDescriptor := NewCDCCSInterfaceDescriptor(usb_CDC_UNION, usb_CDC_ACM_INTERFACE, usb_CDC_DATA_INTERFACE)
|
|
||||||
|
|
||||||
callManagement := NewCMFunctionalDescriptor(usb_CDC_CALL_MANAGEMENT, 1, 1)
|
|
||||||
|
|
||||||
cifin := NewEndpointDescriptor((usb_CDC_ENDPOINT_ACM | usbEndpointIn), usb_ENDPOINT_TYPE_INTERRUPT, 0x10, 0x10)
|
|
||||||
|
|
||||||
dif := NewInterfaceDescriptor(usb_CDC_DATA_INTERFACE, 2, usb_CDC_DATA_INTERFACE_CLASS, 0, 0)
|
|
||||||
|
|
||||||
out := NewEndpointDescriptor((usb_CDC_ENDPOINT_OUT | usbEndpointOut), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0)
|
|
||||||
|
|
||||||
in := NewEndpointDescriptor((usb_CDC_ENDPOINT_IN | usbEndpointIn), usb_ENDPOINT_TYPE_BULK, usbEndpointPacketSize, 0)
|
|
||||||
|
|
||||||
cdc := NewCDCDescriptor(iad,
|
|
||||||
cif,
|
|
||||||
header,
|
|
||||||
controlManagement,
|
|
||||||
functionalDescriptor,
|
|
||||||
callManagement,
|
|
||||||
cifin,
|
|
||||||
dif,
|
|
||||||
out,
|
|
||||||
in)
|
|
||||||
|
|
||||||
sz := uint16(configDescriptorSize + cdcSize)
|
|
||||||
config := NewConfigDescriptor(sz, 2)
|
|
||||||
|
|
||||||
configBuf := config.Bytes()
|
|
||||||
cdcBuf := cdc.Bytes()
|
|
||||||
var buf [configDescriptorSize + cdcSize]byte
|
|
||||||
copy(buf[0:], configBuf[:])
|
|
||||||
copy(buf[configDescriptorSize:], cdcBuf[:])
|
|
||||||
|
|
||||||
sendUSBPacket(0, buf[:])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hidCallback is a variable that holds the callback when using HID.
|
||||||
|
var hidCallback func()
|
||||||
|
|
52
src/machine/usb/hid/buffer.go
Обычный файл
52
src/machine/usb/hid/buffer.go
Обычный файл
|
@ -0,0 +1,52 @@
|
||||||
|
package hid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime/volatile"
|
||||||
|
)
|
||||||
|
|
||||||
|
const bufferSize = 128
|
||||||
|
|
||||||
|
// RingBuffer is ring buffer implementation inspired by post at
|
||||||
|
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
|
||||||
|
type RingBuffer struct {
|
||||||
|
rxbuffer [bufferSize][9]byte
|
||||||
|
head volatile.Register8
|
||||||
|
tail volatile.Register8
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRingBuffer returns a new ring buffer.
|
||||||
|
func NewRingBuffer() *RingBuffer {
|
||||||
|
return &RingBuffer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used returns how many bytes in buffer have been used.
|
||||||
|
func (rb *RingBuffer) Used() uint8 {
|
||||||
|
return uint8(rb.head.Get() - rb.tail.Get())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put stores a byte in the buffer. If the buffer is already
|
||||||
|
// full, the method will return false.
|
||||||
|
func (rb *RingBuffer) Put(val []byte) bool {
|
||||||
|
if rb.Used() != bufferSize {
|
||||||
|
rb.head.Set(rb.head.Get() + 1)
|
||||||
|
copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a byte from the buffer. If the buffer is empty,
|
||||||
|
// the method will return a false as the second value.
|
||||||
|
func (rb *RingBuffer) Get() ([]byte, bool) {
|
||||||
|
if rb.Used() != 0 {
|
||||||
|
rb.tail.Set(rb.tail.Get() + 1)
|
||||||
|
return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear resets the head and tail pointer to zero.
|
||||||
|
func (rb *RingBuffer) Clear() {
|
||||||
|
rb.head.Set(0)
|
||||||
|
rb.tail.Set(0)
|
||||||
|
}
|
51
src/machine/usb/hid/hid.go
Обычный файл
51
src/machine/usb/hid/hid.go
Обычный файл
|
@ -0,0 +1,51 @@
|
||||||
|
package hid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"machine"
|
||||||
|
)
|
||||||
|
|
||||||
|
// from usb-hid.go
|
||||||
|
var (
|
||||||
|
ErrHIDInvalidPort = errors.New("invalid USB port")
|
||||||
|
ErrHIDInvalidCore = errors.New("invalid USB core")
|
||||||
|
ErrHIDReportTransfer = errors.New("failed to transfer HID report")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hidEndpoint = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
type hidDevicer interface {
|
||||||
|
Callback() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var devices [5]hidDevicer
|
||||||
|
var size int
|
||||||
|
|
||||||
|
// SetCallbackHandler sets the callback. Only the first time it is called, it
|
||||||
|
// calls machine.EnableHID for USB configuration
|
||||||
|
func SetCallbackHandler(d hidDevicer) {
|
||||||
|
if size == 0 {
|
||||||
|
machine.EnableHID(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
devices[size] = d
|
||||||
|
size++
|
||||||
|
}
|
||||||
|
|
||||||
|
func callback() {
|
||||||
|
for _, d := range devices {
|
||||||
|
if d == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if done := d.Callback(); done {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendUSBPacket sends a HIDPacket.
|
||||||
|
func SendUSBPacket(b []byte) {
|
||||||
|
machine.SendUSBHIDPacket(hidEndpoint, b)
|
||||||
|
}
|
478
src/machine/usb/hid/keyboard/keyboard.go
Обычный файл
478
src/machine/usb/hid/keyboard/keyboard.go
Обычный файл
|
@ -0,0 +1,478 @@
|
||||||
|
package keyboard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"machine/usb/hid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// from usb-hid-keyboard.go
|
||||||
|
var (
|
||||||
|
ErrInvalidCodepoint = errors.New("invalid Unicode codepoint")
|
||||||
|
ErrInvalidKeycode = errors.New("invalid keyboard keycode")
|
||||||
|
ErrInvalidUTF8 = errors.New("invalid UTF-8 encoding")
|
||||||
|
ErrKeypressMaximum = errors.New("maximum keypresses exceeded")
|
||||||
|
)
|
||||||
|
|
||||||
|
var Keyboard *keyboard
|
||||||
|
|
||||||
|
// Keyboard represents a USB HID keyboard device with support for international
|
||||||
|
// layouts and various control, system, multimedia, and consumer keycodes.
|
||||||
|
//
|
||||||
|
// Keyboard implements the io.Writer interface that translates UTF-8 encoded
|
||||||
|
// byte strings into sequences of keypress events.
|
||||||
|
type keyboard struct {
|
||||||
|
// led holds the current state of all keyboard LEDs:
|
||||||
|
// 1=NumLock 2=CapsLock 4=ScrollLock 8=Compose 16=Kana
|
||||||
|
led uint8
|
||||||
|
|
||||||
|
// mod holds the current state of all keyboard modifier keys:
|
||||||
|
// 1=LeftCtrl 2=LeftShift 4=LeftAlt 8=LeftGUI
|
||||||
|
// 16=RightCtrl 32=RightShift 64=RightAlt 128=RightGUI
|
||||||
|
mod uint8
|
||||||
|
|
||||||
|
// key holds a list of all keyboard keys currently pressed.
|
||||||
|
key [hidKeyboardKeyCount]uint8
|
||||||
|
con [hidKeyboardConCount]uint16
|
||||||
|
sys [hidKeyboardSysCount]uint8
|
||||||
|
|
||||||
|
// decode holds the current state of the UTF-8 decoder.
|
||||||
|
decode decodeState
|
||||||
|
|
||||||
|
// wideChar holds high bits for the UTF-8 decoder.
|
||||||
|
wideChar uint16
|
||||||
|
|
||||||
|
buf *hid.RingBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
// decodeState represents a state in the UTF-8 decode state machine.
|
||||||
|
type decodeState uint8
|
||||||
|
|
||||||
|
// Constant enumerated values of type decodeState.
|
||||||
|
const (
|
||||||
|
decodeReset decodeState = iota
|
||||||
|
decodeByte1
|
||||||
|
decodeByte2
|
||||||
|
decodeByte3
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if Keyboard == nil {
|
||||||
|
Keyboard = newKeyboard()
|
||||||
|
hid.SetCallbackHandler(Keyboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns hid-keybord.
|
||||||
|
func New() *keyboard {
|
||||||
|
return Keyboard
|
||||||
|
}
|
||||||
|
|
||||||
|
func newKeyboard() *keyboard {
|
||||||
|
return &keyboard{
|
||||||
|
buf: hid.NewRingBuffer(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) Callback() bool {
|
||||||
|
if b, ok := kb.buf.Get(); ok {
|
||||||
|
hid.SendUSBPacket(b)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) ready() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write transmits press-and-release key sequences for each Keycode translated
|
||||||
|
// from the given UTF-8 byte string. Write implements the io.Writer interface
|
||||||
|
// and conforms to all documented conventions for arguments and return values.
|
||||||
|
func (kb *keyboard) Write(b []byte) (n int, err error) {
|
||||||
|
for _, c := range b {
|
||||||
|
if err = kb.WriteByte(c); nil != err {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
n += 1
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteByte processes a single byte from a UTF-8 byte string. This method is a
|
||||||
|
// stateful method with respect to the receiver Keyboard, meaning that its exact
|
||||||
|
// behavior will depend on the current state of its UTF-8 decode state machine:
|
||||||
|
//
|
||||||
|
// (a) If the given byte is a valid ASCII encoding (0-127), then a keypress
|
||||||
|
// sequence is immediately transmitted for the respective Keycode.
|
||||||
|
//
|
||||||
|
// (b) If the given byte represents the final byte in a multi-byte codepoint,
|
||||||
|
// then a keypress sequence is immediately transmitted by translating the
|
||||||
|
// multi-byte codepoint to its respective Keycode.
|
||||||
|
//
|
||||||
|
// (c) If the given byte appears to represent high bits for a multi-byte
|
||||||
|
// codepoint, then the bits are copied to the receiver's internal state
|
||||||
|
// machine buffer for use by a subsequent call to WriteByte() (or Write())
|
||||||
|
// that completes the codepoint.
|
||||||
|
//
|
||||||
|
// (d) If the given byte is out of range, or contains illegal bits for the
|
||||||
|
// current state of the UTF-8 decoder, then the UTF-8 decode state machine
|
||||||
|
// is reset to its initial state.
|
||||||
|
//
|
||||||
|
// In cases (c) and (d), a keypress sequence is not generated and no data is
|
||||||
|
// transmitted. In case (c), additional bytes must be received via WriteByte()
|
||||||
|
// (or Write()) to complete or discard the current codepoint.
|
||||||
|
func (kb *keyboard) WriteByte(b byte) error {
|
||||||
|
switch {
|
||||||
|
case b < 0x80:
|
||||||
|
// 1-byte encoding (0x00-0x7F)
|
||||||
|
kb.decode = decodeByte1
|
||||||
|
return kb.write(uint16(b))
|
||||||
|
|
||||||
|
case b < 0xC0:
|
||||||
|
// 2nd, 3rd, or 4th byte (0x80-0xBF)
|
||||||
|
b = Keycode(b).key()
|
||||||
|
switch kb.decode {
|
||||||
|
case decodeByte2:
|
||||||
|
kb.decode = decodeByte1
|
||||||
|
return kb.write(kb.wideChar | uint16(b))
|
||||||
|
case decodeByte3:
|
||||||
|
kb.decode = decodeByte2
|
||||||
|
kb.wideChar |= uint16(b) << 6
|
||||||
|
}
|
||||||
|
|
||||||
|
case b < 0xE0:
|
||||||
|
// 2-byte encoding (0xC2-0xDF), or illegal byte 2 (0xC0-0xC1)
|
||||||
|
kb.decode = decodeByte2
|
||||||
|
kb.wideChar = uint16(b&0x1F) << 6
|
||||||
|
|
||||||
|
case b < 0xF0:
|
||||||
|
// 3-byte encoding (0xE0-0xEF)
|
||||||
|
kb.decode = decodeByte3
|
||||||
|
kb.wideChar = uint16(b&0x0F) << 12
|
||||||
|
|
||||||
|
default:
|
||||||
|
// 4-byte encoding unsupported (0xF0-0xF4), or illegal byte 4 (0xF5-0xFF)
|
||||||
|
kb.decode = decodeReset
|
||||||
|
return ErrInvalidUTF8
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) write(p uint16) error {
|
||||||
|
c := keycode(p)
|
||||||
|
if 0 == c {
|
||||||
|
return ErrInvalidCodepoint
|
||||||
|
}
|
||||||
|
if d := deadkey(c); 0 != d {
|
||||||
|
if err := kb.writeKeycode(d); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kb.writeKeycode(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) writeKeycode(c Keycode) error {
|
||||||
|
var b [9]byte
|
||||||
|
b[0] = 0x02
|
||||||
|
b[1] = c.mod()
|
||||||
|
b[2] = 0
|
||||||
|
b[3] = c.key()
|
||||||
|
b[4] = 0
|
||||||
|
b[5] = 0
|
||||||
|
b[6] = 0
|
||||||
|
b[7] = 0
|
||||||
|
b[8] = 0
|
||||||
|
if !kb.sendKey(false, b[:]) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
|
||||||
|
b[1] = 0
|
||||||
|
b[3] = 0
|
||||||
|
if !kb.sendKey(false, b[:]) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Press transmits a press-and-release sequence for the given Keycode, which
|
||||||
|
// simulates a discrete keypress event.
|
||||||
|
//
|
||||||
|
// The following values of Keycode are supported:
|
||||||
|
//
|
||||||
|
// 0x0020 - 0x007F ASCII (U+0020 to U+007F) [USES LAYOUT]
|
||||||
|
// 0x0080 - 0xC1FF Unicode (U+0080 to U+C1FF) [USES LAYOUT]
|
||||||
|
// 0xC200 - 0xDFFF UTF-8 packed (U+0080 to U+07FF) [USES LAYOUT]
|
||||||
|
// 0xE000 - 0xE0FF Modifier key (bitmap, 8 keys, Shift/Ctrl/Alt/GUI)
|
||||||
|
// 0xE200 - 0xE2FF System key (HID usage code, page 1)
|
||||||
|
// 0xE400 - 0xE7FF Media/Consumer key (HID usage code, page 12)
|
||||||
|
// 0xF000 - 0xFFFF Normal key (HID usage code, page 7)
|
||||||
|
func (kb *keyboard) Press(c Keycode) error {
|
||||||
|
if err := kb.Down(c); nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return kb.Up(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) sendKey(consumer bool, b []byte) bool {
|
||||||
|
kb.buf.Put(b)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) keyboardSendKeys(consumer bool) bool {
|
||||||
|
var b [9]byte
|
||||||
|
b[0] = 0x02
|
||||||
|
b[1] = kb.mod
|
||||||
|
b[2] = 0x02
|
||||||
|
b[3] = kb.key[0]
|
||||||
|
b[4] = kb.key[1]
|
||||||
|
b[5] = kb.key[2]
|
||||||
|
b[6] = kb.key[3]
|
||||||
|
b[7] = kb.key[4]
|
||||||
|
b[8] = kb.key[5]
|
||||||
|
return kb.sendKey(consumer, b[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Down transmits a key-down event for the given Keycode.
|
||||||
|
//
|
||||||
|
// The host will interpret the key as being held down continuously until a
|
||||||
|
// corresponding key-up event is transmitted, e.g., via method Up().
|
||||||
|
//
|
||||||
|
// See godoc comment on method Press() for details on what input is accepted and
|
||||||
|
// how it is interpreted.
|
||||||
|
func (kb *keyboard) Down(c Keycode) error {
|
||||||
|
var res uint8
|
||||||
|
msb := c >> 8
|
||||||
|
if msb >= 0xC2 {
|
||||||
|
if msb < 0xE0 {
|
||||||
|
c = ((msb & 0x1F) << 6) | Keycode(c.key())
|
||||||
|
} else {
|
||||||
|
switch msb {
|
||||||
|
case 0xF0:
|
||||||
|
return kb.down(uint8(c), 0)
|
||||||
|
|
||||||
|
case 0xE0:
|
||||||
|
return kb.down(0, uint8(c))
|
||||||
|
|
||||||
|
case 0xE2:
|
||||||
|
return kb.downSys(uint8(c))
|
||||||
|
|
||||||
|
default:
|
||||||
|
if 0xE4 <= msb && msb <= 0xE7 {
|
||||||
|
return kb.downCon(uint16(c & 0x03FF))
|
||||||
|
}
|
||||||
|
return ErrInvalidKeycode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = keycode(uint16(c))
|
||||||
|
if 0 == c {
|
||||||
|
return ErrInvalidCodepoint
|
||||||
|
}
|
||||||
|
if d := deadkey(c); 0 != d {
|
||||||
|
res = kb.mod
|
||||||
|
if 0 != res {
|
||||||
|
kb.mod = 0
|
||||||
|
kb.keyboardSendKeys(false)
|
||||||
|
}
|
||||||
|
kb.down(d.key(), d.mod())
|
||||||
|
kb.up(d.key(), d.mod())
|
||||||
|
}
|
||||||
|
return kb.down(c.key(), c.mod()|res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) down(key uint8, mod uint8) error {
|
||||||
|
send := false
|
||||||
|
if 0 != mod {
|
||||||
|
if kb.mod&mod != mod {
|
||||||
|
kb.mod |= mod
|
||||||
|
send = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if 0 != key {
|
||||||
|
for _, k := range kb.key {
|
||||||
|
if k == key {
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, k := range kb.key {
|
||||||
|
if 0 == k {
|
||||||
|
kb.key[i] = key
|
||||||
|
send = true
|
||||||
|
goto end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrKeypressMaximum
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
if send {
|
||||||
|
if !kb.keyboardSendKeys(false) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) downCon(key uint16) error {
|
||||||
|
if 0 == key {
|
||||||
|
return ErrInvalidKeycode
|
||||||
|
}
|
||||||
|
for _, k := range kb.con {
|
||||||
|
if key == k {
|
||||||
|
return nil // already pressed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, k := range kb.con {
|
||||||
|
if 0 == k {
|
||||||
|
kb.con[i] = key
|
||||||
|
if !kb.keyboardSendKeys(true) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrKeypressMaximum
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) downSys(key uint8) error {
|
||||||
|
if 0 == key {
|
||||||
|
return ErrInvalidKeycode
|
||||||
|
}
|
||||||
|
for _, k := range kb.sys {
|
||||||
|
if key == k {
|
||||||
|
return nil // already pressed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i, k := range kb.sys {
|
||||||
|
if 0 == k {
|
||||||
|
kb.sys[i] = key
|
||||||
|
if !kb.keyboardSendKeys(true) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrKeypressMaximum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Up transmits a key-up event for the given Keycode.
|
||||||
|
//
|
||||||
|
// See godoc comment on method Press() for details on what input is accepted and
|
||||||
|
// how it is interpreted.
|
||||||
|
func (kb *keyboard) Up(c Keycode) error {
|
||||||
|
msb := c >> 8
|
||||||
|
if msb >= 0xC2 {
|
||||||
|
if msb < 0xE0 {
|
||||||
|
c = ((msb & 0x1F) << 6) | Keycode(c.key())
|
||||||
|
} else {
|
||||||
|
switch msb {
|
||||||
|
case 0xF0:
|
||||||
|
return kb.up(uint8(c), 0)
|
||||||
|
|
||||||
|
case 0xE0:
|
||||||
|
return kb.up(0, uint8(c))
|
||||||
|
|
||||||
|
case 0xE2:
|
||||||
|
return kb.upSys(uint8(c))
|
||||||
|
|
||||||
|
default:
|
||||||
|
if 0xE4 <= msb && msb <= 0xE7 {
|
||||||
|
return kb.upCon(uint16(c & 0x03FF))
|
||||||
|
}
|
||||||
|
return ErrInvalidKeycode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = keycode(uint16(c))
|
||||||
|
if 0 == c {
|
||||||
|
return ErrInvalidCodepoint
|
||||||
|
}
|
||||||
|
return kb.up(c.key(), c.mod())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release transmits a key-up event for all keyboard keys currently pressed as
|
||||||
|
// if the user removed his/her hands from the keyboard entirely.
|
||||||
|
func (kb *keyboard) Release() error {
|
||||||
|
|
||||||
|
bits := uint16(kb.mod)
|
||||||
|
kb.mod = 0
|
||||||
|
for i, k := range kb.key {
|
||||||
|
bits |= uint16(k)
|
||||||
|
kb.key[i] = 0
|
||||||
|
}
|
||||||
|
if 0 != bits {
|
||||||
|
if !kb.keyboardSendKeys(false) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bits = 0
|
||||||
|
for i, k := range kb.con {
|
||||||
|
bits |= k
|
||||||
|
kb.con[i] = 0
|
||||||
|
}
|
||||||
|
for i, k := range kb.sys {
|
||||||
|
bits |= uint16(k)
|
||||||
|
kb.sys[i] = 0
|
||||||
|
}
|
||||||
|
if 0 != bits {
|
||||||
|
if !kb.keyboardSendKeys(true) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) up(key uint8, mod uint8) error {
|
||||||
|
send := false
|
||||||
|
if 0 != mod {
|
||||||
|
if kb.mod&mod != 0 {
|
||||||
|
kb.mod &^= mod
|
||||||
|
send = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if 0 != key {
|
||||||
|
for i, k := range kb.key {
|
||||||
|
if key == k {
|
||||||
|
kb.key[i] = 0
|
||||||
|
send = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if send {
|
||||||
|
if !kb.keyboardSendKeys(false) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) upCon(key uint16) error {
|
||||||
|
if 0 == key {
|
||||||
|
return ErrInvalidKeycode
|
||||||
|
}
|
||||||
|
for i, k := range kb.con {
|
||||||
|
if key == k {
|
||||||
|
kb.con[i] = 0
|
||||||
|
if !kb.keyboardSendKeys(true) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) upSys(key uint8) error {
|
||||||
|
if 0 == key {
|
||||||
|
return ErrInvalidKeycode
|
||||||
|
}
|
||||||
|
for i, k := range kb.sys {
|
||||||
|
if key == k {
|
||||||
|
kb.sys[i] = 0
|
||||||
|
if !kb.keyboardSendKeys(true) {
|
||||||
|
return hid.ErrHIDReportTransfer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
532
src/machine/usb/hid/keyboard/keycode.go
Обычный файл
532
src/machine/usb/hid/keyboard/keycode.go
Обычный файл
|
@ -0,0 +1,532 @@
|
||||||
|
package keyboard
|
||||||
|
|
||||||
|
// Keycode is a package-defined bitmap used to encode the value of a given key.
|
||||||
|
type Keycode uint16
|
||||||
|
|
||||||
|
// keycode returns the given Unicode codepoint translated to a Keycode sequence.
|
||||||
|
// Unicode codepoints greater than U+FFFF are unsupported.
|
||||||
|
//go:inline
|
||||||
|
func keycode(p uint16) Keycode {
|
||||||
|
if p < 0x80 {
|
||||||
|
return ascii[p]
|
||||||
|
} else if p >= 0xA0 && p < 0x0100 {
|
||||||
|
return iso88591[p-0xA0]
|
||||||
|
} else if uint16(UNICODE20AC) == p {
|
||||||
|
return UNICODE20AC.mask()
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func deadkey(c Keycode) Keycode {
|
||||||
|
switch c & deadkeysMask {
|
||||||
|
case acuteAccentBits:
|
||||||
|
return deadkeyAcuteAccent
|
||||||
|
case circumflexBits:
|
||||||
|
return deadkeyCircumflex
|
||||||
|
case diaeresisBits:
|
||||||
|
return deadkeyDiaeresis
|
||||||
|
case graveAccentBits:
|
||||||
|
return deadkeyGraveAccent
|
||||||
|
case tildeBits:
|
||||||
|
return deadkeyTilde
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (c Keycode) mask() Keycode { return c & keycodeMask }
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (c Keycode) key() uint8 { return uint8(c & keyMask) }
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (c Keycode) mod() uint8 {
|
||||||
|
var m Keycode
|
||||||
|
if 0 != c&shiftMask {
|
||||||
|
m |= KeyModifierShift
|
||||||
|
}
|
||||||
|
if 0 != c&altgrMask {
|
||||||
|
m |= KeyModifierRightAlt
|
||||||
|
}
|
||||||
|
return uint8(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (c Keycode) Shift() Keycode { return c | KeyModifierShift }
|
||||||
|
|
||||||
|
const (
|
||||||
|
hidKeyboardKeyCount = 6 // Max number of simultaneous keypresses
|
||||||
|
hidKeyboardSysCount = 3
|
||||||
|
hidKeyboardConCount = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keycodes common to all Keyboard layouts
|
||||||
|
const (
|
||||||
|
KeyModifierCtrl Keycode = 0x01 | 0xE000
|
||||||
|
KeyModifierShift Keycode = 0x02 | 0xE000
|
||||||
|
KeyModifierAlt Keycode = 0x04 | 0xE000
|
||||||
|
KeyModifierGUI Keycode = 0x08 | 0xE000
|
||||||
|
KeyModifierLeftCtrl Keycode = 0x01 | 0xE000
|
||||||
|
KeyModifierLeftShift Keycode = 0x02 | 0xE000
|
||||||
|
KeyModifierLeftAlt Keycode = 0x04 | 0xE000
|
||||||
|
KeyModifierLeftGUI Keycode = 0x08 | 0xE000
|
||||||
|
KeyModifierRightCtrl Keycode = 0x10 | 0xE000
|
||||||
|
KeyModifierRightShift Keycode = 0x20 | 0xE000
|
||||||
|
KeyModifierRightAlt Keycode = 0x40 | 0xE000
|
||||||
|
KeyModifierRightGUI Keycode = 0x80 | 0xE000
|
||||||
|
|
||||||
|
KeySystemPowerDown Keycode = 0x81 | 0xE200
|
||||||
|
KeySystemSleep Keycode = 0x82 | 0xE200
|
||||||
|
KeySystemWakeUp Keycode = 0x83 | 0xE200
|
||||||
|
|
||||||
|
KeyMediaPlay Keycode = 0xB0 | 0xE400
|
||||||
|
KeyMediaPause Keycode = 0xB1 | 0xE400
|
||||||
|
KeyMediaRecord Keycode = 0xB2 | 0xE400
|
||||||
|
KeyMediaFastForward Keycode = 0xB3 | 0xE400
|
||||||
|
KeyMediaRewind Keycode = 0xB4 | 0xE400
|
||||||
|
KeyMediaNextTrack Keycode = 0xB5 | 0xE400
|
||||||
|
KeyMediaPrevTrack Keycode = 0xB6 | 0xE400
|
||||||
|
KeyMediaStop Keycode = 0xB7 | 0xE400
|
||||||
|
KeyMediaEject Keycode = 0xB8 | 0xE400
|
||||||
|
KeyMediaRandomPlay Keycode = 0xB9 | 0xE400
|
||||||
|
KeyMediaPlayPause Keycode = 0xCD | 0xE400
|
||||||
|
KeyMediaPlaySkip Keycode = 0xCE | 0xE400
|
||||||
|
KeyMediaMute Keycode = 0xE2 | 0xE400
|
||||||
|
KeyMediaVolumeInc Keycode = 0xE9 | 0xE400
|
||||||
|
KeyMediaVolumeDec Keycode = 0xEA | 0xE400
|
||||||
|
|
||||||
|
KeyA Keycode = 4 | 0xF000
|
||||||
|
KeyB Keycode = 5 | 0xF000
|
||||||
|
KeyC Keycode = 6 | 0xF000
|
||||||
|
KeyD Keycode = 7 | 0xF000
|
||||||
|
KeyE Keycode = 8 | 0xF000
|
||||||
|
KeyF Keycode = 9 | 0xF000
|
||||||
|
KeyG Keycode = 10 | 0xF000
|
||||||
|
KeyH Keycode = 11 | 0xF000
|
||||||
|
KeyI Keycode = 12 | 0xF000
|
||||||
|
KeyJ Keycode = 13 | 0xF000
|
||||||
|
KeyK Keycode = 14 | 0xF000
|
||||||
|
KeyL Keycode = 15 | 0xF000
|
||||||
|
KeyM Keycode = 16 | 0xF000
|
||||||
|
KeyN Keycode = 17 | 0xF000
|
||||||
|
KeyO Keycode = 18 | 0xF000
|
||||||
|
KeyP Keycode = 19 | 0xF000
|
||||||
|
KeyQ Keycode = 20 | 0xF000
|
||||||
|
KeyR Keycode = 21 | 0xF000
|
||||||
|
KeyS Keycode = 22 | 0xF000
|
||||||
|
KeyT Keycode = 23 | 0xF000
|
||||||
|
KeyU Keycode = 24 | 0xF000
|
||||||
|
KeyV Keycode = 25 | 0xF000
|
||||||
|
KeyW Keycode = 26 | 0xF000
|
||||||
|
KeyX Keycode = 27 | 0xF000
|
||||||
|
KeyY Keycode = 28 | 0xF000
|
||||||
|
KeyZ Keycode = 29 | 0xF000
|
||||||
|
Key1 Keycode = 30 | 0xF000
|
||||||
|
Key2 Keycode = 31 | 0xF000
|
||||||
|
Key3 Keycode = 32 | 0xF000
|
||||||
|
Key4 Keycode = 33 | 0xF000
|
||||||
|
Key5 Keycode = 34 | 0xF000
|
||||||
|
Key6 Keycode = 35 | 0xF000
|
||||||
|
Key7 Keycode = 36 | 0xF000
|
||||||
|
Key8 Keycode = 37 | 0xF000
|
||||||
|
Key9 Keycode = 38 | 0xF000
|
||||||
|
Key0 Keycode = 39 | 0xF000
|
||||||
|
KeyEnter Keycode = 40 | 0xF000
|
||||||
|
KeyEsc Keycode = 41 | 0xF000
|
||||||
|
KeyBackspace Keycode = 42 | 0xF000
|
||||||
|
KeyTab Keycode = 43 | 0xF000
|
||||||
|
KeySpace Keycode = 44 | 0xF000
|
||||||
|
KeyMinus Keycode = 45 | 0xF000
|
||||||
|
KeyEqual Keycode = 46 | 0xF000
|
||||||
|
KeyLeftBrace Keycode = 47 | 0xF000
|
||||||
|
KeyRightBrace Keycode = 48 | 0xF000
|
||||||
|
KeyBackslash Keycode = 49 | 0xF000
|
||||||
|
KeyNonUsNum Keycode = 50 | 0xF000
|
||||||
|
KeySemicolon Keycode = 51 | 0xF000
|
||||||
|
KeyQuote Keycode = 52 | 0xF000
|
||||||
|
KeyTilde Keycode = 53 | 0xF000
|
||||||
|
KeyComma Keycode = 54 | 0xF000
|
||||||
|
KeyPeriod Keycode = 55 | 0xF000
|
||||||
|
KeySlash Keycode = 56 | 0xF000
|
||||||
|
KeyCapsLock Keycode = 57 | 0xF000
|
||||||
|
KeyF1 Keycode = 58 | 0xF000
|
||||||
|
KeyF2 Keycode = 59 | 0xF000
|
||||||
|
KeyF3 Keycode = 60 | 0xF000
|
||||||
|
KeyF4 Keycode = 61 | 0xF000
|
||||||
|
KeyF5 Keycode = 62 | 0xF000
|
||||||
|
KeyF6 Keycode = 63 | 0xF000
|
||||||
|
KeyF7 Keycode = 64 | 0xF000
|
||||||
|
KeyF8 Keycode = 65 | 0xF000
|
||||||
|
KeyF9 Keycode = 66 | 0xF000
|
||||||
|
KeyF10 Keycode = 67 | 0xF000
|
||||||
|
KeyF11 Keycode = 68 | 0xF000
|
||||||
|
KeyF12 Keycode = 69 | 0xF000
|
||||||
|
KeyPrintscreen Keycode = 70 | 0xF000
|
||||||
|
KeyScrollLock Keycode = 71 | 0xF000
|
||||||
|
KeyPause Keycode = 72 | 0xF000
|
||||||
|
KeyInsert Keycode = 73 | 0xF000
|
||||||
|
KeyHome Keycode = 74 | 0xF000
|
||||||
|
KeyPageUp Keycode = 75 | 0xF000
|
||||||
|
KeyDelete Keycode = 76 | 0xF000
|
||||||
|
KeyEnd Keycode = 77 | 0xF000
|
||||||
|
KeyPageDown Keycode = 78 | 0xF000
|
||||||
|
KeyRight Keycode = 79 | 0xF000
|
||||||
|
KeyLeft Keycode = 80 | 0xF000
|
||||||
|
KeyDown Keycode = 81 | 0xF000
|
||||||
|
KeyUp Keycode = 82 | 0xF000
|
||||||
|
KeyNumLock Keycode = 83 | 0xF000
|
||||||
|
KeypadSlash Keycode = 84 | 0xF000
|
||||||
|
KeypadAsterisk Keycode = 85 | 0xF000
|
||||||
|
KeypadMinus Keycode = 86 | 0xF000
|
||||||
|
KeypadPlus Keycode = 87 | 0xF000
|
||||||
|
KeypadEnter Keycode = 88 | 0xF000
|
||||||
|
Keypad1 Keycode = 89 | 0xF000
|
||||||
|
Keypad2 Keycode = 90 | 0xF000
|
||||||
|
Keypad3 Keycode = 91 | 0xF000
|
||||||
|
Keypad4 Keycode = 92 | 0xF000
|
||||||
|
Keypad5 Keycode = 93 | 0xF000
|
||||||
|
Keypad6 Keycode = 94 | 0xF000
|
||||||
|
Keypad7 Keycode = 95 | 0xF000
|
||||||
|
Keypad8 Keycode = 96 | 0xF000
|
||||||
|
Keypad9 Keycode = 97 | 0xF000
|
||||||
|
Keypad0 Keycode = 98 | 0xF000
|
||||||
|
KeypadPeriod Keycode = 99 | 0xF000
|
||||||
|
KeyNonUSBS Keycode = 100 | 0xF000
|
||||||
|
KeyMenu Keycode = 101 | 0xF000
|
||||||
|
KeyF13 Keycode = 104 | 0xF000
|
||||||
|
KeyF14 Keycode = 105 | 0xF000
|
||||||
|
KeyF15 Keycode = 106 | 0xF000
|
||||||
|
KeyF16 Keycode = 107 | 0xF000
|
||||||
|
KeyF17 Keycode = 108 | 0xF000
|
||||||
|
KeyF18 Keycode = 109 | 0xF000
|
||||||
|
KeyF19 Keycode = 110 | 0xF000
|
||||||
|
KeyF20 Keycode = 111 | 0xF000
|
||||||
|
KeyF21 Keycode = 112 | 0xF000
|
||||||
|
KeyF22 Keycode = 113 | 0xF000
|
||||||
|
KeyF23 Keycode = 114 | 0xF000
|
||||||
|
KeyF24 Keycode = 115 | 0xF000
|
||||||
|
|
||||||
|
KeyUpArrow Keycode = KeyUp
|
||||||
|
KeyDownArrow Keycode = KeyDown
|
||||||
|
KeyLeftArrow Keycode = KeyLeft
|
||||||
|
KeyRightArrow Keycode = KeyRight
|
||||||
|
KeyReturn Keycode = KeyEnter
|
||||||
|
KeyLeftCtrl Keycode = KeyModifierLeftCtrl
|
||||||
|
KeyLeftShift Keycode = KeyModifierLeftShift
|
||||||
|
KeyLeftAlt Keycode = KeyModifierLeftAlt
|
||||||
|
KeyLeftGUI Keycode = KeyModifierLeftGUI
|
||||||
|
KeyRightCtrl Keycode = KeyModifierRightCtrl
|
||||||
|
KeyRightShift Keycode = KeyModifierRightShift
|
||||||
|
KeyRightAlt Keycode = KeyModifierRightAlt
|
||||||
|
KeyRightGUI Keycode = KeyModifierRightGUI
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keycodes for layout US English (0x0904)
|
||||||
|
const (
|
||||||
|
keycodeMask Keycode = 0x07FF
|
||||||
|
keyMask Keycode = 0x003F
|
||||||
|
|
||||||
|
shiftMask Keycode = 0x0040
|
||||||
|
altgrMask Keycode = 0x0080
|
||||||
|
deadkeysMask Keycode = 0x0700
|
||||||
|
circumflexBits Keycode = 0x0100
|
||||||
|
acuteAccentBits Keycode = 0x0200
|
||||||
|
graveAccentBits Keycode = 0x0300
|
||||||
|
tildeBits Keycode = 0x0400
|
||||||
|
diaeresisBits Keycode = 0x0500
|
||||||
|
deadkeyCircumflex Keycode = Key6 | shiftMask
|
||||||
|
deadkeyAcuteAccent Keycode = KeyQuote
|
||||||
|
deadkeyGraveAccent Keycode = KeyTilde
|
||||||
|
deadkeyTilde Keycode = KeyTilde | shiftMask
|
||||||
|
deadkeyDiaeresis Keycode = KeyQuote | shiftMask
|
||||||
|
|
||||||
|
ASCII00 Keycode = 0 // 0 NUL
|
||||||
|
ASCII01 Keycode = 0 // 1 SOH
|
||||||
|
ASCII02 Keycode = 0 // 2 STX
|
||||||
|
ASCII03 Keycode = 0 // 3 ETX
|
||||||
|
ASCII04 Keycode = 0 // 4 EOT
|
||||||
|
ASCII05 Keycode = 0 // 5 ENQ
|
||||||
|
ASCII06 Keycode = 0 // 6 ACK
|
||||||
|
ASCII07 Keycode = 0 // 7 BEL
|
||||||
|
ASCII08 Keycode = KeyBackspace // 8 BS
|
||||||
|
ASCII09 Keycode = KeyTab // 9 TAB
|
||||||
|
ASCII0A Keycode = KeyEnter // 10 LF
|
||||||
|
ASCII0B Keycode = 0 // 11 VT
|
||||||
|
ASCII0C Keycode = 0 // 12 FF
|
||||||
|
ASCII0D Keycode = 0 // 13 CR
|
||||||
|
ASCII0E Keycode = 0 // 14 SO
|
||||||
|
ASCII0F Keycode = 0 // 15 SI
|
||||||
|
ASCII10 Keycode = 0 // 16 DEL
|
||||||
|
ASCII11 Keycode = 0 // 17 DC1
|
||||||
|
ASCII12 Keycode = 0 // 18 DC2
|
||||||
|
ASCII13 Keycode = 0 // 19 DC3
|
||||||
|
ASCII14 Keycode = 0 // 20 DC4
|
||||||
|
ASCII15 Keycode = 0 // 21 NAK
|
||||||
|
ASCII16 Keycode = 0 // 22 SYN
|
||||||
|
ASCII17 Keycode = 0 // 23 ETB
|
||||||
|
ASCII18 Keycode = 0 // 24 CAN
|
||||||
|
ASCII19 Keycode = 0 // 25 EM
|
||||||
|
ASCII1A Keycode = 0 // 26 SUB
|
||||||
|
ASCII1B Keycode = 0 // 27 ESC
|
||||||
|
ASCII1C Keycode = 0 // 28 FS
|
||||||
|
ASCII1D Keycode = 0 // 29 GS
|
||||||
|
ASCII1E Keycode = 0 // 30 RS
|
||||||
|
ASCII1F Keycode = 0 // 31 US
|
||||||
|
|
||||||
|
ASCII20 Keycode = KeySpace // 32 SPACE
|
||||||
|
ASCII21 Keycode = Key1 | shiftMask // 33 !
|
||||||
|
ASCII22 Keycode = diaeresisBits | KeySpace // 34 "
|
||||||
|
ASCII23 Keycode = Key3 | shiftMask // 35 #
|
||||||
|
ASCII24 Keycode = Key4 | shiftMask // 36 $
|
||||||
|
ASCII25 Keycode = Key5 | shiftMask // 37 %
|
||||||
|
ASCII26 Keycode = Key7 | shiftMask // 38 &
|
||||||
|
ASCII27 Keycode = acuteAccentBits | KeySpace // 39 '
|
||||||
|
ASCII28 Keycode = Key9 | shiftMask // 40 (
|
||||||
|
ASCII29 Keycode = Key0 | shiftMask // 41 )
|
||||||
|
ASCII2A Keycode = Key8 | shiftMask // 42 *
|
||||||
|
ASCII2B Keycode = KeyEqual | shiftMask // 43 +
|
||||||
|
ASCII2C Keycode = KeyComma // 44 ,
|
||||||
|
ASCII2D Keycode = KeyMinus // 45 -
|
||||||
|
ASCII2E Keycode = KeyPeriod // 46 .
|
||||||
|
ASCII2F Keycode = KeySlash // 47 /
|
||||||
|
ASCII30 Keycode = Key0 // 48 0
|
||||||
|
ASCII31 Keycode = Key1 // 49 1
|
||||||
|
ASCII32 Keycode = Key2 // 50 2
|
||||||
|
ASCII33 Keycode = Key3 // 51 3
|
||||||
|
ASCII34 Keycode = Key4 // 52 4
|
||||||
|
ASCII35 Keycode = Key5 // 53 5
|
||||||
|
ASCII36 Keycode = Key6 // 54 6
|
||||||
|
ASCII37 Keycode = Key7 // 55 7
|
||||||
|
ASCII38 Keycode = Key8 // 55 8
|
||||||
|
ASCII39 Keycode = Key9 // 57 9
|
||||||
|
ASCII3A Keycode = KeySemicolon | shiftMask // 58 :
|
||||||
|
ASCII3B Keycode = KeySemicolon // 59 ;
|
||||||
|
ASCII3C Keycode = KeyComma | shiftMask // 60 <
|
||||||
|
ASCII3D Keycode = KeyEqual // 61 =
|
||||||
|
ASCII3E Keycode = KeyPeriod | shiftMask // 62 >
|
||||||
|
ASCII3F Keycode = KeySlash | shiftMask // 63 ?
|
||||||
|
ASCII40 Keycode = Key2 | shiftMask // 64 @
|
||||||
|
ASCII41 Keycode = KeyA | shiftMask // 65 A
|
||||||
|
ASCII42 Keycode = KeyB | shiftMask // 66 B
|
||||||
|
ASCII43 Keycode = KeyC | shiftMask // 67 C
|
||||||
|
ASCII44 Keycode = KeyD | shiftMask // 68 D
|
||||||
|
ASCII45 Keycode = KeyE | shiftMask // 69 E
|
||||||
|
ASCII46 Keycode = KeyF | shiftMask // 70 F
|
||||||
|
ASCII47 Keycode = KeyG | shiftMask // 71 G
|
||||||
|
ASCII48 Keycode = KeyH | shiftMask // 72 H
|
||||||
|
ASCII49 Keycode = KeyI | shiftMask // 73 I
|
||||||
|
ASCII4A Keycode = KeyJ | shiftMask // 74 J
|
||||||
|
ASCII4B Keycode = KeyK | shiftMask // 75 K
|
||||||
|
ASCII4C Keycode = KeyL | shiftMask // 76 L
|
||||||
|
ASCII4D Keycode = KeyM | shiftMask // 77 M
|
||||||
|
ASCII4E Keycode = KeyN | shiftMask // 78 N
|
||||||
|
ASCII4F Keycode = KeyO | shiftMask // 79 O
|
||||||
|
ASCII50 Keycode = KeyP | shiftMask // 80 P
|
||||||
|
ASCII51 Keycode = KeyQ | shiftMask // 81 Q
|
||||||
|
ASCII52 Keycode = KeyR | shiftMask // 82 R
|
||||||
|
ASCII53 Keycode = KeyS | shiftMask // 83 S
|
||||||
|
ASCII54 Keycode = KeyT | shiftMask // 84 T
|
||||||
|
ASCII55 Keycode = KeyU | shiftMask // 85 U
|
||||||
|
ASCII56 Keycode = KeyV | shiftMask // 86 V
|
||||||
|
ASCII57 Keycode = KeyW | shiftMask // 87 W
|
||||||
|
ASCII58 Keycode = KeyX | shiftMask // 88 X
|
||||||
|
ASCII59 Keycode = KeyY | shiftMask // 89 Y
|
||||||
|
ASCII5A Keycode = KeyZ | shiftMask // 90 Z
|
||||||
|
ASCII5B Keycode = KeyLeftBrace // 91 [
|
||||||
|
ASCII5C Keycode = KeyBackslash // 92 \
|
||||||
|
ASCII5D Keycode = KeyRightBrace // 93 ]
|
||||||
|
ASCII5E Keycode = circumflexBits | KeySpace // 94 ^
|
||||||
|
ASCII5F Keycode = KeyMinus | shiftMask // 95
|
||||||
|
ASCII60 Keycode = graveAccentBits | KeySpace // 96 `
|
||||||
|
ASCII61 Keycode = KeyA // 97 a
|
||||||
|
ASCII62 Keycode = KeyB // 98 b
|
||||||
|
ASCII63 Keycode = KeyC // 99 c
|
||||||
|
ASCII64 Keycode = KeyD // 100 d
|
||||||
|
ASCII65 Keycode = KeyE // 101 e
|
||||||
|
ASCII66 Keycode = KeyF // 102 f
|
||||||
|
ASCII67 Keycode = KeyG // 103 g
|
||||||
|
ASCII68 Keycode = KeyH // 104 h
|
||||||
|
ASCII69 Keycode = KeyI // 105 i
|
||||||
|
ASCII6A Keycode = KeyJ // 106 j
|
||||||
|
ASCII6B Keycode = KeyK // 107 k
|
||||||
|
ASCII6C Keycode = KeyL // 108 l
|
||||||
|
ASCII6D Keycode = KeyM // 109 m
|
||||||
|
ASCII6E Keycode = KeyN // 110 n
|
||||||
|
ASCII6F Keycode = KeyO // 111 o
|
||||||
|
ASCII70 Keycode = KeyP // 112 p
|
||||||
|
ASCII71 Keycode = KeyQ // 113 q
|
||||||
|
ASCII72 Keycode = KeyR // 114 r
|
||||||
|
ASCII73 Keycode = KeyS // 115 s
|
||||||
|
ASCII74 Keycode = KeyT // 116 t
|
||||||
|
ASCII75 Keycode = KeyU // 117 u
|
||||||
|
ASCII76 Keycode = KeyV // 118 v
|
||||||
|
ASCII77 Keycode = KeyW // 119 w
|
||||||
|
ASCII78 Keycode = KeyX // 120 x
|
||||||
|
ASCII79 Keycode = KeyY // 121 y
|
||||||
|
ASCII7A Keycode = KeyZ // 122 z
|
||||||
|
ASCII7B Keycode = KeyLeftBrace | shiftMask // 123 {
|
||||||
|
ASCII7C Keycode = KeyBackslash | shiftMask // 124 |
|
||||||
|
ASCII7D Keycode = KeyRightBrace | shiftMask // 125 }
|
||||||
|
ASCII7E Keycode = tildeBits | KeySpace // 126 ~
|
||||||
|
ASCII7F Keycode = KeyBackspace // 127 DEL
|
||||||
|
ISO88591A0 Keycode = KeySpace // 160 Nonbreakng Space
|
||||||
|
ISO88591A1 Keycode = Key1 | altgrMask // 161 ¡ Inverted Exclamation
|
||||||
|
ISO88591A2 Keycode = KeyC | altgrMask | shiftMask // 162 ¢ Cent SIGN
|
||||||
|
ISO88591A3 Keycode = Key4 | altgrMask | shiftMask // 163 £ Pound Sign
|
||||||
|
ISO88591A4 Keycode = Key4 | altgrMask // 164 ¤ Currency or Euro Sign
|
||||||
|
ISO88591A5 Keycode = KeyMinus | altgrMask // 165 ¥ YEN SIGN
|
||||||
|
ISO88591A6 Keycode = KeyBackslash | altgrMask | shiftMask // 166 ¦ BROKEN BAR ??
|
||||||
|
ISO88591A7 Keycode = KeyS | altgrMask | shiftMask // 167 § SECTION SIGN
|
||||||
|
ISO88591A8 Keycode = KeyQuote | altgrMask | shiftMask // 168 ¨ DIAERESIS
|
||||||
|
ISO88591A9 Keycode = KeyC | altgrMask // 169 © COPYRIGHT SIGN
|
||||||
|
ISO88591AA Keycode = 0 // 170 ª FEMININE ORDINAL
|
||||||
|
ISO88591AB Keycode = KeyLeftBrace | altgrMask // 171 « LEFT DOUBLE ANGLE QUOTE
|
||||||
|
ISO88591AC Keycode = KeyBackslash | altgrMask // 172 ¬ NOT SIGN ??
|
||||||
|
ISO88591AD Keycode = 0 // 173 SOFT HYPHEN
|
||||||
|
ISO88591AE Keycode = KeyR | altgrMask // 174 ® REGISTERED SIGN
|
||||||
|
ISO88591AF Keycode = 0 // 175 ¯ MACRON
|
||||||
|
ISO88591B0 Keycode = KeySemicolon | altgrMask | shiftMask // 176 ° DEGREE SIGN
|
||||||
|
ISO88591B1 Keycode = 0 // 177 ± PLUS-MINUS SIGN
|
||||||
|
ISO88591B2 Keycode = Key2 | altgrMask // 178 ² SUPERSCRIPT TWO
|
||||||
|
ISO88591B3 Keycode = Key3 | altgrMask // 179 ³ SUPERSCRIPT THREE
|
||||||
|
ISO88591B4 Keycode = KeyQuote | altgrMask // 180 ´ ACUTE ACCENT
|
||||||
|
ISO88591B5 Keycode = KeyM | altgrMask // 181 µ MICRO SIGN
|
||||||
|
ISO88591B6 Keycode = KeySemicolon | altgrMask // 182 ¶ PILCROW SIGN
|
||||||
|
ISO88591B7 Keycode = 0 // 183 · MIDDLE DOT
|
||||||
|
ISO88591B8 Keycode = 0 // 184 ¸ CEDILLA
|
||||||
|
ISO88591B9 Keycode = Key1 | altgrMask | shiftMask // 185 ¹ SUPERSCRIPT ONE
|
||||||
|
ISO88591BA Keycode = 0 // 186 º MASCULINE ORDINAL
|
||||||
|
ISO88591BB Keycode = KeyRightBrace | altgrMask // 187 » RIGHT DOUBLE ANGLE QUOTE
|
||||||
|
ISO88591BC Keycode = Key6 | altgrMask // 188 ¼ FRACTION ONE QUARTER
|
||||||
|
ISO88591BD Keycode = Key7 | altgrMask // 189 ½ FRACTION ONE HALF
|
||||||
|
ISO88591BE Keycode = Key8 | altgrMask // 190 ¾ FRACTION THREE QUARTERS
|
||||||
|
ISO88591BF Keycode = KeySlash | altgrMask // 191 ¿ INVERTED QUESTION MARK
|
||||||
|
ISO88591C0 Keycode = graveAccentBits | KeyA | shiftMask // 192 À A GRAVE
|
||||||
|
ISO88591C1 Keycode = KeyA | altgrMask | shiftMask // 193 Á A ACUTE
|
||||||
|
ISO88591C2 Keycode = circumflexBits | KeyA | shiftMask // 194 Â A CIRCUMFLEX
|
||||||
|
ISO88591C3 Keycode = tildeBits | KeyA | shiftMask // 195 Ã A TILDE
|
||||||
|
ISO88591C4 Keycode = KeyQ | altgrMask | shiftMask // 196 Ä A DIAERESIS
|
||||||
|
ISO88591C5 Keycode = KeyW | altgrMask | shiftMask // 197 Å A RING ABOVE
|
||||||
|
ISO88591C6 Keycode = KeyZ | altgrMask | shiftMask // 198 Æ AE
|
||||||
|
ISO88591C7 Keycode = KeyComma | altgrMask | shiftMask // 199 Ç C CEDILLA
|
||||||
|
ISO88591C8 Keycode = graveAccentBits | KeyE | shiftMask // 200 È E GRAVE
|
||||||
|
ISO88591C9 Keycode = KeyE | altgrMask | shiftMask // 201 É E ACUTE
|
||||||
|
ISO88591CA Keycode = circumflexBits | KeyE | shiftMask // 202 Ê E CIRCUMFLEX
|
||||||
|
ISO88591CB Keycode = diaeresisBits | KeyE | shiftMask // 203 Ë E DIAERESIS
|
||||||
|
ISO88591CC Keycode = graveAccentBits | KeyI | shiftMask // 204 Ì I GRAVE
|
||||||
|
ISO88591CD Keycode = KeyI | altgrMask | shiftMask // 205 Í I ACUTE
|
||||||
|
ISO88591CE Keycode = circumflexBits | KeyI | shiftMask // 206 Î I CIRCUMFLEX
|
||||||
|
ISO88591CF Keycode = diaeresisBits | KeyI | shiftMask // 207 Ï I DIAERESIS
|
||||||
|
ISO88591D0 Keycode = KeyD | altgrMask | shiftMask // 208 Ð ETH
|
||||||
|
ISO88591D1 Keycode = KeyN | altgrMask | shiftMask // 209 Ñ N TILDE
|
||||||
|
ISO88591D2 Keycode = graveAccentBits | KeyO | shiftMask // 210 Ò O GRAVE
|
||||||
|
ISO88591D3 Keycode = KeyO | altgrMask | shiftMask // 211 Ó O ACUTE
|
||||||
|
ISO88591D4 Keycode = circumflexBits | KeyO | shiftMask // 212 Ô O CIRCUMFLEX
|
||||||
|
ISO88591D5 Keycode = tildeBits | KeyO | shiftMask // 213 Õ O TILDE
|
||||||
|
ISO88591D6 Keycode = KeyP | altgrMask | shiftMask // 214 Ö O DIAERESIS
|
||||||
|
ISO88591D7 Keycode = KeyEqual | altgrMask // 215 × MULTIPLICATION
|
||||||
|
ISO88591D8 Keycode = KeyL | altgrMask | shiftMask // 216 Ø O STROKE
|
||||||
|
ISO88591D9 Keycode = graveAccentBits | KeyU | shiftMask // 217 Ù U GRAVE
|
||||||
|
ISO88591DA Keycode = KeyU | altgrMask | shiftMask // 218 Ú U ACUTE
|
||||||
|
ISO88591DB Keycode = circumflexBits | KeyU | shiftMask // 219 Û U CIRCUMFLEX
|
||||||
|
ISO88591DC Keycode = KeyY | altgrMask | shiftMask // 220 Ü U DIAERESIS
|
||||||
|
ISO88591DD Keycode = acuteAccentBits | KeyY | shiftMask // 221 Ý Y ACUTE
|
||||||
|
ISO88591DE Keycode = KeyT | altgrMask | shiftMask // 222 Þ THORN
|
||||||
|
ISO88591DF Keycode = KeyS | altgrMask // 223 ß SHARP S
|
||||||
|
ISO88591E0 Keycode = graveAccentBits | KeyA // 224 à a GRAVE
|
||||||
|
ISO88591E1 Keycode = KeyA | altgrMask // 225 á a ACUTE
|
||||||
|
ISO88591E2 Keycode = circumflexBits | KeyA // 226 â a CIRCUMFLEX
|
||||||
|
ISO88591E3 Keycode = tildeBits | KeyA // 227 ã a TILDE
|
||||||
|
ISO88591E4 Keycode = diaeresisBits | KeyA // 228 ä a DIAERESIS
|
||||||
|
ISO88591E5 Keycode = KeyW | altgrMask // 229 å a RING ABOVE
|
||||||
|
ISO88591E6 Keycode = KeyZ | altgrMask // 230 æ ae
|
||||||
|
ISO88591E7 Keycode = KeyComma | altgrMask // 231 ç c CEDILLA
|
||||||
|
ISO88591E8 Keycode = graveAccentBits | KeyE // 232 è e GRAVE
|
||||||
|
ISO88591E9 Keycode = acuteAccentBits | KeyE // 233 é e ACUTE
|
||||||
|
ISO88591EA Keycode = circumflexBits | KeyE // 234 ê e CIRCUMFLEX
|
||||||
|
ISO88591EB Keycode = diaeresisBits | KeyE // 235 ë e DIAERESIS
|
||||||
|
ISO88591EC Keycode = graveAccentBits | KeyI // 236 ì i GRAVE
|
||||||
|
ISO88591ED Keycode = KeyI | altgrMask // 237 í i ACUTE
|
||||||
|
ISO88591EE Keycode = circumflexBits | KeyI // 238 î i CIRCUMFLEX
|
||||||
|
ISO88591EF Keycode = diaeresisBits | KeyI // 239 ï i DIAERESIS
|
||||||
|
ISO88591F0 Keycode = KeyD | altgrMask // 240 ð ETH
|
||||||
|
ISO88591F1 Keycode = KeyN | altgrMask // 241 ñ n TILDE
|
||||||
|
ISO88591F2 Keycode = graveAccentBits | KeyO // 242 ò o GRAVE
|
||||||
|
ISO88591F3 Keycode = KeyO | altgrMask // 243 ó o ACUTE
|
||||||
|
ISO88591F4 Keycode = circumflexBits | KeyO // 244 ô o CIRCUMFLEX
|
||||||
|
ISO88591F5 Keycode = tildeBits | KeyO // 245 õ o TILDE
|
||||||
|
ISO88591F6 Keycode = KeyP | altgrMask // 246 ö o DIAERESIS
|
||||||
|
ISO88591F7 Keycode = KeyEqual | altgrMask | shiftMask // 247 ÷ DIVISION
|
||||||
|
ISO88591F8 Keycode = KeyL | altgrMask // 248 ø o STROKE
|
||||||
|
ISO88591F9 Keycode = graveAccentBits | KeyU // 249 ù u GRAVE
|
||||||
|
ISO88591FA Keycode = KeyU | altgrMask // 250 ú u ACUTE
|
||||||
|
ISO88591FB Keycode = circumflexBits | KeyU // 251 û u CIRCUMFLEX
|
||||||
|
ISO88591FC Keycode = KeyY | altgrMask // 252 ü u DIAERESIS
|
||||||
|
ISO88591FD Keycode = acuteAccentBits | KeyY // 253 ý y ACUTE
|
||||||
|
ISO88591FE Keycode = KeyT | altgrMask // 254 þ THORN
|
||||||
|
ISO88591FF Keycode = diaeresisBits | KeyY // 255 ÿ y DIAERESIS
|
||||||
|
UNICODE20AC Keycode = Key5 | altgrMask // 20AC € Euro Sign
|
||||||
|
)
|
||||||
|
|
||||||
|
var ascii = [...]Keycode{
|
||||||
|
ASCII00.mask(), ASCII01.mask(), ASCII02.mask(), ASCII03.mask(),
|
||||||
|
ASCII04.mask(), ASCII05.mask(), ASCII06.mask(), ASCII07.mask(),
|
||||||
|
ASCII08.mask(), ASCII09.mask(), ASCII0A.mask(), ASCII0B.mask(),
|
||||||
|
ASCII0C.mask(), ASCII0D.mask(), ASCII0E.mask(), ASCII0F.mask(),
|
||||||
|
ASCII10.mask(), ASCII11.mask(), ASCII12.mask(), ASCII13.mask(),
|
||||||
|
ASCII14.mask(), ASCII15.mask(), ASCII16.mask(), ASCII17.mask(),
|
||||||
|
ASCII18.mask(), ASCII19.mask(), ASCII1A.mask(), ASCII1B.mask(),
|
||||||
|
ASCII1C.mask(), ASCII1D.mask(), ASCII1E.mask(), ASCII1F.mask(),
|
||||||
|
ASCII20.mask(), ASCII21.mask(), ASCII22.mask(), ASCII23.mask(),
|
||||||
|
ASCII24.mask(), ASCII25.mask(), ASCII26.mask(), ASCII27.mask(),
|
||||||
|
ASCII28.mask(), ASCII29.mask(), ASCII2A.mask(), ASCII2B.mask(),
|
||||||
|
ASCII2C.mask(), ASCII2D.mask(), ASCII2E.mask(), ASCII2F.mask(),
|
||||||
|
ASCII30.mask(), ASCII31.mask(), ASCII32.mask(), ASCII33.mask(),
|
||||||
|
ASCII34.mask(), ASCII35.mask(), ASCII36.mask(), ASCII37.mask(),
|
||||||
|
ASCII38.mask(), ASCII39.mask(), ASCII3A.mask(), ASCII3B.mask(),
|
||||||
|
ASCII3C.mask(), ASCII3D.mask(), ASCII3E.mask(), ASCII3F.mask(),
|
||||||
|
ASCII40.mask(), ASCII41.mask(), ASCII42.mask(), ASCII43.mask(),
|
||||||
|
ASCII44.mask(), ASCII45.mask(), ASCII46.mask(), ASCII47.mask(),
|
||||||
|
ASCII48.mask(), ASCII49.mask(), ASCII4A.mask(), ASCII4B.mask(),
|
||||||
|
ASCII4C.mask(), ASCII4D.mask(), ASCII4E.mask(), ASCII4F.mask(),
|
||||||
|
ASCII50.mask(), ASCII51.mask(), ASCII52.mask(), ASCII53.mask(),
|
||||||
|
ASCII54.mask(), ASCII55.mask(), ASCII56.mask(), ASCII57.mask(),
|
||||||
|
ASCII58.mask(), ASCII59.mask(), ASCII5A.mask(), ASCII5B.mask(),
|
||||||
|
ASCII5C.mask(), ASCII5D.mask(), ASCII5E.mask(), ASCII5F.mask(),
|
||||||
|
ASCII60.mask(), ASCII61.mask(), ASCII62.mask(), ASCII63.mask(),
|
||||||
|
ASCII64.mask(), ASCII65.mask(), ASCII66.mask(), ASCII67.mask(),
|
||||||
|
ASCII68.mask(), ASCII69.mask(), ASCII6A.mask(), ASCII6B.mask(),
|
||||||
|
ASCII6C.mask(), ASCII6D.mask(), ASCII6E.mask(), ASCII6F.mask(),
|
||||||
|
ASCII70.mask(), ASCII71.mask(), ASCII72.mask(), ASCII73.mask(),
|
||||||
|
ASCII74.mask(), ASCII75.mask(), ASCII76.mask(), ASCII77.mask(),
|
||||||
|
ASCII78.mask(), ASCII79.mask(), ASCII7A.mask(), ASCII7B.mask(),
|
||||||
|
ASCII7C.mask(), ASCII7D.mask(), ASCII7E.mask(), ASCII7F.mask(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var iso88591 = [...]Keycode{
|
||||||
|
ISO88591A0.mask(), ISO88591A1.mask(), ISO88591A2.mask(), ISO88591A3.mask(),
|
||||||
|
ISO88591A4.mask(), ISO88591A5.mask(), ISO88591A6.mask(), ISO88591A7.mask(),
|
||||||
|
ISO88591A8.mask(), ISO88591A9.mask(), ISO88591AA.mask(), ISO88591AB.mask(),
|
||||||
|
ISO88591AC.mask(), ISO88591AD.mask(), ISO88591AE.mask(), ISO88591AF.mask(),
|
||||||
|
ISO88591B0.mask(), ISO88591B1.mask(), ISO88591B2.mask(), ISO88591B3.mask(),
|
||||||
|
ISO88591B4.mask(), ISO88591B5.mask(), ISO88591B6.mask(), ISO88591B7.mask(),
|
||||||
|
ISO88591B8.mask(), ISO88591B9.mask(), ISO88591BA.mask(), ISO88591BB.mask(),
|
||||||
|
ISO88591BC.mask(), ISO88591BD.mask(), ISO88591BE.mask(), ISO88591BF.mask(),
|
||||||
|
ISO88591C0.mask(), ISO88591C1.mask(), ISO88591C2.mask(), ISO88591C3.mask(),
|
||||||
|
ISO88591C4.mask(), ISO88591C5.mask(), ISO88591C6.mask(), ISO88591C7.mask(),
|
||||||
|
ISO88591C8.mask(), ISO88591C9.mask(), ISO88591CA.mask(), ISO88591CB.mask(),
|
||||||
|
ISO88591CC.mask(), ISO88591CD.mask(), ISO88591CE.mask(), ISO88591CF.mask(),
|
||||||
|
ISO88591D0.mask(), ISO88591D1.mask(), ISO88591D2.mask(), ISO88591D3.mask(),
|
||||||
|
ISO88591D4.mask(), ISO88591D5.mask(), ISO88591D6.mask(), ISO88591D7.mask(),
|
||||||
|
ISO88591D8.mask(), ISO88591D9.mask(), ISO88591DA.mask(), ISO88591DB.mask(),
|
||||||
|
ISO88591DC.mask(), ISO88591DD.mask(), ISO88591DE.mask(), ISO88591DF.mask(),
|
||||||
|
ISO88591E0.mask(), ISO88591E1.mask(), ISO88591E2.mask(), ISO88591E3.mask(),
|
||||||
|
ISO88591E4.mask(), ISO88591E5.mask(), ISO88591E6.mask(), ISO88591E7.mask(),
|
||||||
|
ISO88591E8.mask(), ISO88591E9.mask(), ISO88591EA.mask(), ISO88591EB.mask(),
|
||||||
|
ISO88591EC.mask(), ISO88591ED.mask(), ISO88591EE.mask(), ISO88591EF.mask(),
|
||||||
|
ISO88591F0.mask(), ISO88591F1.mask(), ISO88591F2.mask(), ISO88591F3.mask(),
|
||||||
|
ISO88591F4.mask(), ISO88591F5.mask(), ISO88591F6.mask(), ISO88591F7.mask(),
|
||||||
|
ISO88591F8.mask(), ISO88591F9.mask(), ISO88591FA.mask(), ISO88591FB.mask(),
|
||||||
|
ISO88591FC.mask(), ISO88591FD.mask(), ISO88591FE.mask(), ISO88591FF.mask(),
|
||||||
|
}
|
90
src/machine/usb/hid/mouse/mouse.go
Обычный файл
90
src/machine/usb/hid/mouse/mouse.go
Обычный файл
|
@ -0,0 +1,90 @@
|
||||||
|
package mouse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"machine/usb/hid"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Mouse *mouse
|
||||||
|
|
||||||
|
type mouse struct {
|
||||||
|
buf *hid.RingBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if Mouse == nil {
|
||||||
|
Mouse = newMouse()
|
||||||
|
hid.SetCallbackHandler(Mouse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns hid-mouse.
|
||||||
|
func New() *mouse {
|
||||||
|
return Mouse
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMouse() *mouse {
|
||||||
|
return &mouse{
|
||||||
|
buf: hid.NewRingBuffer(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mouse) Callback() bool {
|
||||||
|
if b, ok := m.buf.Get(); ok {
|
||||||
|
hid.SendUSBPacket(b[:5])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move is a function that moves the mouse cursor.
|
||||||
|
func (m *mouse) Move(vx, vy int) {
|
||||||
|
if vx == 0 && vy == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if vx < -128 {
|
||||||
|
vx = -128
|
||||||
|
}
|
||||||
|
if vx > 127 {
|
||||||
|
vx = 127
|
||||||
|
}
|
||||||
|
|
||||||
|
if vy < -128 {
|
||||||
|
vy = -128
|
||||||
|
}
|
||||||
|
if vy > 127 {
|
||||||
|
vy = 127
|
||||||
|
}
|
||||||
|
|
||||||
|
m.buf.Put([]byte{
|
||||||
|
0x01, 0x00, byte(vx), byte(vy), 0x00,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WHEEL controls the mouse wheel.
|
||||||
|
func (m *mouse) Wheel(v int) {
|
||||||
|
if v == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if v < -128 {
|
||||||
|
v = -128
|
||||||
|
}
|
||||||
|
if v > 127 {
|
||||||
|
v = 127
|
||||||
|
}
|
||||||
|
|
||||||
|
m.buf.Put([]byte{
|
||||||
|
0x01, 0x00, 0x00, 0x00, byte(v),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WheelDown turns the mouse wheel down.
|
||||||
|
func (m *mouse) WheelDown() {
|
||||||
|
m.Wheel(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WheelUp turns the mouse wheel up.
|
||||||
|
func (m *mouse) WheelUp() {
|
||||||
|
m.Wheel(1)
|
||||||
|
}
|
70
src/machine/usb_descriptor.go
Обычный файл
70
src/machine/usb_descriptor.go
Обычный файл
|
@ -0,0 +1,70 @@
|
||||||
|
//go:build sam || nrf52840
|
||||||
|
// +build sam nrf52840
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
type USBDescriptor struct {
|
||||||
|
Device []byte
|
||||||
|
Configuration []byte
|
||||||
|
HID map[uint16][]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *USBDescriptor) Configure(idVendor, idProduct uint16) {
|
||||||
|
d.Device[8] = byte(idVendor)
|
||||||
|
d.Device[9] = byte(idVendor >> 8)
|
||||||
|
d.Device[10] = byte(idProduct)
|
||||||
|
d.Device[11] = byte(idProduct >> 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptorCDC = USBDescriptor{
|
||||||
|
Device: []byte{
|
||||||
|
0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
|
||||||
|
},
|
||||||
|
Configuration: []byte{
|
||||||
|
0x09, 0x02, 0x4b, 0x00, 0x02, 0x01, 0x00, 0xa0, 0x32,
|
||||||
|
0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
|
||||||
|
0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
|
||||||
|
0x05, 0x24, 0x00, 0x10, 0x01,
|
||||||
|
0x04, 0x24, 0x02, 0x06,
|
||||||
|
0x05, 0x24, 0x06, 0x00, 0x01,
|
||||||
|
0x05, 0x24, 0x01, 0x01, 0x01,
|
||||||
|
0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
|
||||||
|
0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
|
||||||
|
0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var descriptorCDCHID = USBDescriptor{
|
||||||
|
Device: []byte{
|
||||||
|
0x12, 0x01, 0x00, 0x02, 0xef, 0x02, 0x01, 0x40, 0x86, 0x28, 0x2d, 0x80, 0x00, 0x01, 0x01, 0x02, 0x03, 0x01,
|
||||||
|
},
|
||||||
|
Configuration: []byte{
|
||||||
|
0x09, 0x02, 0x64, 0x00, 0x03, 0x01, 0x00, 0xa0, 0x32,
|
||||||
|
0x08, 0x0b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00,
|
||||||
|
0x09, 0x04, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00,
|
||||||
|
0x05, 0x24, 0x00, 0x10, 0x01,
|
||||||
|
0x04, 0x24, 0x02, 0x06,
|
||||||
|
0x05, 0x24, 0x06, 0x00, 0x01,
|
||||||
|
0x05, 0x24, 0x01, 0x01, 0x01,
|
||||||
|
0x07, 0x05, 0x81, 0x03, 0x10, 0x00, 0x10,
|
||||||
|
0x09, 0x04, 0x01, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00,
|
||||||
|
0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x00,
|
||||||
|
0x09, 0x04, 0x02, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00,
|
||||||
|
0x09, 0x21, 0x01, 0x01, 0x00, 0x01, 0x22, 0x65, 0x00,
|
||||||
|
0x07, 0x05, 0x84, 0x03, 0x40, 0x00, 0x01,
|
||||||
|
},
|
||||||
|
HID: map[uint16][]byte{
|
||||||
|
2: []byte{
|
||||||
|
// keyboard and mouse
|
||||||
|
0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x85, 0x02, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15, 0x00,
|
||||||
|
0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x06,
|
||||||
|
0x75, 0x08, 0x15, 0x00, 0x25, 0x73, 0x05, 0x07, 0x19, 0x00, 0x29, 0x73, 0x81, 0x00, 0xc0, 0x05,
|
||||||
|
0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x85, 0x01, 0x05, 0x09, 0x19, 0x01, 0x29,
|
||||||
|
0x03, 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81,
|
||||||
|
0x03, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95,
|
||||||
|
0x03, 0x81, 0x06, 0xc0, 0xc0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче