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, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | } | ||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 sago35
						sago35