2 /*
3 * Inkscape::DeviceManager - a view of input devices available.
4 *
5 * Copyright 2006 Jon A. Cruz <jon@joncruz.org>
6 *
7 * Released under GNU GPL, read the file 'COPYING' for more information
8 */
10 #include <glib.h>
11 #include <map>
13 #include "device-manager.h"
16 static void createFakeList();
17 GdkDevice fakeout[5];
18 static GList* fakeList = 0;
21 namespace Inkscape {
23 using std::pair;
25 static pair<gint, gint> vals[] = {
26 pair<gint, gint>(0, 1), pair<gint, gint>(1, 1 << 1), pair<gint, gint>(2, 1 << 2), pair<gint, gint>(3, 1 << 3),
27 pair<gint, gint>(4, 1 << 4), pair<gint, gint>(5, 1 << 5), pair<gint, gint>(6, 1 << 6), pair<gint, gint>(7, 1 << 7),
28 pair<gint, gint>(8, 1 << 8), pair<gint, gint>(9, 1 << 9), pair<gint, gint>(10, 1 << 10), pair<gint, gint>(11, 1 << 11),
29 pair<gint, gint>(12, 1 << 12), pair<gint, gint>(13, 1 << 13), pair<gint, gint>(14, 1 << 14), pair<gint, gint>(15, 1 << 15),
30 pair<gint, gint>(16, 1 << 16), pair<gint, gint>(17, 1 << 17), pair<gint, gint>(18, 1 << 18), pair<gint, gint>(19, 1 << 19),
31 pair<gint, gint>(20, 1 << 20), pair<gint, gint>(21, 1 << 21), pair<gint, gint>(22, 1 << 22), pair<gint, gint>(23, 1 << 23)
32 };
33 static std::map<gint, gint> bitVals(vals, &vals[G_N_ELEMENTS(vals)]);
36 InputDevice::InputDevice()
37 : Glib::Object()
38 {}
40 InputDevice::~InputDevice() {}
42 class InputDeviceImpl : public InputDevice {
43 public:
44 virtual Glib::ustring getId() const {return id;}
45 virtual Glib::ustring getName() const {return name;}
46 virtual Gdk::InputSource getSource() const {return source;}
47 virtual Gdk::InputMode getMode() const {return static_cast<Gdk::InputMode>(device->mode);}
48 virtual bool hasCursor() const {return device->has_cursor;}
49 virtual gint getNumAxes() const {return device->num_axes;}
50 virtual gint getNumKeys() const {return device->num_keys;}
51 virtual Glib::ustring getLink() const {return link;}
52 virtual void setLink( Glib::ustring const& link ) {this->link = link;}
53 virtual gint getLiveAxes() const {return liveAxes;}
54 virtual void setLiveAxes(gint axes) {liveAxes = axes;}
55 virtual gint getLiveButtons() const {return liveButtons;}
56 virtual void setLiveButtons(gint buttons) {liveButtons = buttons;}
59 InputDeviceImpl(GdkDevice* device);
60 virtual ~InputDeviceImpl() {}
62 private:
63 InputDeviceImpl(InputDeviceImpl const &); // no copy
64 void operator=(InputDeviceImpl const &); // no assign
66 GdkDevice* device;
67 Glib::ustring id;
68 Glib::ustring name;
69 Gdk::InputSource source;
70 Glib::ustring link;
71 guint liveAxes;
72 guint liveButtons;
73 };
75 class IdMatcher : public std::unary_function<InputDeviceImpl*, bool> {
76 public:
77 IdMatcher(Glib::ustring const& target):target(target) {}
78 bool operator ()(InputDeviceImpl* dev) {return dev && (target == dev->getId());}
80 private:
81 Glib::ustring const& target;
82 };
84 class LinkMatcher : public std::unary_function<InputDeviceImpl*, bool> {
85 public:
86 LinkMatcher(Glib::ustring const& target):target(target) {}
87 bool operator ()(InputDeviceImpl* dev) {return dev && (target == dev->getLink());}
89 private:
90 Glib::ustring const& target;
91 };
93 InputDeviceImpl::InputDeviceImpl(GdkDevice* device)
94 : InputDevice(),
95 device(device),
96 id(),
97 name(device->name ? device->name : ""),
98 source(static_cast<Gdk::InputSource>(device->source)),
99 link(),
100 liveAxes(0),
101 liveButtons(0)
102 {
103 switch ( source ) {
104 case Gdk::SOURCE_MOUSE:
105 id = "M:";
106 break;
107 case Gdk::SOURCE_CURSOR:
108 id = "C:";
109 break;
110 case Gdk::SOURCE_PEN:
111 id = "P:";
112 break;
113 case Gdk::SOURCE_ERASER:
114 id = "E:";
115 break;
116 default:
117 id = "?:";
118 }
119 id += name;
120 }
129 class DeviceManagerImpl : public DeviceManager {
130 public:
131 DeviceManagerImpl();
132 virtual std::list<InputDevice const *> getDevices();
133 virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalDeviceChanged();
134 virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalAxesChanged();
135 virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalButtonsChanged();
136 virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalLinkChanged();
138 virtual void addAxis(Glib::ustring const & id, gint axis);
139 virtual void addButton(Glib::ustring const & id, gint button);
140 virtual void setLinkedTo(Glib::ustring const & id, Glib::ustring const& link);
142 protected:
143 std::list<InputDeviceImpl*> devices;
144 sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalDeviceChangedPriv;
145 sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalAxesChangedPriv;
146 sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalButtonsChangedPriv;
147 sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalLinkChangedPriv;
148 };
151 DeviceManagerImpl::DeviceManagerImpl() :
152 DeviceManager(),
153 devices()
154 {
155 GList* devList = gdk_devices_list();
157 if ( !fakeList ) {
158 createFakeList();
159 }
160 // devList = fakeList;
162 for ( GList* curr = devList; curr; curr = g_list_next(curr) ) {
163 GdkDevice* dev = reinterpret_cast<GdkDevice*>(curr->data);
164 if ( dev ) {
165 // g_message("device: name[%s] source[0x%x] mode[0x%x] cursor[%s] axis count[%d] key count[%d]", dev->name, dev->source, dev->mode,
166 // dev->has_cursor?"Yes":"no", dev->num_axes, dev->num_keys);
168 InputDeviceImpl* device = new InputDeviceImpl(dev);
169 devices.push_back(device);
170 }
171 }
172 }
174 std::list<InputDevice const *> DeviceManagerImpl::getDevices()
175 {
176 std::list<InputDevice const *> tmp;
177 for ( std::list<InputDeviceImpl*>::const_iterator it = devices.begin(); it != devices.end(); ++it ) {
178 tmp.push_back(*it);
179 }
180 return tmp;
181 }
184 sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalDeviceChanged()
185 {
186 return signalDeviceChangedPriv;
187 }
189 sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalAxesChanged()
190 {
191 return signalAxesChangedPriv;
192 }
194 sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalButtonsChanged()
195 {
196 return signalButtonsChangedPriv;
197 }
199 sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalLinkChanged()
200 {
201 return signalLinkChangedPriv;
202 }
204 void DeviceManagerImpl::addAxis(Glib::ustring const & id, gint axis)
205 {
206 if ( axis >= 0 && axis < static_cast<gint>(bitVals.size()) ) {
207 std::list<InputDeviceImpl*>::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
208 if ( it != devices.end() ) {
209 gint mask = bitVals[axis];
210 if ( (mask & (*it)->getLiveAxes()) == 0 ) {
211 (*it)->setLiveAxes((*it)->getLiveAxes() | mask);
213 // Only signal if a new axis was added
214 (*it)->reference();
215 signalAxesChangedPriv.emit(Glib::RefPtr<InputDevice>(*it));
216 }
217 }
218 }
219 }
221 void DeviceManagerImpl::addButton(Glib::ustring const & id, gint button)
222 {
223 if ( button >= 0 && button < static_cast<gint>(bitVals.size()) ) {
224 std::list<InputDeviceImpl*>::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
225 if ( it != devices.end() ) {
226 gint mask = bitVals[button];
227 if ( (mask & (*it)->getLiveButtons()) == 0 ) {
228 (*it)->setLiveButtons((*it)->getLiveButtons() | mask);
230 // Only signal if a new button was added
231 (*it)->reference();
232 signalButtonsChangedPriv.emit(Glib::RefPtr<InputDevice>(*it));
233 }
234 }
235 }
236 }
238 void DeviceManagerImpl::setLinkedTo(Glib::ustring const & id, Glib::ustring const& link)
239 {
240 std::list<InputDeviceImpl*>::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
241 if ( it != devices.end() ) {
242 InputDeviceImpl* dev = *it;
245 InputDeviceImpl* targetDev = 0;
246 if ( !link.empty() ) {
247 // Need to be sure the target of the link exists
248 it = std::find_if(devices.begin(), devices.end(), IdMatcher(link));
249 if ( it != devices.end() ) {
250 targetDev = *it;
251 }
252 }
255 if ( (link.empty() && !dev->getLink().empty())
256 || (targetDev && (targetDev->getLink() != id)) ) {
257 // only muck about if they aren't already linked
258 std::list<InputDeviceImpl*> changedItems;
260 if ( targetDev ) {
261 // Is something else already using that link?
262 it = std::find_if(devices.begin(), devices.end(), LinkMatcher(link));
263 if ( it != devices.end() ) {
264 (*it)->setLink("");
265 changedItems.push_back(*it);
266 }
267 }
268 it = std::find_if(devices.begin(), devices.end(), LinkMatcher(id));
269 if ( it != devices.end() ) {
270 (*it)->setLink("");
271 changedItems.push_back(*it);
272 }
273 if ( targetDev ) {
274 targetDev->setLink(id);
275 changedItems.push_back(targetDev);
276 }
277 dev->setLink(link);
278 changedItems.push_back(dev);
280 for ( std::list<InputDeviceImpl*>::const_iterator iter = changedItems.begin(); iter != changedItems.end(); ++iter ) {
281 (*iter)->reference();
282 signalLinkChangedPriv.emit(Glib::RefPtr<InputDevice>(*iter));
283 }
284 }
285 }
286 }
293 static DeviceManagerImpl* theInstance = 0;
295 DeviceManager::DeviceManager()
296 : Glib::Object()
297 {
298 }
300 DeviceManager::~DeviceManager() {
301 }
303 DeviceManager& DeviceManager::getManager() {
304 if ( !theInstance ) {
305 theInstance = new DeviceManagerImpl();
306 }
308 return *theInstance;
309 }
311 } // namespace Inkscape
318 GdkDeviceAxis padAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
319 {GDK_AXIS_Y, 0.0, 0.0},
320 {GDK_AXIS_PRESSURE, 0.0, 1.0},
321 {GDK_AXIS_XTILT, -1.0, 1.0},
322 {GDK_AXIS_YTILT, -1.0, 1.0},
323 {GDK_AXIS_WHEEL, 0.0, 1.0}};
324 GdkDeviceKey padKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
325 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
327 GdkDeviceAxis eraserAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
328 {GDK_AXIS_Y, 0.0, 0.0},
329 {GDK_AXIS_PRESSURE, 0.0, 1.0},
330 {GDK_AXIS_XTILT, -1.0, 1.0},
331 {GDK_AXIS_YTILT, -1.0, 1.0},
332 {GDK_AXIS_WHEEL, 0.0, 1.0}};
333 GdkDeviceKey eraserKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
334 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
336 GdkDeviceAxis cursorAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
337 {GDK_AXIS_Y, 0.0, 0.0},
338 {GDK_AXIS_PRESSURE, 0.0, 1.0},
339 {GDK_AXIS_XTILT, -1.0, 1.0},
340 {GDK_AXIS_YTILT, -1.0, 1.0},
341 {GDK_AXIS_WHEEL, 0.0, 1.0}};
342 GdkDeviceKey cursorKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
343 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
345 GdkDeviceAxis stylusAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
346 {GDK_AXIS_Y, 0.0, 0.0},
347 {GDK_AXIS_PRESSURE, 0.0, 1.0},
348 {GDK_AXIS_XTILT, -1.0, 1.0},
349 {GDK_AXIS_YTILT, -1.0, 1.0},
350 {GDK_AXIS_WHEEL, 0.0, 1.0}};
351 GdkDeviceKey stylusKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
352 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
355 GdkDeviceAxis coreAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
356 {GDK_AXIS_Y, 0.0, 0.0}};
358 static void createFakeList() {
359 if ( !fakeList ) {
360 fakeout[0].name = g_strdup("pad");
361 fakeout[0].source = GDK_SOURCE_PEN;
362 fakeout[0].mode = GDK_MODE_SCREEN;
363 fakeout[0].has_cursor = TRUE;
364 fakeout[0].num_axes = 6;
365 fakeout[0].axes = padAxes;
366 fakeout[0].num_keys = 8;
367 fakeout[0].keys = padKeys;
369 fakeout[1].name = g_strdup("eraser");
370 fakeout[1].source = GDK_SOURCE_ERASER;
371 fakeout[1].mode = GDK_MODE_SCREEN;
372 fakeout[1].has_cursor = TRUE;
373 fakeout[1].num_axes = 6;
374 fakeout[1].axes = eraserAxes;
375 fakeout[1].num_keys = 7;
376 fakeout[1].keys = eraserKeys;
378 fakeout[2].name = g_strdup("cursor");
379 fakeout[2].source = GDK_SOURCE_CURSOR;
380 fakeout[2].mode = GDK_MODE_SCREEN;
381 fakeout[2].has_cursor = TRUE;
382 fakeout[2].num_axes = 6;
383 fakeout[2].axes = cursorAxes;
384 fakeout[2].num_keys = 7;
385 fakeout[2].keys = cursorKeys;
387 fakeout[3].name = g_strdup("stylus");
388 fakeout[3].source = GDK_SOURCE_PEN;
389 fakeout[3].mode = GDK_MODE_SCREEN;
390 fakeout[3].has_cursor = TRUE;
391 fakeout[3].num_axes = 6;
392 fakeout[3].axes = stylusAxes;
393 fakeout[3].num_keys = 7;
394 fakeout[3].keys = stylusKeys;
396 // try to find the first *real* core pointer
397 GList* devList = gdk_devices_list();
398 while ( devList && devList->data && (((GdkDevice*)devList->data)->source != GDK_SOURCE_MOUSE) ) {
399 devList = g_list_next(devList);
400 }
401 if ( devList && devList->data ) {
402 fakeout[4] = *((GdkDevice*)devList->data);
403 } else {
404 fakeout[4].name = g_strdup("Core Pointer");
405 fakeout[4].source = GDK_SOURCE_MOUSE;
406 fakeout[4].mode = GDK_MODE_SCREEN;
407 fakeout[4].has_cursor = TRUE;
408 fakeout[4].num_axes = 2;
409 fakeout[4].axes = coreAxes;
410 fakeout[4].num_keys = 0;
411 fakeout[4].keys = NULL;
412 }
414 for ( guint pos = 0; pos < G_N_ELEMENTS(fakeout); pos++) {
415 fakeList = g_list_append(fakeList, &(fakeout[pos]));
416 }
417 }
418 }
421 /*
422 Local Variables:
423 mode:c++
424 c-file-style:"stroustrup"
425 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
426 indent-tabs-mode:nil
427 fill-column:99
428 End:
429 */
430 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :