Selaa lähdekoodia

Finished keyboard emulations

Toby Chui 1 päivä sitten
vanhempi
commit
44b56869bd
55 muutettua tiedostoa jossa 460 lisäystä ja 64 poistoa
  1. 0 0
      usbkvm/legacy/remdeskd_cursor_only/.vscode/c_cpp_properties.json
  2. 0 0
      usbkvm/legacy/remdeskd_cursor_only/.vscode/launch.json
  3. 0 0
      usbkvm/legacy/remdeskd_cursor_only/.vscode/settings.json
  4. 0 0
      usbkvm/legacy/remdeskd_cursor_only/go.mod
  5. 0 0
      usbkvm/legacy/remdeskd_cursor_only/go.sum
  6. 0 0
      usbkvm/legacy/remdeskd_cursor_only/main.go
  7. 0 0
      usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/handler.go
  8. 0 0
      usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/hidcomm.go
  9. 0 0
      usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/hidconv.go
  10. 0 0
      usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/remdeshid.go
  11. 0 0
      usbkvm/legacy/remdeskd_cursor_only/mod/usbcapture/usbcapture.go
  12. 0 0
      usbkvm/legacy/remdeskd_cursor_only/mod/usbcapture/video_device.go
  13. 0 0
      usbkvm/legacy/remdeskd_cursor_only/www/index.html
  14. 0 0
      usbkvm/legacy/testcase/go.mod
  15. 0 0
      usbkvm/legacy/testcase/go.sum
  16. 0 0
      usbkvm/legacy/testcase/keyboard_ctrl_alt_del.bat
  17. 0 0
      usbkvm/legacy/testcase/keyboard_delete.bat
  18. 0 0
      usbkvm/legacy/testcase/keyboard_funckey.bat
  19. 0 0
      usbkvm/legacy/testcase/keyboard_modkey.bat
  20. 2 2
      usbkvm/legacy/testcase/keyboard_press.bat
  21. 0 0
      usbkvm/legacy/testcase/keyboard_write.bat
  22. 0 0
      usbkvm/legacy/testcase/main.go
  23. 0 0
      usbkvm/legacy/testcase/mouse_click.bat
  24. 0 0
      usbkvm/legacy/testcase/mouse_home.bat
  25. 0 0
      usbkvm/legacy/testcase/mouse_move.bat
  26. 0 0
      usbkvm/legacy/testcase/mouse_scroll.bat
  27. 0 0
      usbkvm/legacy/usbkvm_fw/keyboard_emu.ino
  28. 0 0
      usbkvm/legacy/usbkvm_fw/mouse_emu.ino
  29. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/HIDClassCommon.h
  30. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/README.txt
  31. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/StdDescriptors.h
  32. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/USBHIDKeyboardMouse.c
  33. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/USBHIDKeyboardMouse.h
  34. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/USBconstant.c
  35. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/USBconstant.h
  36. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/USBhandler.c
  37. 0 0
      usbkvm/legacy/usbkvm_fw/src/remdesHid/USBhandler.h
  38. 0 0
      usbkvm/legacy/usbkvm_fw/usb_switch.ino
  39. 0 0
      usbkvm/legacy/usbkvm_fw/usbkvm_fw.h
  40. 0 0
      usbkvm/legacy/usbkvm_fw/usbkvm_fw.ino
  41. 7 0
      usbkvm/testcase_fw2/go.mod
  42. 4 0
      usbkvm/testcase_fw2/go.sum
  43. 3 0
      usbkvm/testcase_fw2/keyboard_ctrl_alt_del.bat
  44. 6 0
      usbkvm/testcase_fw2/keyboard_funckey.bat
  45. 29 0
      usbkvm/testcase_fw2/keyboard_modkey.bat
  46. 33 0
      usbkvm/testcase_fw2/keyboard_multi_press.bat
  47. 11 0
      usbkvm/testcase_fw2/keyboard_single_press.bat
  48. 67 0
      usbkvm/testcase_fw2/main.go
  49. 11 0
      usbkvm/testcase_fw2/mouse_click.bat
  50. 15 0
      usbkvm/testcase_fw2/mouse_home.bat
  51. 12 0
      usbkvm/testcase_fw2/mouse_move.bat
  52. 6 0
      usbkvm/testcase_fw2/mouse_scroll.bat
  53. 46 0
      usbkvm/usbkvm_fw2/ch9329_utils.ino
  54. 142 18
      usbkvm/usbkvm_fw2/keyboard_emu.ino
  55. 66 44
      usbkvm/usbkvm_fw2/usbkvm_fw2.ino

+ 0 - 0
usbkvm/remdeskd_cursor_only/.vscode/c_cpp_properties.json → usbkvm/legacy/remdeskd_cursor_only/.vscode/c_cpp_properties.json


+ 0 - 0
usbkvm/remdeskd_cursor_only/.vscode/launch.json → usbkvm/legacy/remdeskd_cursor_only/.vscode/launch.json


+ 0 - 0
usbkvm/remdeskd_cursor_only/.vscode/settings.json → usbkvm/legacy/remdeskd_cursor_only/.vscode/settings.json


+ 0 - 0
usbkvm/remdeskd_cursor_only/go.mod → usbkvm/legacy/remdeskd_cursor_only/go.mod


+ 0 - 0
usbkvm/remdeskd_cursor_only/go.sum → usbkvm/legacy/remdeskd_cursor_only/go.sum


+ 0 - 0
usbkvm/remdeskd_cursor_only/main.go → usbkvm/legacy/remdeskd_cursor_only/main.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/mod/remdeshid/handler.go → usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/handler.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/mod/remdeshid/hidcomm.go → usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/hidcomm.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/mod/remdeshid/hidconv.go → usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/hidconv.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/mod/remdeshid/remdeshid.go → usbkvm/legacy/remdeskd_cursor_only/mod/remdeshid/remdeshid.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/mod/usbcapture/usbcapture.go → usbkvm/legacy/remdeskd_cursor_only/mod/usbcapture/usbcapture.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/mod/usbcapture/video_device.go → usbkvm/legacy/remdeskd_cursor_only/mod/usbcapture/video_device.go


+ 0 - 0
usbkvm/remdeskd_cursor_only/www/index.html → usbkvm/legacy/remdeskd_cursor_only/www/index.html


+ 0 - 0
usbkvm/testcase/go.mod → usbkvm/legacy/testcase/go.mod


+ 0 - 0
usbkvm/testcase/go.sum → usbkvm/legacy/testcase/go.sum


+ 0 - 0
usbkvm/testcase/keyboard_ctrl_alt_del.bat → usbkvm/legacy/testcase/keyboard_ctrl_alt_del.bat


+ 0 - 0
usbkvm/testcase/keyboard_delete.bat → usbkvm/legacy/testcase/keyboard_delete.bat


+ 0 - 0
usbkvm/testcase/keyboard_funckey.bat → usbkvm/legacy/testcase/keyboard_funckey.bat


+ 0 - 0
usbkvm/testcase/keyboard_modkey.bat → usbkvm/legacy/testcase/keyboard_modkey.bat


+ 2 - 2
usbkvm/testcase/keyboard_press.bat → usbkvm/legacy/testcase/keyboard_press.bat

@@ -1,9 +1,9 @@
 @echo off
 :: Press CAPS LOCK twice with a delay of 3 seconds between each press
 echo "Pressing CAPS LOCK"
-send.exe COM4 115200 0x01 0x07 0xC1 0x01 0x08 0xC1
+send.exe COM3 115200 0x01 0x07 0xC1 0x01 0x08 0xC1
 
 timeout /t 3 /nobreak >nul
 
 echo "Pressing CAPS LOCK again"
-send.exe COM4 115200 0x01 0x07 0xC1 0x01 0x08 0xC1
+send.exe COM3 115200 0x01 0x07 0xC1 0x01 0x08 0xC1

+ 0 - 0
usbkvm/testcase/keyboard_write.bat → usbkvm/legacy/testcase/keyboard_write.bat


+ 0 - 0
usbkvm/testcase/main.go → usbkvm/legacy/testcase/main.go


+ 0 - 0
usbkvm/testcase/mouse_click.bat → usbkvm/legacy/testcase/mouse_click.bat


+ 0 - 0
usbkvm/testcase/mouse_home.bat → usbkvm/legacy/testcase/mouse_home.bat


+ 0 - 0
usbkvm/testcase/mouse_move.bat → usbkvm/legacy/testcase/mouse_move.bat


+ 0 - 0
usbkvm/testcase/mouse_scroll.bat → usbkvm/legacy/testcase/mouse_scroll.bat


+ 0 - 0
usbkvm/usbkvm_fw/keyboard_emu.ino → usbkvm/legacy/usbkvm_fw/keyboard_emu.ino


+ 0 - 0
usbkvm/usbkvm_fw/mouse_emu.ino → usbkvm/legacy/usbkvm_fw/mouse_emu.ino


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/HIDClassCommon.h → usbkvm/legacy/usbkvm_fw/src/remdesHid/HIDClassCommon.h


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/README.txt → usbkvm/legacy/usbkvm_fw/src/remdesHid/README.txt


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/StdDescriptors.h → usbkvm/legacy/usbkvm_fw/src/remdesHid/StdDescriptors.h


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/USBHIDKeyboardMouse.c → usbkvm/legacy/usbkvm_fw/src/remdesHid/USBHIDKeyboardMouse.c


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/USBHIDKeyboardMouse.h → usbkvm/legacy/usbkvm_fw/src/remdesHid/USBHIDKeyboardMouse.h


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/USBconstant.c → usbkvm/legacy/usbkvm_fw/src/remdesHid/USBconstant.c


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/USBconstant.h → usbkvm/legacy/usbkvm_fw/src/remdesHid/USBconstant.h


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/USBhandler.c → usbkvm/legacy/usbkvm_fw/src/remdesHid/USBhandler.c


+ 0 - 0
usbkvm/usbkvm_fw/src/remdesHid/USBhandler.h → usbkvm/legacy/usbkvm_fw/src/remdesHid/USBhandler.h


+ 0 - 0
usbkvm/usbkvm_fw/usb_switch.ino → usbkvm/legacy/usbkvm_fw/usb_switch.ino


+ 0 - 0
usbkvm/usbkvm_fw/usbkvm_fw.h → usbkvm/legacy/usbkvm_fw/usbkvm_fw.h


+ 0 - 0
usbkvm/usbkvm_fw/usbkvm_fw.ino → usbkvm/legacy/usbkvm_fw/usbkvm_fw.ino


+ 7 - 0
usbkvm/testcase_fw2/go.mod

@@ -0,0 +1,7 @@
+module imuslab.com/remdes/send
+
+go 1.24.1
+
+require github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
+
+require golang.org/x/sys v0.31.0 // indirect

+ 4 - 0
usbkvm/testcase_fw2/go.sum

@@ -0,0 +1,4 @@
+github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
+github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
+golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
+golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=

+ 3 - 0
usbkvm/testcase_fw2/keyboard_ctrl_alt_del.bat

@@ -0,0 +1,3 @@
+@echo off
+:: Press Ctrl + Alt + Del
+.\send.exe COM3 115200 0xFF 0x02 0x03 0x09 0x02 0x01 0x2E 0x02 0x02 0x2E 0x02 0x03 0x00

+ 6 - 0
usbkvm/testcase_fw2/keyboard_funckey.bat

@@ -0,0 +1,6 @@
+@echo off
+:: Press F11
+echo "Pressing F11"
+send.exe COM3 115200 0x02 0x01 0x7A 0x02 0x02 0x7A
+
+

+ 29 - 0
usbkvm/testcase_fw2/keyboard_modkey.bat

@@ -0,0 +1,29 @@
+@echo off
+:: Hold Shift via HID keys
+.\send.exe COM3 115200 0xFF
+
+echo "Holding Ctrl"
+.\send.exe COM3 115200 0x02 0x03 0x01
+timeout /t 1 /nobreak >nul
+
+echo "Releasing Ctrl"
+.\send.exe COM3 115200 0x02 0x04 0x01
+timeout /t 1 /nobreak >nul
+
+
+echo "Pressing Win key"
+.\send.exe COM3 115200 0x02 0x03 0x04 0x02 0x04 0x04
+timeout /t 1 /nobreak >nul
+
+
+echo "Pressing Shift + A"
+.\send.exe COM3 115200 0x02 0x03 0x02 0x02 0x01 0x41 
+timeout /t 1 /nobreak >nul
+.\send.exe COM3 115200 0x02 0x02 0x41 0x02 0x04 0x02
+
+echo "Testing combo modkeys"
+.\send.exe COM3 115200 0x02 0x03 0x09 
+timeout /t 1 /nobreak >nul
+.\send.exe COM3 115200 0x02 0x04 0x01
+timeout /t 1 /nobreak >nul
+.\send.exe COM3 115200 0x02 0x04 0x03

+ 33 - 0
usbkvm/testcase_fw2/keyboard_multi_press.bat

@@ -0,0 +1,33 @@
+@echo off
+
+echo "Testing 6 key presses"
+.\send.exe COM3 115200 0xFF
+timeout /t 1 /nobreak >nul
+
+echo "Pressing A"
+.\send.exe COM3 115200 0x02 0x01 0x41
+echo "Pressing B"
+.\send.exe COM3 115200 0x02 0x01 0x42
+echo "Pressing C"
+.\send.exe COM3 115200 0x02 0x01 0x43
+echo "Pressing D"
+.\send.exe COM3 115200 0x02 0x01 0x44
+echo "Pressing E"
+.\send.exe COM3 115200 0x02 0x01 0x45
+echo "Pressing F"
+.\send.exe COM3 115200 0x02 0x01 0x46
+timeout /t 1 /nobreak >nul
+
+echo "Releasing A"
+.\send.exe COM3 115200 0x02 0x02 0x41
+echo "Releasing B"
+.\send.exe COM3 115200 0x02 0x02 0x42
+echo "Releasing C"
+.\send.exe COM3 115200 0x02 0x02 0x43
+echo "Releasing D"
+.\send.exe COM3 115200 0x02 0x02 0x44
+echo "Releasing E"
+.\send.exe COM3 115200 0x02 0x02 0x45
+echo "Releasing F"
+.\send.exe COM3 115200 0x02 0x02 0x46
+timeout /t 1 /nobreak >nul

+ 11 - 0
usbkvm/testcase_fw2/keyboard_single_press.bat

@@ -0,0 +1,11 @@
+@echo off
+
+.\send.exe COM3 115200 0xFF
+timeout /t 1 /nobreak >nul
+
+echo "Pressing A"
+.\send.exe COM3 115200 0x02 0x01 0x41
+timeout /t 1 /nobreak >nul
+
+echo "Releasing A"
+.\send.exe COM3 115200 0x02 0x02 0x41

+ 67 - 0
usbkvm/testcase_fw2/main.go

@@ -0,0 +1,67 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"strconv"
+	"time"
+
+	"github.com/tarm/serial"
+)
+
+func main() {
+	if len(os.Args) < 4 {
+		log.Fatalf("Usage: %s <port> <baud> <data...>", os.Args[0])
+	}
+
+	portName := os.Args[1]
+	baudRate, err := strconv.Atoi(os.Args[2])
+	if err != nil {
+		log.Fatalf("Invalid baud rate: %v", err)
+	}
+
+	config := &serial.Config{
+		Name:   portName,
+		Baud:   baudRate,
+		Size:   8,
+		Parity: serial.ParityNone,
+	}
+
+	port, err := serial.OpenPort(config)
+	if err != nil {
+		log.Fatalf("Failed to open port: %v", err)
+	}
+	defer port.Close()
+
+	go func() {
+		buf := make([]byte, 128)
+		for {
+			n, err := port.Read(buf)
+			if err != nil {
+				log.Printf("Failed to read from port: %v", err)
+				return
+			}
+			if n > 0 {
+				fmt.Print("Received bytes: ")
+				for i := 0; i < n; i++ {
+					fmt.Printf("0x%02X ", buf[i])
+				}
+				fmt.Println()
+			}
+		}
+	}()
+
+	for _, arg := range os.Args[3:] {
+		data, err := strconv.ParseUint(arg, 0, 8)
+		if err != nil {
+			log.Fatalf("Invalid data byte: %v", err)
+		}
+		n, err := port.Write([]byte{byte(data)})
+		if err != nil {
+			log.Fatalf("Failed to write to port: %v", err)
+		}
+		fmt.Printf("Sent %d bytes to %s\n", n, portName)
+		time.Sleep(10 * time.Millisecond)
+	}
+}

+ 11 - 0
usbkvm/testcase_fw2/mouse_click.bat

@@ -0,0 +1,11 @@
+@echo off
+:: Hold the left mouse button for 3 seconds
+.\send.exe COM4 115200 0x02 0x02 0x01
+timeout /t 3 /nobreak >nul
+.\send.exe COM4 115200 0x02 0x03 0x01
+timeout /t 3 /nobreak >nul
+:: Do a right click
+.\send.exe COM4 115200 0x02 0x01 0x02
+timeout /t 3 /nobreak >nul
+:: Do a middle click
+.\send.exe COM4 115200 0x02 0x01 0x03

+ 15 - 0
usbkvm/testcase_fw2/mouse_home.bat

@@ -0,0 +1,15 @@
+@echo off
+:: Move cursor to the top left corner
+.\send.exe COM4 115200 0x02 0x04 0x00
+timeout /t 3 /nobreak >nul
+
+:: Move cursor to the bottom left corner
+.\send.exe COM4 115200 0x02 0x04 0x01
+timeout /t 3 /nobreak >nul
+
+:: Move cursor to the top left corner
+.\send.exe COM4 115200 0x02 0x04 0x02
+timeout /t 3 /nobreak >nul
+
+:: Move cursor to the bottom right corner
+.\send.exe COM4 115200 0x02 0x04 0x03

+ 12 - 0
usbkvm/testcase_fw2/mouse_move.bat

@@ -0,0 +1,12 @@
+@echo off
+:: Move down x_value, y_value, x_positive, y_positive
+.\send.exe COM4 115200 0x03 0x00 0x80 0x00 0x00
+timeout /t 1 /nobreak >nul
+:: Move up
+.\send.exe COM4 115200 0x03 0x00 0x80 0x00 0x01
+timeout /t 1 /nobreak >nul
+:: Move right
+.\send.exe COM4 115200 0x03 0x80 0x00 0x00 0x00
+timeout /t 1 /nobreak >nul
+:: Move left
+.\send.exe COM4 115200 0x03 0x80 0x00 0x01 0x00

+ 6 - 0
usbkvm/testcase_fw2/mouse_scroll.bat

@@ -0,0 +1,6 @@
+@echo off
+:: Scroll up (Tested on Windows)
+.\send.exe COM4 115200 0x04 0x00 0x02
+timeout /t 3 /nobreak >nul
+:: Scroll down
+.\send.exe COM4 115200 0x04 0x01 0x02

+ 46 - 0
usbkvm/usbkvm_fw2/ch9329_utils.ino

@@ -0,0 +1,46 @@
+// Checksum = sum of all bytes except last
+uint8_t calcChecksum(uint8_t* data, uint8_t len) {
+  uint8_t sum = 0;
+  for (uint8_t i = 0; i < len; i++) sum += data[i];
+  return sum;
+}
+
+// Helper to write an array of uint8_t to CH9329
+void Serial0_writeBuf(const uint8_t* data, uint8_t len) {
+  for (uint8_t i = 0; i < len; i++) {
+    Serial0_write(data[i]);
+  }
+}
+
+// flush the serial RX (blocking)
+void flush_cmd_resp() {
+  delay(100);
+  while (Serial0_available()) {
+    uint8_t b = Serial0_read();
+    USBSerial_print("0x");
+    if (b < 0x10) USBSerial_print("0");
+    USBSerial_print(b, HEX);
+    USBSerial_print(" ");
+  }
+  USBSerial_println("");
+}
+
+// Send a CH9329 cmd via UART0
+void send_cmd(uint8_t cmd, uint8_t* data, uint8_t length) {
+  uint8_t sum = 0;
+  Serial0_write(0x57);
+  sum += 0x57;
+  Serial0_write(0xAB);
+  sum += 0xAB;
+  Serial0_write(0x00);
+
+  Serial0_write(cmd);
+  sum += cmd;
+  Serial0_write(length);
+  sum += length;
+  for (int i = 0; i < length; i++) {
+    Serial0_write(data[i]);
+    sum += data[i];
+  }
+  Serial0_write(sum);
+}

+ 142 - 18
usbkvm/usbkvm_fw2/keyboard_emu.ino

@@ -3,8 +3,8 @@
 
   This file handle keyboard emulation and key writes
 */
-#define MAX_KEYBOARD_HID_KEYCODE_NO 6
-#define ENABLE_KEYBOARD_DEBUG_PRINTOUT
+#define KEYBOARD_HID_KEYCODE_LENGTH 6
+//#define ENABLE_KEYBOARD_DEBUG_PRINTOUT
 
 /* Modifier keycode for CH9329 */
 #define MOD_LCTRL 0x01
@@ -17,7 +17,9 @@
 #define MOD_RGUI 0x80
 
 /* Runtime variables */
-uint8_t keyboard_state[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+uint8_t keyboard_state[KEYBOARD_HID_KEYCODE_LENGTH] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+uint8_t keyboard_pressing_key_count = 0;  //No. of key currently pressing, max is 6
+uint8_t keyboard_modifiers = 0x00;        //Current modifier key state
 
 //byte 0: Computer connected
 //byte 1:
@@ -58,25 +60,20 @@ void handle_keyboard_get_info_reply() {
 #endif
 }
 
-/* helper to write an array of uint8_t to CH9329 */
-void Serial0_writeBuf(const uint8_t* data, uint8_t len) {
-  for (uint8_t i = 0; i < len; i++) {
-    Serial0_write(data[i]);
-  }
-}
-
-/* Send key combinations, keycode must be an array with length 6 */
-int keyboard_send_key_combinations(uint8_t modifiers, uint8_t* keycode, uint8_t length) {
-  if (length != MAX_KEYBOARD_HID_KEYCODE_NO) {
-    //This function must take in an array of 6 keycodes
-    return -1;
-  }
+/* Send key combinations to CH9329*/
+int keyboard_send_key_combinations() {
   uint8_t packet[14] = {
     0x57, 0xAB, 0x00, 0x02, 0x08,
-    modifiers, 0x00,
-    keycode[0], keycode[1], keycode[2], keycode[3], keycode[4], keycode[5],
+    keyboard_modifiers, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     0x00
   };
+
+  //Populate the HID keycodes
+  for (uint8_t i = 0; i < KEYBOARD_HID_KEYCODE_LENGTH; i++) {
+    packet[7 + i] = keyboard_state[i];
+  }
+
   packet[13] = calcChecksum(packet, 13);
   Serial0_writeBuf(packet, 14);
   return 0;
@@ -224,4 +221,131 @@ uint8_t javascript_keycode_to_hid_opcode(uint8_t keycode) {
     default:
       return 0x00;  // Unknown / unsupported
   }
+}
+
+//Send a keyboard press by JavaScript keycode
+int keyboard_press_key(uint8_t keycode) {
+  //Convert javascript keycode to HID
+  keycode = javascript_keycode_to_hid_opcode(keycode);
+  if (keycode == 0x00) {
+    //Not supported
+    return -1;
+  }
+
+  // Already pressed? Skip
+  for (int i = 0; i < 6; i++) {
+    if (keyboard_state[i] == keycode) {
+      return 0;  // Already held
+    }
+  }
+
+  //Get the empty slot in the current HID list
+  for (int i = 0; i < 6; i++) {
+    if (keyboard_state[i] == 0x00) {
+      keyboard_state[i] = keycode;
+      keyboard_pressing_key_count++;
+      keyboard_send_key_combinations();
+      return 0;
+    }
+  }
+
+  //No space left
+  return -1;
+}
+
+//Send a keyboard release by JavaScript keycode
+int keyboard_release_key(uint8_t keycode) {
+  //Convert javascript keycode to HID
+  keycode = javascript_keycode_to_hid_opcode(keycode);
+  if (keycode == 0x00) {
+    //Not supported
+    return -1;
+  }
+
+  //Get the position where the key is pressed
+  for (int i = 0; i < 6; i++) {
+    if (keyboard_state[i] == keycode) {
+      keyboard_state[i] = 0x00;
+      if (keyboard_pressing_key_count > 0) {
+        keyboard_pressing_key_count--;
+      }
+      keyboard_send_key_combinations();
+      return 0;
+    }
+  }
+
+  //That key is not pressed
+  return 0;
+}
+
+uint8_t keyboard_get_modifier_bit_from_opcode(uint8_t opcode) {
+  switch (opcode) {
+    case 0x01:
+      return MOD_LCTRL;
+    case 0x02:
+      return MOD_LSHIFT;
+    case 0x03:
+      return MOD_LALT;
+    case 0x04:
+      return MOD_LGUI;
+    case 0x05:
+      return MOD_RCTRL;
+    case 0x06:
+      return MOD_RSHIFT;
+    case 0x07:
+      return MOD_RALT;
+    case 0x08:
+      return MOD_RGUI;
+    case 0x09:
+      //Ctrl + Alt + Del
+      return MOD_LCTRL | MOD_LALT;
+    case 0x0A:
+      //Win + Shift + S
+      return MOD_LSHIFT | MOD_LGUI;
+      break;
+    //To be added
+    default:
+      return 0x00;
+  }
+}
+
+//Set the modifier key bit
+int keyboard_press_modkey(uint8_t opcode) {
+  if (opcode == 0x00){
+    //Reset the modkeys
+    keyboard_modifiers = 0;
+    keyboard_send_key_combinations();
+    return 0;
+  }
+  uint8_t mask = keyboard_get_modifier_bit_from_opcode(opcode);
+  if (mask == 0x00){
+    return -1;
+  }
+  keyboard_modifiers |= mask;
+  keyboard_send_key_combinations();
+  return 0;
+}
+
+//Unset modifier key bit
+int keyboard_release_modkey(uint8_t opcode) {
+  if (opcode == 0x00){
+    //Reset the modkeys
+    keyboard_modifiers = 0;
+    keyboard_send_key_combinations();
+    return 0;
+  }
+  uint8_t mask = keyboard_get_modifier_bit_from_opcode(opcode);
+  if (mask == 0x00){
+    return -1;
+  }
+  keyboard_modifiers &= ~mask;
+  keyboard_send_key_combinations();
+  return 0;
+}
+
+//Reset all keypress on keyboard
+void keyboard_reset(){
+  memset(keyboard_state, 0x00, sizeof(keyboard_state));
+  keyboard_modifiers = 0x00;
+  keyboard_send_key_combinations();
 }

+ 66 - 44
usbkvm/usbkvm_fw2/usbkvm_fw2.ino

@@ -12,56 +12,31 @@
 
 #define MAX_CMD_LEN 32
 
+//Recv buffer from control software
 uint8_t cmdBuf[MAX_CMD_LEN];
 uint8_t cmdIndex = 0;
-//Buffer and state machine for CH9329 UART COMM
+uint8_t cmdMaxLen = 0;  //Expected length of the LTV command
+//Recv buffer from CH9329
 uint8_t kbCmdBuf[MAX_CMD_LEN];
 uint8_t kbCmdIndex = 0;
 uint8_t kbCmdCounter = MAX_CMD_LEN;  //How many index left to terminate
 
 /* Function Prototypes */
+//ch9329_utils.ino
+void send_cmd(uint8_t cmd, uint8_t* data, uint8_t length);
+void flush_cmd_resp();
+
+//keyboard_emu.ino
 void keyboard_get_info();
+void keyboard_reset(); 
 void handle_keyboard_get_info_reply();
+int keyboard_press_key(uint8_t keycode);
+int keyboard_release_key(uint8_t keycode);
+int keyboard_press_modkey(uint8_t opcode);
+int keyboard_release_modkey(uint8_t opcode);
 
-// Checksum = sum of all bytes except last
-uint8_t calcChecksum(uint8_t* data, uint8_t len) {
-  uint8_t sum = 0;
-  for (uint8_t i = 0; i < len; i++) sum += data[i];
-  return sum;
-}
-
-// flush the serial RX
-void flush_cmd_resp() {
-  delay(100);
-  while (Serial0_available()) {
-    uint8_t b = Serial0_read();
-    USBSerial_print("0x");
-    if (b < 0x10) USBSerial_print("0");
-    USBSerial_print(b, HEX);
-    USBSerial_print(" ");
-  }
-  USBSerial_println("");
-}
-
-void send_cmd(uint8_t cmd, uint8_t* data, uint8_t length) {
-  uint8_t sum = 0;
-  Serial0_write(0x57);
-  sum += 0x57;
-  Serial0_write(0xAB);
-  sum += 0xAB;
-  Serial0_write(0x00);
-
-  Serial0_write(cmd);
-  sum += cmd;
-  Serial0_write(length);
-  sum += length;
-  for (int i = 0; i < length; i++) {
-    Serial0_write(data[i]);
-    sum += data[i];
-  }
-  Serial0_write(sum);
-}
 
+// Set the USB descriptor exposed to the slave device
 void setup_keyboard_chip_cfg() {
   //Set manufacturer string
   uint8_t manufacturer_string[9] = { 0x00, 0x07, 'i', 'm', 'u', 's', 'l', 'a', 'b' };
@@ -73,7 +48,7 @@ void setup_keyboard_chip_cfg() {
   flush_cmd_resp();
 }
 
-//This function will trigger the target handler to handle the buffer data in kbCmdBuf
+//This function will trigger the target handler to handle the buffer data recv from CH9329
 void handle_cmd_processing(uint8_t cmd) {
   switch (cmd) {
     case 0x81:
@@ -86,6 +61,33 @@ void handle_cmd_processing(uint8_t cmd) {
   }
 }
 
+//This function will handle the incoming cmd from RemdesKVM control software
+void handle_ctrl_cmd() {
+  uint8_t cmd = cmdBuf[1];    //Type of operation
+  uint8_t value = cmdBuf[2];  //values for 2 bytes cmd
+  switch (cmd) {
+    case 0x01:
+      //keyboard press
+      keyboard_press_key(value);
+      break;
+    case 0x02:
+      //keyboard release
+      keyboard_release_key(value);
+      break;
+    case 0x03:
+      //keyboard modifier key press
+      keyboard_press_modkey(value);
+      break;
+    case 0x04:
+      //keyboard modifier key release
+      keyboard_release_modkey(value);
+      break;
+    default:
+      //unknown operation, do nothing
+      break;
+  }
+}
+
 void setup() {
   USBSerial_println("Ready");
   Serial0_begin(9600);  // CH9329 UART default baudd
@@ -97,13 +99,33 @@ void loop() {
   // Read characters into buffer
   while (USBSerial_available()) {
     uint8_t c = USBSerial_read();
-    USBSerial_println(c);
-    if (c == 'k') {
-      keyboard_get_info();
+    if (c == 0xFF) {
+      //Reset
+      keyboard_reset();
+      memset(cmdBuf, 0, sizeof(cmdBuf));
+      cmdIndex = 0;
+      cmdMaxLen = 0;
+      continue;
+    }
+
+    if (cmdIndex == 0) {
+      //This is the length value
+      cmdMaxLen = c + 1;
+    }
+    cmdBuf[cmdIndex] = c;
+    cmdIndex++;
+    cmdMaxLen--;
+    if (cmdMaxLen == 0) {
+      //End of ctrl cmd, handle it
+      handle_ctrl_cmd();
+
+      //Clear ctrl cmd buf
+      memset(cmdBuf, 0, sizeof(cmdBuf));
+      cmdIndex = 0;
+      cmdMaxLen = 0;
     }
   }
 
-  // Debug: Echo CH9329 response
   while (Serial0_available()) {
     uint8_t b = Serial0_read();
     if (b == 0x57) {