FreeCAD
146 строк · 5.3 Кб
1/***************************************************************************
2* Copyright (c) 2018 Torsten Sadowski <tsadowski[at]gmx.net> *
3* *
4* This file is part of the FreeCAD CAx development system. *
5* *
6* This library is free software; you can redistribute it and/or *
7* modify it under the terms of the GNU Library General Public *
8* License as published by the Free Software Foundation; either *
9* version 2 of the License, or (at your option) any later version. *
10* *
11* This library is distributed in the hope that it will be useful, *
12* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14* GNU Library General Public License for more details. *
15* *
16* You should have received a copy of the GNU Library General Public *
17* License along with this library; see the file COPYING.LIB. If not, *
18* write to the Free Software Foundation, Inc., 59 Temple Place, *
19* Suite 330, Boston, MA 02111-1307, USA *
20* *
21***************************************************************************/
22
23#include <FCConfig.h>
24#include "SpaceballEvent.h"
25
26#include <QMainWindow>
27
28#include "GuiNativeEventLinuxX11.h"
29
30#include "GuiApplicationNativeEventAware.h"
31#include <Base/Console.h>
32
33#include <QX11Info>
34#include <spnav.h>
35
36#include "GuiRawInputEventFilter.h"
37#undef Bool
38#undef CursorShape
39#undef Expose
40#undef KeyPress
41#undef KeyRelease
42#undef FocusIn
43#undef FocusOut
44#undef FontChange
45#undef None
46#undef Status
47#undef Unsorted
48#undef False
49#undef True
50#undef Complex
51
52
53Gui::GuiNativeEvent::GuiNativeEvent(Gui::GUIApplicationNativeEventAware *app)
54: GuiAbstractNativeEvent(app)
55{
56}
57
58Gui::GuiNativeEvent::~GuiNativeEvent()
59{
60if (spnav_close())
61Base::Console().Log("Couldn't disconnect from spacenav daemon\n");
62else
63Base::Console().Log("Disconnected from spacenav daemon\n");
64}
65
66void Gui::GuiNativeEvent::initSpaceball(QMainWindow *window)
67{
68if (!QX11Info::isPlatformX11()) {
69Base::Console().Log("Application is not running on X11\n");
70return;
71}
72if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) {
73Base::Console().Log("Couldn't connect to spacenav daemon on X11. Please ignore if you don't have a spacemouse.\n");
74} else {
75Base::Console().Log("Connected to spacenav daemon on X11\n");
76mainApp->setSpaceballPresent(true);
77mainApp->installNativeEventFilter(new Gui::RawInputEventFilter(&xcbEventFilter));
78}
79}
80
81bool Gui::GuiNativeEvent::xcbEventFilter(void *xcb_void, long* result)
82{
83Q_UNUSED(result);
84auto inst(dynamic_cast<Gui::GUIApplicationNativeEventAware *>(QApplication::instance()));
85if (!inst)
86return false;
87
88spnav_event navEvent;
89
90const xcb_client_message_event_t* xcb_ev = static_cast<const xcb_client_message_event_t*>(xcb_void);
91// Qt4 used XEvents in native event filters, but Qt5 changed to XCB. The
92// SpaceNavigator API only works with XEvent, so we need to construct a
93// temporary XEvent with just enough information for spnav_x11_event()
94if ((xcb_ev->response_type & 0x7F) == XCB_CLIENT_MESSAGE) {
95XClientMessageEvent xev;
96
97xev.type = ClientMessage;
98xev.message_type = xcb_ev->type;
99memcpy(xev.data.b, xcb_ev->data.data8, sizeof(xev.data.b));
100xev.serial = 0; // These are just to squash warnings...
101xev.send_event = 0;
102xev.display = 0;
103xev.window = 0;
104xev.format = 0;
105
106if (!spnav_x11_event(reinterpret_cast<XEvent *>(&xev), &navEvent)) {
107return false;
108}
109} else {
110return false;
111}
112// navEvent is now initialised
113
114switch (navEvent.type) {
115case SPNAV_EVENT_MOTION:
116{
117motionDataArray[0] = -navEvent.motion.x;
118motionDataArray[1] = -navEvent.motion.z;
119motionDataArray[2] = -navEvent.motion.y;
120motionDataArray[3] = -navEvent.motion.rx;
121motionDataArray[4] = -navEvent.motion.rz;
122motionDataArray[5] = -navEvent.motion.ry;
123
124inst->postMotionEvent(motionDataArray);
125return true;
126}
127
128case SPNAV_EVENT_BUTTON:
129{
130auto buttonEvent(new Spaceball::ButtonEvent());
131buttonEvent->setButtonNumber(navEvent.button.bnum);
132if (navEvent.button.press) {
133buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED);
134} else {
135buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED);
136}
137inst->postButtonEvent(navEvent.button.bnum, navEvent.button.press);
138return true;
139}
140default:
141Base::Console().Log("Unknown spaceball event\n");
142return true;
143} // end switch (navEvent.type) {
144}
145
146#include "3Dconnexion/moc_GuiNativeEventLinuxX11.cpp"
147