1 /*
2  *  OpenSCAD (www.openscad.org)
3  *  Copyright (C) 2009-2011 Clifford Wolf <clifford@clifford.at> and
4  *                          Marius Kintel <marius@kintel.net>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  As a special exception, you have permission to link this program
12  *  with the CGAL library and distribute executables, as long as you
13  *  follow the requirements of the GNU GPL in regard to all of the
14  *  software in the executable aside from CGAL.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License
22  *  along with this program; if not, write to the Free Software
23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  */
26 
27 /*
28  *  Initial implementation by Jochen Kunz and Gert Menke provided as
29  *  Public Domain.
30  */
31 
32 #include "input/SpaceNavInputDriver.h"
33 #include "input/InputDriverManager.h"
34 
35 #include <spnav.h>
36 #include <unistd.h>
37 
SpaceNavInputDriver()38 SpaceNavInputDriver::SpaceNavInputDriver()
39 {
40 
41 }
42 
~SpaceNavInputDriver()43 SpaceNavInputDriver::~SpaceNavInputDriver()
44 {
45 
46 }
47 
run()48 void SpaceNavInputDriver::run()
49 {
50     while (spnav_input()) {
51         QThread::msleep(20);
52         spnav_remove_events(SPNAV_EVENT_MOTION);
53     }
54 }
55 
56 /*
57  * Handle events from the spacenavd daemon. The method blocks until at least
58  * one event is available and then processes all events until the queue is
59  * empty.
60  */
spnav_input(void)61 bool SpaceNavInputDriver::spnav_input(void)
62 {
63     spnav_event ev;
64 
65 	// The low level driver seems to inhibit events in the dead zone, so if we
66 	// enter that case, make sure to zero out our axis values.
67 	bool have_event = false;
68 	for (int a = 0; a < 3; ++a) {
69 		if (spnav_poll_event(&ev) != 0) {
70 			have_event = true;
71 			break;
72 		}
73 		QThread::msleep(20);
74     }
75 
76 	if (!have_event) {
77 		InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(0, 0));
78 		InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(1, 0));
79 		InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(2, 0));
80 		InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(3, 0));
81 		InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(4, 0));
82 		InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(5, 0));
83 
84 		if (spnav_wait_event(&ev) == 0) {
85 			return false;
86 		}
87 	}
88 
89     do {
90         if (ev.type == SPNAV_EVENT_MOTION) {
91 #ifdef DEBUG
92 			if ((ev.motion.x != 0) || (ev.motion.y != 0) || (ev.motion.z != 0)) {
93 				PRINTDB("Translate Event: x = %d, y = %d, z = %d", ev.motion.x % ev.motion.y % ev.motion.z);
94 			}
95 			if ((ev.motion.rx != 0) || (ev.motion.ry != 0) || (ev.motion.rz != 0)) {
96 				PRINTDB("Rotate Event: rx = %d, ry = %d, rz = %d", ev.motion.rx % ev.motion.ry % ev.motion.rz);
97 			}
98 #endif
99 
100             if (this->dominantAxisOnly) {
101                 // dominant axis only
102                 int m=ev.motion.x;
103                 if (abs(m) < abs(ev.motion.y)) m=ev.motion.y;
104                 if (abs(m) < abs(ev.motion.z)) m=ev.motion.z;
105                 if (abs(m) < abs(ev.motion.rx)) m=ev.motion.rx;
106                 if (abs(m) < abs(ev.motion.ry)) m=ev.motion.ry;
107                 if (abs(m) < abs(ev.motion.rz)) m=ev.motion.rz;
108 
109                 if (ev.motion.x == m) {                ev.motion.y=0; ev.motion.z=0; ev.motion.rx=0; ev.motion.ry=0; ev.motion.rz=0; }
110                 if (ev.motion.y == m) { ev.motion.x=0;                ev.motion.z=0; ev.motion.rx=0; ev.motion.ry=0; ev.motion.rz=0; }
111                 if (ev.motion.z == m) { ev.motion.x=0; ev.motion.y=0;                ev.motion.rx=0; ev.motion.ry=0; ev.motion.rz=0; }
112                 if (ev.motion.rx== m) { ev.motion.x=0; ev.motion.y=0; ev.motion.z=0;                 ev.motion.ry=0; ev.motion.rz=0; }
113                 if (ev.motion.ry== m) { ev.motion.x=0; ev.motion.y=0; ev.motion.z=0; ev.motion.rx=0;                 ev.motion.rz=0; }
114                 if (ev.motion.rz== m) { ev.motion.x=0; ev.motion.y=0; ev.motion.z=0; ev.motion.rx=0; ev.motion.ry=0;                 }
115             }
116 
117 			if (ev.motion.x != 0) {
118 				InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(0, ev.motion.x / 500.0));
119 			}
120 			if (ev.motion.y != 0) {
121 				InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(1, ev.motion.y / 500.0));
122 			}
123 			if (ev.motion.z != 0) {
124 				InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(2, ev.motion.z / 500.0));
125 			}
126 			if (ev.motion.rx != 0) {
127 				InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(3, ev.motion.rx / 500.0));
128 			}
129 			if (ev.motion.ry != 0) {
130 				InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(4, ev.motion.ry / 500.0));
131 			}
132 			if (ev.motion.rz != 0) {
133 				InputDriverManager::instance()->sendEvent(new InputEventAxisChanged(5, ev.motion.rz / 500.0));
134 			}
135         } else if (ev.type == SPNAV_EVENT_BUTTON) {
136 			PRINTDB("Button Event: num = %d, %s", ev.button.bnum % (ev.button.press ? "pressed" : "released"));
137             InputEvent *event = new InputEventButtonChanged(ev.button.bnum, ev.button.press);
138             InputDriverManager::instance()->sendEvent(event);
139         }
140     } while (spnav_poll_event(&ev));
141 
142     return true;
143 }
144 
open()145 bool SpaceNavInputDriver::open()
146 {
147     if (spnav_open() < 0) {
148         return false;
149     }
150     start();
151     return true;
152 }
153 
close()154 void SpaceNavInputDriver::close()
155 {
156 
157 }
158 
setDominantAxisOnly(bool var)159 void SpaceNavInputDriver::setDominantAxisOnly(bool var){
160     this->dominantAxisOnly = var;
161 }
162 
get_name() const163 const std::string & SpaceNavInputDriver::get_name() const
164 {
165     static std::string name = "SpaceNavInputDriver";
166     return name;
167 }
168 
get_info() const169 std::string SpaceNavInputDriver::get_info() const
170 {
171 	return STR(get_name() << " " << (isOpen() ? "open" : "not open") << " ");
172 }
173