You are not logged in.

#1 2026-05-09 12:15:00

DirtPeasant
Member
Registered: 2026-05-09
Posts: 1

Multi HID spacemouse not working correctly on arch.

Hi, I built the device from https://github.com/sb-ocr/cad-mouse-mk2. Specifically using most of the firmware from here: https://github.com/lenkaiser/cad-mouse-mk2 (with some modifications to make the following work).
The rest of the device is the same as stated in there ^.
With spacenavd from aur the spacemouse portion of it works in blender. It works a bit weirdly, but those are more weird defaults for spacenavd.
I have a work laptop with windows, so I am able to test the device on there as well.

I wanted to also be able to use it as a mouse and 2 joysticks (for the fun of it), using the side buttons as mode switches.
Slight issue, arch does not seem to be able to "use" the input of the device as a mouse or controller, somehow it only seems to be able to use the Space-mouse portion of it.
If all 3 HID's are enabled they also don't all show up in dmesg, it will only ever show me 2 out of the 3, any less and it will show me exactly the ones i enabled (enabled as in "did not comment out in the code").
When testing the mouse portion back on windows it does work correctly, like i can move the mouse and everything.
But both the mouse portion and controller portion refuse to work back on arch, steam does recognize it as a controller, but receives no input.

This is what dmesg tells me:

[10680.844315] usb 1-2.4: new full-speed USB device number 52 using xhci_hcd
[10681.147425] usb 1-2.4: New USB device found, idVendor=[REDACTED], idProduct=[REDACTED], bcdDevice= 1.00
[10681.147435] usb 1-2.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[10681.147437] usb 1-2.4: Product: [REDACTED]
[10681.147439] usb 1-2.4: Manufacturer: Seeed Studio
[10681.147441] usb 1-2.4: SerialNumber: 4250304B38353816
[10681.182341] cdc_acm 1-2.4:1.0: ttyACM1: USB ACM device
[10681.182836] input: Seeed Studio [REDACTED] as /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:10:00.0/usb1/1-2/1-2.4/1-2.4:1.2/0003:2E8A:000A.003A/input/input145
[10681.182892] hid-generic 0003:2E8A:000A.003A: input,hidraw3: USB HID v1.11 Multi-Axis Controller [Seeed Studio [REDACTED]] on usb-0000:10:00.0-2.4/input2
[10681.183756] input: Seeed Studio [REDACTED] as /devices/pci0000:00/0000:00:02.1/0000:05:00.0/0000:06:0c.0/0000:10:00.0/usb1/1-2/1-2.4/1-2.4:1.3/0003:2E8A:000A.003B/input/input146
[10681.183804] hid-generic 0003:2E8A:000A.003B: input,hidraw4: USB HID v1.11 Mouse [Seeed Studio [REDACTED]] on usb-0000:10:00.0-2.4/input3
[10682.403795] input: Microsoft X-Box 360 pad 0 as /devices/virtual/input/input147

What lsusb tells me:

Bus 001 Device 052: ID 2e8a:000a Seeed Studio [REDACTED]

The modified HIDController.cpp file:

#include "controllers/HIDController.h"

#include <math.h>

#include "Config.h"

namespace {
const uint8_t kHidReportDescriptor[] PROGMEM = {
    0x05, 0x01,        // USAGE_PAGE (Generic Desktop)
    0x09, 0x08,        // USAGE (Multi-axis Controller)
    0xA1, 0x01,        // COLLECTION (Application)
    0xA1, 0x00,        // COLLECTION (Physical)
    0x85, 0x01,        // REPORT_ID (1)
    0x16, 0xA2, 0xFE,  // LOGICAL_MINIMUM  (-350)
    0x26, 0x5E, 0x01,  // LOGICAL_MAXIMUM  (350)
    0x09, 0x30,        // USAGE (X)
    0x09, 0x31,        // USAGE (Y)
    0x09, 0x32,        // USAGE (Z)
    0x09, 0x33,        // USAGE (Rx)
    0x09, 0x34,        // USAGE (Ry)
    0x09, 0x35,        // USAGE (Rz)
    0x75, 0x10,        // REPORT_SIZE (16)
    0x95, 0x06,        // REPORT_COUNT (6)
    0x81, 0x02,        // INPUT (Data,Var,Abs)
    0xC0,              // END_COLLECTION
    0xA1, 0x00,        // COLLECTION (Physical)
    0x85, 0x03,        // REPORT_ID (3)
    0x05, 0x09,        // USAGE_PAGE (Button)
    0x19, 0x01,        // USAGE_MINIMUM (Button 1)
    0x29, 0x02,        // USAGE_MAXIMUM (Button 2)
    0x15, 0x00,        // LOGICAL_MINIMUM (0)
    0x25, 0x01,        // LOGICAL_MAXIMUM (1)
    0x75, 0x01,        // REPORT_SIZE (1)
    0x95, 0x02,        // REPORT_COUNT (2)
    0x81, 0x02,        // INPUT (Data,Var,Abs)
    0x95, 0x0E,        // REPORT_COUNT (14) padding
    0x81, 0x01,        // INPUT (Const,Array,Abs)
    0xC0,              // END_COLLECTION
    0xC0               // END_COLLECTION
};
}

uint8_t const desc_mouse_report[] = {
    TUD_HID_REPORT_DESC_MOUSE()
};

uint8_t const desc_controller_report[] = {
    TUD_HID_REPORT_DESC_GAMEPAD()
};

void HIDController::begin() {
  if (!TinyUSBDevice.isInitialized()) {
    TinyUSBDevice.begin(0);
  }

  usbHid_Spacemouse.setReportDescriptor(kHidReportDescriptor, sizeof(kHidReportDescriptor));
  usbHid_Spacemouse.setPollInterval(3);
  usbHid_Spacemouse.begin();

  usbHid_Mouse.setPollInterval(3);
  usbHid_Mouse.setBootProtocol(HID_ITF_PROTOCOL_MOUSE);
  usbHid_Mouse.setReportDescriptor(desc_mouse_report, sizeof(desc_mouse_report));
  usbHid_Mouse.setStringDescriptor("Spacemouse - Mouse mode");
  usbHid_Mouse.begin();

  usbHid_Controller.setPollInterval(3);
  usbHid_Controller.setReportDescriptor(desc_controller_report, sizeof(desc_controller_report));
  usbHid_Controller.setStringDescriptor("Spacemouse - Controller mode");
  usbHid_Controller.begin();

  if (TinyUSBDevice.mounted()) {
    TinyUSBDevice.detach();
    delay(10);
    TinyUSBDevice.attach();
  }
}

void HIDController::task() { TinyUSBDevice.task(); }

HIDController::ReportAxes HIDController::makeAxesReport(const float motion[6]) {
  ReportAxes axes{}; //the first side mentioned is the positive value side.
  axes.x = static_cast<int16_t>(motion[0]); //move left and right
  axes.y = static_cast<int16_t>(motion[1]); //move forward and backwards
  axes.z = static_cast<int16_t>(motion[2]); //move up and down
  axes.rx = static_cast<int16_t>(motion[3]); //rotate forward and backwards
  axes.ry = static_cast<int16_t>(motion[4]); //rotate right and left
  axes.rz = static_cast<int16_t>(motion[5]); //rotate counterclockwise and clockwise
  return axes;
}

bool HIDController::axesReportChanged(const ReportAxes& axes) const {
  return axes.x != lastSentAxes_.x ||
         axes.y != lastSentAxes_.y ||
         axes.z != lastSentAxes_.z ||
         axes.rx != lastSentAxes_.rx ||
         axes.ry != lastSentAxes_.ry ||
         axes.rz != lastSentAxes_.rz;
}

bool HIDController::sendReports(const float motion[6], uint16_t buttonBits) {
  const ReportAxes axes = makeAxesReport(motion);
  const bool sendAxes = axesReportChanged(axes);
  const bool sendButtons = (buttonBits != buttonBitsSent_);

  if (!sendAxes || !TinyUSBDevice.mounted()) {//!usbHid_Spacemouse.ready()
    return false;
  }

  if (sendAxes) {
    switch (CurrentMode)
    {
    case 1:
      if (!usbHid_Spacemouse.ready()) 
      {
        return false;
      }
      usbHid_Spacemouse.sendReport(0x01, &axes, sizeof(axes));
      //Serial.println("Sent spacemouse movement");
      break;
    case 2:
    if (!usbHid_Mouse.ready()) 
      {
        return false;
      }
      usbHid_Mouse.mouseMove(0, (int8_t)(motion[4]*mul_fac), (int8_t)(motion[3]*mul_fac));
      // Serial.println("Sent mouse movement");
      break;
    case 3:
      if (!usbHid_Controller.ready()) 
      {
        return false;
      }
      gp.x = (int8_t)(motion[1]*mul_fac);
      gp.y = (int8_t)(motion[0]*mul_fac);
      gp.z = (int8_t)(motion[4]*mul_fac);
      gp.rz = (int8_t)(motion[3]*mul_fac);
      usbHid_Controller.sendReport(0, &gp, sizeof(gp));
      // Serial.println((int8_t)(motion[3]*mul_fac));
      break;
    default:
      break;
    }
    lastSentAxes_ = axes;
  }

  if (sendButtons && buttonBits > 0) {
    CurrentMode = (short)buttonBits;
    if(buttonBits == 3){
      delay(1000);
    }
    /*
    ReportButtons btn{};
    btn.bits = buttonBits & 0x0003;
    usbHid_Spacemouse.sendReport(0x03, &btn, sizeof(btn));
    */
    buttonBitsSent_ = buttonBits;
  }

  return true;
}
 

The modified HIDController.h file:

#pragma once

#include <Adafruit_TinyUSB.h>
#include <Arduino.h>

class HIDController {
 public:
  void begin();
  void task();
  bool sendReports(const float motion[6], uint16_t buttonBits);

 private:
  struct __attribute__((packed)) ReportAxes {
    int16_t x, y, z, rx, ry, rz;
  };

  struct __attribute__((packed)) ReportButtons {
    uint16_t bits;
  };

  static ReportAxes makeAxesReport(const float motion[6]);
  bool axesReportChanged(const ReportAxes& axes) const;

  Adafruit_USBD_HID usbHid_Spacemouse;
  const float mul_fac = 0.3;//(sizeof(int8_t)/350);
  Adafruit_USBD_HID usbHid_Mouse;
  Adafruit_USBD_HID usbHid_Controller;
  hid_gamepad_report_t gp;
  uint16_t buttonBitsSent_ = 0;
  ReportAxes lastSentAxes_{};
  short CurrentMode = 1; //1 = spacemouse, 2 = mouse, 3 = controller
};

The status of systemctl spacenavd.service:

● spacenavd.service - Spacenav driver daemon
     Loaded: loaded (/usr/lib/systemd/system/spacenavd.service; enabled; preset: disabled)
     Active: active (running) since Sat 2026-05-09 11:00:01 CEST; 3h 10min ago
 Invocation: 4c63bf3497604be39fc0263af8d7190a
   Main PID: 968 (spacenavd)
      Tasks: 1 (limit: 74184)
     Memory: 2.2M (peak: 3.2M)
        CPU: 165ms
     CGroup: /system.slice/spacenavd.service
             └─968 /usr/bin/spacenavd

May 09 11:00:01 [REDACTED] systemd[1]: Starting Spacenav driver daemon...
May 09 11:00:01 [REDACTED] systemd[1]: Started Spacenav driver daemon.

I don't really know what to do at this point. am i missing udev rules to make this work correctly or what could be the problem?

Offline

Board footer

Powered by FluxBB