Files
qelectrotech-source-mirror/sources/spacemouse/spnavbackend.cpp
T
ispyisail e35cab33f0 Extract a SpaceMouseBackend seam ahead of a future Windows/macOS backend
The user asked for phase 2 (Windows/macOS via 3Dconnexion's proprietary
3DxWare SDK) on top of #635. This sandbox has no 3DxWare SDK, no Windows
toolchain, and no macOS toolchain -- nothing to compile, link, or run a
single line of platform code against, unlike the Linux/libspnav path,
which was built and actually tested here for real. Writing 3DxWare
integration code that has never even built would be a materially weaker,
unverifiable thing sitting in this PR, so it is not in this commit.

What is: the structural seam that makes adding it later a contained,
reviewable change instead of a rewrite of code that already works.

## Before

SpaceMouseListener did three unrelated things in one class: own the
libspnav connection, read spnav events, and apply motion to the active
DiagramView. A Windows/macOS backend would have had to either duplicate
all of the DiagramView-facing logic (the pan/zoom calls, the Z-to-zoom-
factor mapping, the "which view is active" lookup -- all already verified)
or bolt onto the same class with a maze of #ifdefs. Either way, touching
that file again would put the already-tested Linux path back in scope for
review.

## After

- SpaceMouseBackend: a tiny interface (isAvailable(), a motion(dx,dy,dz)
  signal). A backend's only job is owning one platform's connection to the
  driver/daemon and translating its native event into this one signal.
- SpnavBackend: the libspnav code from the previous commit, moved behind
  that interface with no behaviour change -- still spnav_open() in the
  constructor, still a QSocketNotifier on spnav_fd(), still silent when no
  daemon/device is present.
- SpaceMouseListener: now backend-agnostic. Owns whichever backend the
  platform provides, applies its motion to the active DiagramView exactly
  as before. The DiagramView-facing code (pan/zoom calls,
  zoomFactorForZAxis) did not need to change at all -- only its input
  changed from a spnav_event_motion struct to three plain ints.

A future 3DxWare backend implements SpaceMouseBackend, is selected in
SpaceMouseListener's constructor behind its own
QET_SPACEMOUSE_BACKEND_3DXWARE guard (see the comment marking exactly
where), and never has to touch SpnavBackend or SpaceMouseListener's
DiagramView-facing half.

## CMake: one user option, one define per backend

QET_ENABLE_SPACEMOUSE is unchanged as the single option a user sets.
Internally, find_spacemouse.cmake now decides *which* backend (if any)
that resolves to: on Linux with libspnav found, QET_SPACEMOUSE_BACKEND_SPNAV
plus the umbrella QET_SPACEMOUSE_SUPPORT. Turning the option on anywhere
else today downgrades cleanly with a warning naming discussion #599,
instead of trying (and failing) to find libspnav on a platform that
doesn't ship it. Adding 3DxWare later means adding one more branch here,
not restructuring this file.

## Verified this is a pure refactor, not just "still compiles"

Reconfigured and rebuilt both ways from scratch:
 - option off: unchanged from before -- no new source files compiled, zero
   new object code.
 - option on: both new files compile with zero warnings, binary still
   links against libspnav.so.0 (confirmed via ldd), and run to completion
   in this environment (which has no spacenavd) with zero crashes and zero
   spnav-related output -- identical to before the refactor.
 - zoomFactorForZAxis re-linked and re-run in isolation: identical output
   to the pre-refactor commit (z=0 -> exactly 1.0, z=+-350 -> 1.35/0.65),
   confirming the math moved unchanged rather than being reimplemented.
2026-08-02 21:22:42 +12:00

79 lines
2.3 KiB
C++

/*
Copyright 2006-2026 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "spnavbackend.h"
#include <QSocketNotifier>
#include <spnav.h>
/**
@brief SpnavBackend::SpnavBackend
Try to connect to spacenavd. Failure -- no daemon running, no device
attached -- is left silent: it is the expected state for most users and
must never surface as an error dialog or a log warning on every
ordinary startup.
@param parent
*/
SpnavBackend::SpnavBackend(QObject *parent) :
SpaceMouseBackend(parent)
{
if (spnav_open() == -1) {
return;
}
m_available = true;
m_notifier = new QSocketNotifier(spnav_fd(), QSocketNotifier::Read, this);
connect(m_notifier, &QSocketNotifier::activated,
this, &SpnavBackend::readEvents);
}
/**
@brief SpnavBackend::~SpnavBackend
*/
SpnavBackend::~SpnavBackend()
{
if (m_available) {
spnav_close();
}
}
/**
@brief SpnavBackend::readEvents
Called when the spacenavd socket has data available. Drains every event
currently queued -- spnav_poll_event() returns 0 once the queue is
empty -- rather than handling just one per activation, so events cannot
silently back up if several arrive between two Qt event loop turns.
*/
void SpnavBackend::readEvents()
{
spnav_event event;
while (spnav_poll_event(&event))
{
if (event.type == SPNAV_EVENT_MOTION) {
//A 6-DOF device also reports rotation (rx, ry, rz); QET's
//view has nothing rotation maps to, so those three axes are
//read by nothing here.
emit motion(event.motion.x, event.motion.y, event.motion.z);
}
//Button events (SPNAV_EVENT_BUTTON) are deliberately not
//handled: mapping device buttons to QET actions is the "Related,
//not proposed here" follow-up in discussion #599, not this
//phase.
}
}