Using evdev driver would work with Xorg as a 2-axis mouse, but trying to force it as a joystick using udev rules did not help. Although the device would show up as /dev/input/by-id/usb-3Dconnexion_SpaceNavigator-event-joystick, no /dev/input/js* was created, and Xorg would not pick it up as an input device. Neither was it identified by jstest.
However evdev was able to identify all the axes and buttons properly. evtest shows:
Code: Select all
Input device name: "3Dconnexion SpaceNavigator"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 256 (BTN_0)
Event code 257 (BTN_1)
Event type 2 (EV_REL)
Event code 0 (REL_X)
Event code 1 (REL_Y)
Event code 2 (REL_Z)
Event code 3 (REL_RX)
Event code 4 (REL_RY)
Event code 5 (REL_RZ)
Event type 4 (EV_MSC)
Event code 4 (MSC_SCAN)
Event type 17 (EV_LED)
Event code 8 (LED_MISC) state 0
In order to get it to be picked up by Xorg as an input device, I used a small python wrapper using python3-evdev and python3-uinput. Along with a udev rule, xorg.conf.d/ configuration, and a systemd service to start and stop the wrapper automatically. This seems to work well and should be flexible for alternate configurations or similar deices.
FILES
/etc/udev/rules.d/41-spacenavigator.rules
/etc/systemd/system/spacenav-python-evdev.service
/usr/local/bin/spacenav-python.py
/etc/X11/xorg.conf.d/54-spacenav-pyevdev.conf
/etc/udev/rules.d/41-spacenavigator.rules
Code: Select all
#obseved 046d:c626
#KERNEL Line allows non root user to create uinput device. ADD action identifies devices flags as joystick, and creates input/spacenav symlink,
KERNEL=="uinput", MODE="0666"
ACTION=="add", KERNEL=="event[0-9]*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c626", ENV{ID_INPUT_JOYSTICK}="1", SYMLINK+="input/spacenav", RUN+="/usr/bin/systemctl start spacenav-python-evdev.service"
ACTION=="remove", KERNEL=="event[0-9]*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c626", RUN+="/usr/bin/systemctl stop spacenav-python-evdev.service"
/etc/systemd/system/spacenav-python-evdev.service
Code: Select all
[Unit]
Description = spacenav python evdev wrapper
[Service]
Type=oneshot
ExecStart = python3 /usr/local/bin/spacenav-python.py
ExecStop = killall spacenav-python.py
[Install]
/usr/local/bin/spacenav-python.py
Code: Select all
#!/usr/bin/python
# -*- coding: utf-8 -*-
import evdev
from evdev import InputDevice, categorize, ecodes
import time
import uinput
# creates object 'sn' to store the data
sn = InputDevice('/dev/input/spacenav')
# prints out device info at start
print sn
# for event in sn.read_loop():
# print(categorize(event))
# input codes
X = 0
Y = 1 # negative=up
Z = 2
RY = 3
RX = 4
RZ = 5
BTN_L = 256
BTN_R = 257
max = 350
min = -max
fuzz = 5
flat = 5
events = (
uinput.BTN_LEFT,
uinput.BTN_RIGHT,
uinput.ABS_X + (min, max, fuzz, flat),
uinput.ABS_Y + (min, max, fuzz, flat),
uinput.ABS_Z + (min, max, fuzz, flat),
uinput.ABS_RX + (min, max, fuzz, flat),
uinput.ABS_RY + (min, max, fuzz, flat),
uinput.ABS_RZ + (min, max, fuzz, flat),
)
device = uinput.Device(events, name='spacenav-pyevdev')
# loop and filter by event code
for event in sn.read_loop():
if event.type != ecodes.EV_KEY:
# if abs(event.value) > 20:
if event.code == Y:
# print("Y",event.value)
device.emit(uinput.ABS_Y, event.value)
elif event.code == X:
# print("X", event.value)
device.emit(uinput.ABS_X, event.value)
elif event.code == Z:
# print("Z" , event.value)
device.emit(uinput.ABS_Z, event.value)
elif event.code == RY:
# print("RY", event.value)
device.emit(uinput.ABS_RY, event.value)
elif event.code == RX:
# print("RX", event.value)
device.emit(uinput.ABS_RX, event.value)
elif event.code == RZ:
# print("RZ", event.value)
device.emit(uinput.ABS_RZ, event.value)
if event.type == ecodes.EV_KEY:
if event.code == BTN_L:
device.emit(uinput.BTN_LEFT, event.value)
# without the emit ABS_RX 0, for some reason the ABS_RX would min out until new value sent?
device.emit(uinput.ABS_RX, 0)
elif event.code == BTN_R:
device.emit(uinput.BTN_RIGHT, event.value)
device.emit(uinput.ABS_RX, 0)
/etc/X11/xorg.conf.d/54-spacenav-pyevdev.conf
Code: Select all
Section "InputClass"
Identifier "spacenav-python-uinput"
MatchProduct "spacenav-pyevdev"
Option "AutoRepeat" "1500 1"
Driver "joystick"
# X: move left/right - send shift tab, tab
Option "MapAxis1" "keylow=50,23 keyhigh=23 mode=relative axis=+1key deadzone=6000"
# Y: move up/down - send page up/down
Option "MapAxis2" "keylow=112 keyhigh=117 mode=relative axis=+1key deadzone=6000"
# Z: pull up / push down - vertical scroll
Option "MapAxis3" "mode=relative axis=+0.75zy deadzone=6500"
# RY: tilt up/down - move pointer Y
Option "MapAxis4" "mode=relative axis=-1.5x deadzone=4000"
# RX: tilt left/right - move pointer X
Option "MapAxis5" "mode=relative axis=+1.5y deadzone=4000"
# RZ: twist left/right - horizontal scroll
Option "MapAxis6" "mode=relative axis=+1zx deadzone=6000"
# Button 2 - right click
Option "MapButton2" "button=3"
EndSection