Wireless device detection, and CadMouse avoidance logic

New 3dconnexion devices seem to all use the same dongle with USB id
256f:c526. That includes at least the SpaceMouse Wireless and the
CadMouse Wireless. This is a set of hacks to guess what's connected
and act accordingly:

  - Drop the CadMouse (num_axes == 0)
  - Enable the button hack if it's a SpaceMouse Pro Wireless
  - Detect SpaceMouse Wirless and update name/type.

Also added a test for the assumption that devices marked for button
remapping always report 255-256 buttons. If that's not the case undo the
button-hack and ask the user to report it as a bug.
pull/65/head
John Tsiombikas 2022-08-26 16:39:26 +03:00
rodzic 21d90d0db6
commit 3e1cbc52ef
3 zmienionych plików z 58 dodań i 23 usunięć

Wyświetl plik

@ -35,8 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif #endif
#define VENDOR_3DCONNEXION 0x256f
/* The device flags are introduced to normalize input across all known /* The device flags are introduced to normalize input across all known
* supported 6dof devices. Newer USB devices seem to use axis 1 as fwd/back and * supported 6dof devices. Newer USB devices seem to use axis 1 as fwd/back and
* axis 2 as up/down, while older serial devices (and possibly also the early * axis 2 as up/down, while older serial devices (and possibly also the early
@ -57,9 +55,6 @@ enum {
* actual buttons when a negative number is passed as argument, and the button * actual buttons when a negative number is passed as argument, and the button
* mapping otherwise. * mapping otherwise.
*/ */
int bnhack_smpro(int bn);
int bnhack_sment(int bn);
static struct usbdb_entry { static struct usbdb_entry {
int usbid[2]; int usbid[2];
int type; int type;
@ -76,7 +71,7 @@ static struct usbdb_entry {
{{0x046d, 0xc627}, DEV_SEXP, DF_SWAPYZ | DF_INVYZ, 0}, /* space explorer */ {{0x046d, 0xc627}, DEV_SEXP, DF_SWAPYZ | DF_INVYZ, 0}, /* space explorer */
{{0x046d, 0xc628}, DEV_SNAVNB, DF_SWAPYZ | DF_INVYZ, 0}, /* space navigator for notebooks*/ {{0x046d, 0xc628}, DEV_SNAVNB, DF_SWAPYZ | DF_INVYZ, 0}, /* space navigator for notebooks*/
{{0x046d, 0xc629}, DEV_SPILOTPRO, DF_SWAPYZ | DF_INVYZ, 0}, /* space pilot pro*/ {{0x046d, 0xc629}, DEV_SPILOTPRO, DF_SWAPYZ | DF_INVYZ, 0}, /* space pilot pro*/
{{0x046d, 0xc62b}, DEV_SMPRO, DF_SWAPYZ | DF_INVYZ, 0}, /* space mouse pro*/ {{0x046d, 0xc62b}, DEV_SMPRO, DF_SWAPYZ | DF_INVYZ, bnhack_smpro}, /* space mouse pro*/
{{0x046d, 0xc640}, DEV_NULOOQ, 0, 0}, /* nulooq */ {{0x046d, 0xc640}, DEV_NULOOQ, 0, 0}, /* nulooq */
{{0x256f, 0xc62e}, DEV_SMW, DF_SWAPYZ | DF_INVYZ, 0}, /* spacemouse wireless (USB cable) */ {{0x256f, 0xc62e}, DEV_SMW, DF_SWAPYZ | DF_INVYZ, 0}, /* spacemouse wireless (USB cable) */
{{0x256f, 0xc62f}, DEV_SMW, DF_SWAPYZ | DF_INVYZ, 0}, /* spacemouse wireless receiver */ {{0x256f, 0xc62f}, DEV_SMW, DF_SWAPYZ | DF_INVYZ, 0}, /* spacemouse wireless receiver */
@ -191,7 +186,7 @@ int init_devices_usb(void)
remove_device(dev); remove_device(dev);
} else { } else {
/* add the 6dof remapping flags to every future 3dconnexion device */ /* add the 6dof remapping flags to every future 3dconnexion device */
if(dev->usbid[0] == VENDOR_3DCONNEXION) { if(dev->usbid[0] == VID_3DCONN) {
dev->flags |= DF_SWAPYZ | DF_INVYZ; dev->flags |= DF_SWAPYZ | DF_INVYZ;
} }
/* sanity-check the device flags */ /* sanity-check the device flags */
@ -395,7 +390,7 @@ static int match_usbdev(const struct usb_dev_info *devinfo)
} }
/* match any device with the new 3Dconnexion device id */ /* match any device with the new 3Dconnexion device id */
if(vid == VENDOR_3DCONNEXION) { if(vid == VID_3DCONN) {
/* avoid matching and trying to grab the CAD mouse, when connected /* avoid matching and trying to grab the CAD mouse, when connected
* on the same universal receiver as the spacemouse. * on the same universal receiver as the spacemouse.
*/ */

Wyświetl plik

@ -18,6 +18,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef SPNAV_DEV_USB_H_ #ifndef SPNAV_DEV_USB_H_
#define SPNAV_DEV_USB_H_ #define SPNAV_DEV_USB_H_
#define VID_3DCONN 0x256f
#define PID_WIRELESS 0xc652
struct device; struct device;
int open_dev_usb(struct device *dev); int open_dev_usb(struct device *dev);
@ -37,4 +40,8 @@ struct usb_dev_info *find_usb_devices(int (*match)(const struct usb_dev_info*));
void free_usb_devices_list(struct usb_dev_info *list); void free_usb_devices_list(struct usb_dev_info *list);
void print_usb_device_info(struct usb_dev_info *devinfo); void print_usb_device_info(struct usb_dev_info *devinfo);
/* see usbdb_entry table bnmap field in dev.c */
int bnhack_smpro(int bn);
int bnhack_sment(int bn);
#endif /* SPNAV_DEV_USB_H_ */ #endif /* SPNAV_DEV_USB_H_ */

Wyświetl plik

@ -109,6 +109,15 @@ int open_dev_usb(struct device *dev)
} }
dev->num_axes = axes_rel + axes_abs; dev->num_axes = axes_rel + axes_abs;
if(!dev->num_axes) { if(!dev->num_axes) {
if(dev->usbid[0] == VID_3DCONN && dev->usbid[1] == PID_WIRELESS) {
/* a wireless 3Dconnexion device without axes is probably one of the
* CadMouse products, drop it.
*/
logmsg(LOG_DEBUG, "No axes detected, probably a CadMouse, dropping\n");
close(dev->fd);
dev->fd = -1;
return -1;
}
logmsg(LOG_WARNING, "failed to retrieve number of axes. assuming 6\n"); logmsg(LOG_WARNING, "failed to retrieve number of axes. assuming 6\n");
dev->num_axes = 6; dev->num_axes = 6;
} else { } else {
@ -118,25 +127,49 @@ int open_dev_usb(struct device *dev)
} }
/* get number of buttons */ /* get number of buttons */
dev->num_buttons = 0;
if(ioctl(dev->fd, EVIOCGBIT(EV_KEY, sizeof evtype_mask), evtype_mask) != -1) {
for(i=0; i<KEY_CNT; i++) {
int idx = i / 8;
int bit = i % 8;
if(evtype_mask[idx] & (1 << bit)) {
dev->num_buttons++;
}
}
} else {
logmsg(LOG_DEBUG, "EVIOCGBIT(EV_KEY) ioctl failed: %s\n", strerror(errno));
}
/* sanity check, problematic devices appear to report 256 buttons, if that's
* not the case, this is probably a mistake.
*/
if(dev->bnhack && dev->num_buttons < 255) {
logmsg(LOG_DEBUG, "BUG! Please report this at https://github.com/FreeSpacenav/spacenavd/issues, "
"or by sending an email to nuclear@member.fsf.org.\n");
logmsg(LOG_DEBUG, "This device (%04x:%04x) was marked for disjointed "
"button remapping, but unexpectedly reports %d buttons\n",
dev->usbid[0], dev->usbid[1], dev->num_buttons);
dev->bnhack = 0;
}
if(dev->bnhack) { if(dev->bnhack) {
/* for those problematic devices, rely on the hardcoded button value in
* their button remapping hack
*/
dev->num_buttons = dev->bnhack(-1); dev->num_buttons = dev->bnhack(-1);
} else { } else {
dev->num_buttons = 0; if(dev->usbid[0] == VID_3DCONN && dev->usbid[1] == PID_WIRELESS) {
if(ioctl(dev->fd, EVIOCGBIT(EV_KEY, sizeof evtype_mask), evtype_mask) != -1) { /* Wireless devices use the same dongle, try to guess which actual
for(i=0; i<KEY_CNT; i++) { * device this is, and apply the button hack if it's a SpcMouse Pro
int idx = i / 8; */
int bit = i % 8; if(dev->num_buttons >= 255) {
dev->type = DEV_SMPROW;
if(evtype_mask[idx] & (1 << bit)) { dev->bnhack = bnhack_smpro;
logmsg(LOG_DEBUG, "bit %d (part %d bit %d)\n", idx * 8 + i, idx, bit); dev->num_buttons = bnhack_smpro(-1);
dev->num_buttons++; strcpy(dev->name, "3Dconnexion SpaceMouse Pro Wireless (guess)");
} } else {
dev->type = DEV_SMW;
strcpy(dev->name, "3Dconnexion SpaceMouse Wireless (guess)");
} }
} else {
logmsg(LOG_DEBUG, "EVIOCGBIT(EV_KEY) ioctl failed: %s\n", strerror(errno));
} }
} }
if(!dev->num_buttons) { if(!dev->num_buttons) {