2 /*
3 * Inkscape::DeviceManager - a view of input devices available.
4 *
5 * Copyright 2010 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>
12 #include <set>
13 #include <gtk/gtkaccelgroup.h>
15 #include "device-manager.h"
16 #include "preferences.h"
18 #define noDEBUG_VERBOSE 1
20 static void createFakeList();
21 GdkDevice fakeout[5];
22 static GList* fakeList = 0;
24 static bool isValidDevice(GdkDevice *device)
25 {
26 bool valid = true;
27 for (size_t i = 0; (i < G_N_ELEMENTS(fakeout)) && valid; i++) {
28 valid = (device != &fakeout[i]);
29 }
30 return valid;
31 }
33 namespace Inkscape {
35 using std::pair;
37 static pair<gint, gint> vals[] = {
38 pair<gint, gint>(0, 1), pair<gint, gint>(1, 1 << 1), pair<gint, gint>(2, 1 << 2), pair<gint, gint>(3, 1 << 3),
39 pair<gint, gint>(4, 1 << 4), pair<gint, gint>(5, 1 << 5), pair<gint, gint>(6, 1 << 6), pair<gint, gint>(7, 1 << 7),
40 pair<gint, gint>(8, 1 << 8), pair<gint, gint>(9, 1 << 9), pair<gint, gint>(10, 1 << 10), pair<gint, gint>(11, 1 << 11),
41 pair<gint, gint>(12, 1 << 12), pair<gint, gint>(13, 1 << 13), pair<gint, gint>(14, 1 << 14), pair<gint, gint>(15, 1 << 15),
42 pair<gint, gint>(16, 1 << 16), pair<gint, gint>(17, 1 << 17), pair<gint, gint>(18, 1 << 18), pair<gint, gint>(19, 1 << 19),
43 pair<gint, gint>(20, 1 << 20), pair<gint, gint>(21, 1 << 21), pair<gint, gint>(22, 1 << 22), pair<gint, gint>(23, 1 << 23)
44 };
45 static std::map<gint, gint> bitVals(vals, &vals[G_N_ELEMENTS(vals)]);
48 static const int RUNAWAY_MAX = 1000;
50 static Glib::ustring getBaseDeviceName(Gdk::InputSource source)
51 {
52 Glib::ustring name;
53 switch (source) {
54 case GDK_SOURCE_MOUSE:
55 name ="pointer";
56 break;
57 case GDK_SOURCE_PEN:
58 name ="pen";
59 break;
60 case GDK_SOURCE_ERASER:
61 name ="eraser";
62 break;
63 case GDK_SOURCE_CURSOR:
64 name ="cursor";
65 break;
66 default:
67 name = "tablet";
68 }
69 return name;
70 }
72 static std::map<Glib::ustring, Gdk::AxisUse> &getStringToAxis()
73 {
74 static bool init = false;
75 static std::map<Glib::ustring, Gdk::AxisUse> mapping;
76 if (!init) {
77 init = true;
78 mapping["ignore"] = Gdk::AXIS_IGNORE;
79 mapping["x"] = Gdk::AXIS_X;
80 mapping["y"] = Gdk::AXIS_Y;
81 mapping["pressure"] = Gdk::AXIS_PRESSURE;
82 mapping["xtilt"] = Gdk::AXIS_XTILT;
83 mapping["ytilt"] = Gdk::AXIS_YTILT;
84 mapping["wheel"] = Gdk::AXIS_WHEEL;
85 }
86 return mapping;
87 }
89 std::map<Gdk::AxisUse, Glib::ustring> &getAxisToString()
90 {
91 static bool init = false;
92 static std::map<Gdk::AxisUse, Glib::ustring> mapping;
93 if (!init) {
94 init = true;
95 for (std::map<Glib::ustring, Gdk::AxisUse>::iterator it = getStringToAxis().begin(); it != getStringToAxis().end(); ++it) {
96 mapping.insert(std::make_pair(it->second, it->first));
97 }
98 }
99 return mapping;
100 }
102 static std::map<Glib::ustring, Gdk::InputMode> &getStringToMode()
103 {
104 static bool init = false;
105 static std::map<Glib::ustring, Gdk::InputMode> mapping;
106 if (!init) {
107 init = true;
108 mapping["disabled"] = Gdk::MODE_DISABLED;
109 mapping["screen"] = Gdk::MODE_SCREEN;
110 mapping["window"] = Gdk::MODE_WINDOW;
111 }
112 return mapping;
113 }
115 std::map<Gdk::InputMode, Glib::ustring> &getModeToString()
116 {
117 static bool init = false;
118 static std::map<Gdk::InputMode, Glib::ustring> mapping;
119 if (!init) {
120 init = true;
121 for (std::map<Glib::ustring, Gdk::InputMode>::iterator it = getStringToMode().begin(); it != getStringToMode().end(); ++it) {
122 mapping.insert(std::make_pair(it->second, it->first));
123 }
124 }
125 return mapping;
126 }
130 InputDevice::InputDevice()
131 : Glib::Object()
132 {}
134 InputDevice::~InputDevice() {}
136 class InputDeviceImpl : public InputDevice {
137 public:
138 InputDeviceImpl(GdkDevice* device, std::set<Glib::ustring> &knownIDs);
139 virtual ~InputDeviceImpl() {}
141 virtual Glib::ustring getId() const {return id;}
142 virtual Glib::ustring getName() const {return name;}
143 virtual Gdk::InputSource getSource() const {return source;}
144 virtual Gdk::InputMode getMode() const {return static_cast<Gdk::InputMode>(device->mode);}
145 virtual bool hasCursor() const {return device->has_cursor;}
146 virtual gint getNumAxes() const {return device->num_axes;}
147 virtual gint getNumKeys() const {return device->num_keys;}
148 virtual Glib::ustring getLink() const {return link;}
149 virtual void setLink( Glib::ustring const& link ) {this->link = link;}
150 virtual gint getLiveAxes() const {return liveAxes;}
151 virtual void setLiveAxes(gint axes) {liveAxes = axes;}
152 virtual gint getLiveButtons() const {return liveButtons;}
153 virtual void setLiveButtons(gint buttons) {liveButtons = buttons;}
155 // internal methods not on public superclass:
156 virtual GdkDevice *getDevice() { return device; }
158 private:
159 InputDeviceImpl(InputDeviceImpl const &); // no copy
160 void operator=(InputDeviceImpl const &); // no assign
162 static Glib::ustring createId(Glib::ustring const &id, Gdk::InputSource source, std::set<Glib::ustring> &knownIDs);
164 GdkDevice* device;
165 Glib::ustring id;
166 Glib::ustring name;
167 Gdk::InputSource source;
168 Glib::ustring link;
169 guint liveAxes;
170 guint liveButtons;
171 };
173 class IdMatcher : public std::unary_function<Glib::RefPtr<InputDeviceImpl>&, bool> {
174 public:
175 IdMatcher(Glib::ustring const& target):target(target) {}
176 bool operator ()(Glib::RefPtr<InputDeviceImpl>& dev) {return dev && (target == dev->getId());}
178 private:
179 Glib::ustring const& target;
180 };
182 class LinkMatcher : public std::unary_function<Glib::RefPtr<InputDeviceImpl>&, bool> {
183 public:
184 LinkMatcher(Glib::ustring const& target):target(target) {}
185 bool operator ()(Glib::RefPtr<InputDeviceImpl>& dev) {return dev && (target == dev->getLink());}
187 private:
188 Glib::ustring const& target;
189 };
191 InputDeviceImpl::InputDeviceImpl(GdkDevice* device, std::set<Glib::ustring> &knownIDs)
192 : InputDevice(),
193 device(device),
194 id(),
195 name(device->name ? device->name : ""),
196 source(static_cast<Gdk::InputSource>(device->source)),
197 link(),
198 liveAxes(0),
199 liveButtons(0)
200 {
201 id = createId(name, source, knownIDs);
202 }
205 Glib::ustring InputDeviceImpl::createId(Glib::ustring const &id,
206 Gdk::InputSource source,
207 std::set<Glib::ustring> &knownIDs)
208 {
209 // Start with only allowing printable ASCII. Check later for more refinements.
210 bool badName = id.empty() || !id.is_ascii();
211 for (Glib::ustring::const_iterator it = id.begin(); (it != id.end()) && !badName; ++it) {
212 badName = *it < 0x20;
213 }
215 Glib::ustring base;
216 switch ( source ) {
217 case Gdk::SOURCE_MOUSE:
218 base = "M:";
219 break;
220 case Gdk::SOURCE_CURSOR:
221 base = "C:";
222 break;
223 case Gdk::SOURCE_PEN:
224 base = "P:";
225 break;
226 case Gdk::SOURCE_ERASER:
227 base = "E:";
228 break;
229 default:
230 base = "?:";
231 }
233 if (badName) {
234 base += getBaseDeviceName(source);
235 } else {
236 base += id;
237 }
239 // now ensure that all IDs become unique in a session.
240 int num = 1;
241 Glib::ustring result = base;
242 while ((knownIDs.find(result) != knownIDs.end()) && (num < RUNAWAY_MAX)) {
243 result = Glib::ustring::compose("%1%2", base, ++num);
244 }
246 knownIDs.insert(result);
247 return result;
248 }
254 class DeviceManagerImpl : public DeviceManager {
255 public:
256 DeviceManagerImpl();
258 virtual void loadConfig();
259 virtual void saveConfig();
261 virtual std::list<Glib::RefPtr<InputDevice const> > getDevices();
263 virtual sigc::signal<void, Glib::RefPtr<InputDevice const> > signalDeviceChanged();
264 virtual sigc::signal<void, Glib::RefPtr<InputDevice const> > signalAxesChanged();
265 virtual sigc::signal<void, Glib::RefPtr<InputDevice const> > signalButtonsChanged();
266 virtual sigc::signal<void, Glib::RefPtr<InputDevice const> > signalLinkChanged();
268 virtual void addAxis(Glib::ustring const & id, gint axis);
269 virtual void addButton(Glib::ustring const & id, gint button);
270 virtual void setLinkedTo(Glib::ustring const & id, Glib::ustring const& link);
272 virtual void setMode( Glib::ustring const & id, Gdk::InputMode mode );
273 virtual void setAxisUse( Glib::ustring const & id, guint index, Gdk::AxisUse use );
274 virtual void setKey( Glib::ustring const & id, guint index, guint keyval, Gdk::ModifierType mods );
276 protected:
277 std::list<Glib::RefPtr<InputDeviceImpl> > devices;
279 sigc::signal<void, Glib::RefPtr<InputDevice const> > signalDeviceChangedPriv;
280 sigc::signal<void, Glib::RefPtr<InputDevice const> > signalAxesChangedPriv;
281 sigc::signal<void, Glib::RefPtr<InputDevice const> > signalButtonsChangedPriv;
282 sigc::signal<void, Glib::RefPtr<InputDevice const> > signalLinkChangedPriv;
283 };
286 DeviceManagerImpl::DeviceManagerImpl() :
287 DeviceManager(),
288 devices()
289 {
290 GList* devList = gdk_devices_list();
292 if ( !fakeList ) {
293 createFakeList();
294 }
295 //devList = fakeList;
297 std::set<Glib::ustring> knownIDs;
299 for ( GList* curr = devList; curr; curr = g_list_next(curr) ) {
300 GdkDevice* dev = reinterpret_cast<GdkDevice*>(curr->data);
301 if ( dev ) {
302 #if DEBUG_VERBOSE
303 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,
304 dev->has_cursor?"Yes":"no", dev->num_axes, dev->num_keys);
305 #endif
307 InputDeviceImpl* device = new InputDeviceImpl(dev, knownIDs);
308 device->reference();
309 devices.push_back(Glib::RefPtr<InputDeviceImpl>(device));
310 }
311 }
312 }
314 void DeviceManagerImpl::loadConfig()
315 {
316 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
318 for (std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = devices.begin(); it != devices.end(); ++it) {
319 if ((*it)->getSource() != Gdk::SOURCE_MOUSE) {
320 Glib::ustring path = "/devices/" + (*it)->getId();
322 Gdk::InputMode mode = Gdk::MODE_DISABLED;
323 Glib::ustring val = prefs->getString(path + "/mode");
324 if (getStringToMode().find(val) != getStringToMode().end()) {
325 mode = getStringToMode()[val];
326 }
327 if ((*it)->getMode() != mode) {
328 setMode( (*it)->getId(), mode );
329 }
331 //
333 val = prefs->getString(path + "/axes");
334 if (!val.empty()) {
335 std::vector<Glib::ustring> parts = Glib::Regex::split_simple(";", val);
336 for (size_t i = 0; i < parts.size(); ++i) {
337 Glib::ustring name = parts[i];
338 if (getStringToAxis().find(name) != getStringToAxis().end()) {
339 Gdk::AxisUse use = getStringToAxis()[name];
340 setAxisUse( (*it)->getId(), i, use );
341 }
342 }
343 }
345 val = prefs->getString(path + "/keys");
346 if (!val.empty()) {
347 std::vector<Glib::ustring> parts = Glib::Regex::split_simple(";", val);
348 for (size_t i = 0; i < parts.size(); ++i) {
349 Glib::ustring keyStr = parts[i];
350 if (!keyStr.empty()) {
351 guint key = 0;
352 GdkModifierType mods = static_cast<GdkModifierType>(0);
353 gtk_accelerator_parse( keyStr.c_str(), &key, &mods );
354 setKey( (*it)->getId(), i, key, static_cast<Gdk::ModifierType>(mods) );
355 }
356 }
357 }
358 }
359 }
360 }
362 void DeviceManagerImpl::saveConfig()
363 {
364 Inkscape::Preferences *prefs = Inkscape::Preferences::get();
366 for (std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = devices.begin(); it != devices.end(); ++it) {
367 if ((*it)->getSource() != Gdk::SOURCE_MOUSE) {
368 Glib::ustring path = "/devices/" + (*it)->getId();
370 prefs->setString( path + "/mode", getModeToString()[(*it)->getMode()].c_str() );
372 Glib::ustring tmp;
373 for (gint i = 0; i < (*it)->getNumAxes(); ++i) {
374 if (i > 0) {
375 tmp += ";";
376 }
377 tmp += getAxisToString()[static_cast<Gdk::AxisUse>((*it)->getDevice()->axes[i].use)];
378 }
379 prefs->setString( path + "/axes", tmp );
381 tmp = "";
382 for (gint i = 0; i < (*it)->getNumKeys(); ++i) {
383 if (i > 0) {
384 tmp += ";";
385 }
386 tmp += gtk_accelerator_name((*it)->getDevice()->keys[i].keyval, (*it)->getDevice()->keys[i].modifiers);
387 }
388 prefs->setString( path + "/keys", tmp );
389 }
390 }
391 }
393 std::list<Glib::RefPtr<InputDevice const> > DeviceManagerImpl::getDevices()
394 {
395 std::list<Glib::RefPtr<InputDevice const> > tmp;
396 for ( std::list<Glib::RefPtr<InputDeviceImpl> >::const_iterator it = devices.begin(); it != devices.end(); ++it ) {
397 tmp.push_back(*it);
398 }
399 return tmp;
400 }
402 void DeviceManagerImpl::setMode( Glib::ustring const & id, Gdk::InputMode mode )
403 {
404 std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
405 if ( it != devices.end() ) {
406 if (isValidDevice((*it)->getDevice()) && ((*it)->getMode() != mode) ) {
407 bool success = gdk_device_set_mode((*it)->getDevice(), static_cast<GdkInputMode>(mode));
408 if (success) {
409 signalDeviceChangedPriv.emit(*it);
410 } else {
411 g_warning("Unable to set mode on extended input device [%s]", (*it)->getId().c_str());
412 }
413 }
414 }
415 }
417 void DeviceManagerImpl::setAxisUse( Glib::ustring const & id, guint index, Gdk::AxisUse use )
418 {
419 std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
420 if ( it != devices.end() ) {
421 if (isValidDevice((*it)->getDevice())) {
422 if (static_cast<gint>(index) <= (*it)->getNumAxes()) {
423 if ((*it)->getDevice()->axes[index].use != static_cast<GdkAxisUse>(use)) {
424 gdk_device_set_axis_use((*it)->getDevice(), index, static_cast<GdkAxisUse>(use));
425 signalDeviceChangedPriv.emit(*it);
426 }
427 } else {
428 g_warning("Invalid device axis number %d on extended input device [%s]", index, (*it)->getId().c_str());
429 }
430 }
431 }
432 }
434 void DeviceManagerImpl::setKey( Glib::ustring const & id, guint index, guint keyval, Gdk::ModifierType mods )
435 {
436 //static void setDeviceKey( GdkDevice* device, guint index, guint keyval, GdkModifierType modifiers )
437 //
439 std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
440 if ( it != devices.end() ) {
441 if (isValidDevice((*it)->getDevice())) {
442 gdk_device_set_key((*it)->getDevice(), index, keyval, static_cast<GdkModifierType>(mods));
443 signalDeviceChangedPriv.emit(*it);
444 }
445 }
446 }
448 sigc::signal<void, Glib::RefPtr<InputDevice const> > DeviceManagerImpl::signalDeviceChanged()
449 {
450 return signalDeviceChangedPriv;
451 }
453 sigc::signal<void, Glib::RefPtr<InputDevice const> > DeviceManagerImpl::signalAxesChanged()
454 {
455 return signalAxesChangedPriv;
456 }
458 sigc::signal<void, Glib::RefPtr<InputDevice const> > DeviceManagerImpl::signalButtonsChanged()
459 {
460 return signalButtonsChangedPriv;
461 }
463 sigc::signal<void, Glib::RefPtr<InputDevice const> > DeviceManagerImpl::signalLinkChanged()
464 {
465 return signalLinkChangedPriv;
466 }
468 void DeviceManagerImpl::addAxis(Glib::ustring const & id, gint axis)
469 {
470 if ( axis >= 0 && axis < static_cast<gint>(bitVals.size()) ) {
471 std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
472 if ( it != devices.end() ) {
473 gint mask = bitVals[axis];
474 if ( (mask & (*it)->getLiveAxes()) == 0 ) {
475 (*it)->setLiveAxes((*it)->getLiveAxes() | mask);
477 // Only signal if a new axis was added
478 (*it)->reference();
479 signalAxesChangedPriv.emit(*it);
480 }
481 }
482 }
483 }
485 void DeviceManagerImpl::addButton(Glib::ustring const & id, gint button)
486 {
487 if ( button >= 0 && button < static_cast<gint>(bitVals.size()) ) {
488 std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
489 if ( it != devices.end() ) {
490 gint mask = bitVals[button];
491 if ( (mask & (*it)->getLiveButtons()) == 0 ) {
492 (*it)->setLiveButtons((*it)->getLiveButtons() | mask);
494 // Only signal if a new button was added
495 (*it)->reference();
496 signalButtonsChangedPriv.emit(*it);
497 }
498 }
499 }
500 }
502 void DeviceManagerImpl::setLinkedTo(Glib::ustring const & id, Glib::ustring const& link)
503 {
504 std::list<Glib::RefPtr<InputDeviceImpl> >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
505 if ( it != devices.end() ) {
506 Glib::RefPtr<InputDeviceImpl> dev = *it;
508 Glib::RefPtr<InputDeviceImpl> targetDev;
509 if ( !link.empty() ) {
510 // Need to be sure the target of the link exists
511 it = std::find_if(devices.begin(), devices.end(), IdMatcher(link));
512 if ( it != devices.end() ) {
513 targetDev = *it;
514 }
515 }
518 if ( (link.empty() && !dev->getLink().empty())
519 || (targetDev && (targetDev->getLink() != id)) ) {
520 // only muck about if they aren't already linked
521 std::list<Glib::RefPtr<InputDeviceImpl> > changedItems;
523 if ( targetDev ) {
524 // Is something else already using that link?
525 it = std::find_if(devices.begin(), devices.end(), LinkMatcher(link));
526 if ( it != devices.end() ) {
527 (*it)->setLink("");
528 changedItems.push_back(*it);
529 }
530 }
531 it = std::find_if(devices.begin(), devices.end(), LinkMatcher(id));
532 if ( it != devices.end() ) {
533 (*it)->setLink("");
534 changedItems.push_back(*it);
535 }
536 if ( targetDev ) {
537 targetDev->setLink(id);
538 changedItems.push_back(targetDev);
539 }
540 dev->setLink(link);
541 changedItems.push_back(dev);
543 for ( std::list<Glib::RefPtr<InputDeviceImpl> >::const_iterator iter = changedItems.begin(); iter != changedItems.end(); ++iter ) {
544 (*iter)->reference();
545 signalLinkChangedPriv.emit(*iter);
546 }
547 }
548 }
549 }
556 static DeviceManagerImpl* theInstance = 0;
558 DeviceManager::DeviceManager()
559 : Glib::Object()
560 {
561 }
563 DeviceManager::~DeviceManager() {
564 }
566 DeviceManager& DeviceManager::getManager() {
567 if ( !theInstance ) {
568 theInstance = new DeviceManagerImpl();
569 }
571 return *theInstance;
572 }
574 } // namespace Inkscape
581 GdkDeviceAxis padAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
582 {GDK_AXIS_Y, 0.0, 0.0},
583 {GDK_AXIS_PRESSURE, 0.0, 1.0},
584 {GDK_AXIS_XTILT, -1.0, 1.0},
585 {GDK_AXIS_YTILT, -1.0, 1.0},
586 {GDK_AXIS_WHEEL, 0.0, 1.0}};
587 GdkDeviceKey padKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
588 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
590 GdkDeviceAxis eraserAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
591 {GDK_AXIS_Y, 0.0, 0.0},
592 {GDK_AXIS_PRESSURE, 0.0, 1.0},
593 {GDK_AXIS_XTILT, -1.0, 1.0},
594 {GDK_AXIS_YTILT, -1.0, 1.0},
595 {GDK_AXIS_WHEEL, 0.0, 1.0}};
596 GdkDeviceKey eraserKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
597 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
599 GdkDeviceAxis cursorAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
600 {GDK_AXIS_Y, 0.0, 0.0},
601 {GDK_AXIS_PRESSURE, 0.0, 1.0},
602 {GDK_AXIS_XTILT, -1.0, 1.0},
603 {GDK_AXIS_YTILT, -1.0, 1.0},
604 {GDK_AXIS_WHEEL, 0.0, 1.0}};
605 GdkDeviceKey cursorKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
606 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
608 GdkDeviceAxis stylusAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
609 {GDK_AXIS_Y, 0.0, 0.0},
610 {GDK_AXIS_PRESSURE, 0.0, 1.0},
611 {GDK_AXIS_XTILT, -1.0, 1.0},
612 {GDK_AXIS_YTILT, -1.0, 1.0},
613 {GDK_AXIS_WHEEL, 0.0, 1.0}};
614 GdkDeviceKey stylusKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0},
615 {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}};
618 GdkDeviceAxis coreAxes[] = {{GDK_AXIS_X, 0.0, 0.0},
619 {GDK_AXIS_Y, 0.0, 0.0}};
621 static void createFakeList() {
622 if ( !fakeList ) {
623 fakeout[0].name = g_strdup("pad");
624 fakeout[0].source = GDK_SOURCE_PEN;
625 fakeout[0].mode = GDK_MODE_SCREEN;
626 fakeout[0].has_cursor = TRUE;
627 fakeout[0].num_axes = 6;
628 fakeout[0].axes = padAxes;
629 fakeout[0].num_keys = 8;
630 fakeout[0].keys = padKeys;
632 fakeout[1].name = g_strdup("eraser");
633 fakeout[1].source = GDK_SOURCE_ERASER;
634 fakeout[1].mode = GDK_MODE_SCREEN;
635 fakeout[1].has_cursor = TRUE;
636 fakeout[1].num_axes = 6;
637 fakeout[1].axes = eraserAxes;
638 fakeout[1].num_keys = 7;
639 fakeout[1].keys = eraserKeys;
641 fakeout[2].name = g_strdup("cursor");
642 fakeout[2].source = GDK_SOURCE_CURSOR;
643 fakeout[2].mode = GDK_MODE_SCREEN;
644 fakeout[2].has_cursor = TRUE;
645 fakeout[2].num_axes = 6;
646 fakeout[2].axes = cursorAxes;
647 fakeout[2].num_keys = 7;
648 fakeout[2].keys = cursorKeys;
650 fakeout[3].name = g_strdup("stylus");
651 fakeout[3].source = GDK_SOURCE_PEN;
652 fakeout[3].mode = GDK_MODE_SCREEN;
653 fakeout[3].has_cursor = TRUE;
654 fakeout[3].num_axes = 6;
655 fakeout[3].axes = stylusAxes;
656 fakeout[3].num_keys = 7;
657 fakeout[3].keys = stylusKeys;
659 // try to find the first *real* core pointer
660 GList* devList = gdk_devices_list();
661 while ( devList && devList->data && (((GdkDevice*)devList->data)->source != GDK_SOURCE_MOUSE) ) {
662 devList = g_list_next(devList);
663 }
664 if ( devList && devList->data ) {
665 fakeout[4] = *((GdkDevice*)devList->data);
666 } else {
667 fakeout[4].name = g_strdup("Core Pointer");
668 fakeout[4].source = GDK_SOURCE_MOUSE;
669 fakeout[4].mode = GDK_MODE_SCREEN;
670 fakeout[4].has_cursor = TRUE;
671 fakeout[4].num_axes = 2;
672 fakeout[4].axes = coreAxes;
673 fakeout[4].num_keys = 0;
674 fakeout[4].keys = NULL;
675 }
677 for ( guint pos = 0; pos < G_N_ELEMENTS(fakeout); pos++) {
678 fakeList = g_list_append(fakeList, &(fakeout[pos]));
679 }
680 }
681 }
684 /*
685 Local Variables:
686 mode:c++
687 c-file-style:"stroustrup"
688 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
689 indent-tabs-mode:nil
690 fill-column:99
691 End:
692 */
693 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :