/* * Inkscape::DeviceManager - a view of input devices available. * * Copyright 2010 Jon A. Cruz * * Released under GNU GPL, read the file 'COPYING' for more information */ #include #include #include #include "device-manager.h" #include "preferences.h" #include #define noDEBUG_VERBOSE 1 // This is a copy of the private fields of the GdkDevice object, used in order // to create a list of "fake" devices. struct GdkDeviceFake { gchar *name; GdkInputSource source; GdkInputMode mode; gboolean has_cursor; gint num_axes; // GdkDeviceAxis *axes; gint num_keys; // GdkDeviceKey *keys; }; static void createFakeList(); GdkDeviceFake fakeout[5]; static GList* fakeList = 0; static bool isValidDevice(GdkDevice *device) { bool valid = true; for (size_t i = 0; (i < G_N_ELEMENTS(fakeout)) && valid; i++) { // Ideally, we should probably check all fields of the GdkDevice #if GTK_CHECK_VERSION (2, 22, 0) gboolean name_matches = (g_strcmp0 (gdk_device_get_name (device), fakeout[i].name) == 0); gboolean source_matches = (gdk_device_get_source (device) == fakeout[i].source); gboolean mode_matches = (gdk_device_get_mode (device) == fakeout[i].mode); gboolean num_axes_matches = (gdk_device_get_n_axes (device) == fakeout[i].num_axes); #else gboolean name_matches = (g_strcmp0 (device->name, fakeout[i].name) == 0); gboolean source_matches = (device->source == fakeout[i].source); gboolean mode_matches = (device->mode == fakeout[i].mode); gboolean num_axes_matches = (device->num_axes == fakeout[i].num_axes); #endif #if GTK_CHECK_VERSION (2, 24, 0) gboolean num_keys_matches = (gdk_device_get_n_keys (device) == fakeout[i].num_keys); #else gboolean num_keys_matches = (device->num_keys == fakeout[i].num_keys); #endif if (name_matches && source_matches && mode_matches && num_axes_matches && num_keys_matches) valid = false; } return valid; } namespace Inkscape { using std::pair; static pair vals[] = { pair(0, 1), pair(1, 1 << 1), pair(2, 1 << 2), pair(3, 1 << 3), pair(4, 1 << 4), pair(5, 1 << 5), pair(6, 1 << 6), pair(7, 1 << 7), pair(8, 1 << 8), pair(9, 1 << 9), pair(10, 1 << 10), pair(11, 1 << 11), pair(12, 1 << 12), pair(13, 1 << 13), pair(14, 1 << 14), pair(15, 1 << 15), pair(16, 1 << 16), pair(17, 1 << 17), pair(18, 1 << 18), pair(19, 1 << 19), pair(20, 1 << 20), pair(21, 1 << 21), pair(22, 1 << 22), pair(23, 1 << 23) }; static std::map bitVals(vals, &vals[G_N_ELEMENTS(vals)]); static const int RUNAWAY_MAX = 1000; static Glib::ustring getBaseDeviceName(Gdk::InputSource source) { Glib::ustring name; switch (source) { case GDK_SOURCE_MOUSE: name ="pointer"; break; case GDK_SOURCE_PEN: name ="pen"; break; case GDK_SOURCE_ERASER: name ="eraser"; break; case GDK_SOURCE_CURSOR: name ="cursor"; break; default: name = "tablet"; } return name; } static std::map &getStringToAxis() { static bool init = false; static std::map mapping; if (!init) { init = true; mapping["ignore"] = Gdk::AXIS_IGNORE; mapping["x"] = Gdk::AXIS_X; mapping["y"] = Gdk::AXIS_Y; mapping["pressure"] = Gdk::AXIS_PRESSURE; mapping["xtilt"] = Gdk::AXIS_XTILT; mapping["ytilt"] = Gdk::AXIS_YTILT; mapping["wheel"] = Gdk::AXIS_WHEEL; } return mapping; } std::map &getAxisToString() { static bool init = false; static std::map mapping; if (!init) { init = true; for (std::map::iterator it = getStringToAxis().begin(); it != getStringToAxis().end(); ++it) { mapping.insert(std::make_pair(it->second, it->first)); } } return mapping; } static std::map &getStringToMode() { static bool init = false; static std::map mapping; if (!init) { init = true; mapping["disabled"] = Gdk::MODE_DISABLED; mapping["screen"] = Gdk::MODE_SCREEN; mapping["window"] = Gdk::MODE_WINDOW; } return mapping; } std::map &getModeToString() { static bool init = false; static std::map mapping; if (!init) { init = true; for (std::map::iterator it = getStringToMode().begin(); it != getStringToMode().end(); ++it) { mapping.insert(std::make_pair(it->second, it->first)); } } return mapping; } InputDevice::InputDevice() : Glib::Object() {} InputDevice::~InputDevice() {} class InputDeviceImpl : public InputDevice { public: InputDeviceImpl(GdkDevice* device, std::set &knownIDs); virtual ~InputDeviceImpl() {} virtual Glib::ustring getId() const {return id;} virtual Glib::ustring getName() const {return name;} virtual Gdk::InputSource getSource() const {return source;} #if GTK_CHECK_VERSION (2, 22, 0) virtual Gdk::InputMode getMode() const {return static_cast(gdk_device_get_mode (device));} virtual gint getNumAxes() const {return gdk_device_get_n_axes (device);} virtual bool hasCursor() const {return gdk_device_get_has_cursor (device);} #else virtual Gdk::InputMode getMode() const {return static_cast(device->mode);} virtual gint getNumAxes() const {return device->num_axes;} virtual bool hasCursor() const {return device->has_cursor;} #endif virtual gint getNumKeys() const { // Backward-compatibility: The GSEAL-compliant // gdk_device_get_n_keys function was only introduced // with GTK 2.24 #if GTK_CHECK_VERSION(2, 24, 0) return gdk_device_get_n_keys (device); #else return device->num_keys; #endif // GTK_CHECK_VERSION } virtual Glib::ustring getLink() const {return link;} virtual void setLink( Glib::ustring const& link ) {this->link = link;} virtual gint getLiveAxes() const {return liveAxes;} virtual void setLiveAxes(gint axes) {liveAxes = axes;} virtual gint getLiveButtons() const {return liveButtons;} virtual void setLiveButtons(gint buttons) {liveButtons = buttons;} // internal methods not on public superclass: virtual GdkDevice *getDevice() { return device; } private: InputDeviceImpl(InputDeviceImpl const &); // no copy void operator=(InputDeviceImpl const &); // no assign static Glib::ustring createId(Glib::ustring const &id, Gdk::InputSource source, std::set &knownIDs); GdkDevice* device; Glib::ustring id; Glib::ustring name; Gdk::InputSource source; Glib::ustring link; guint liveAxes; guint liveButtons; }; class IdMatcher : public std::unary_function&, bool> { public: IdMatcher(Glib::ustring const& target):target(target) {} bool operator ()(Glib::RefPtr& dev) {return dev && (target == dev->getId());} private: Glib::ustring const& target; }; class LinkMatcher : public std::unary_function&, bool> { public: LinkMatcher(Glib::ustring const& target):target(target) {} bool operator ()(Glib::RefPtr& dev) {return dev && (target == dev->getLink());} private: Glib::ustring const& target; }; InputDeviceImpl::InputDeviceImpl(GdkDevice* device, std::set &knownIDs) : InputDevice(), device(device), id(), #if GTK_CHECK_VERSION (2, 22, 0) name(gdk_device_get_name (device) ? gdk_device_get_name (device) : ""), source(static_cast(gdk_device_get_source (device))), #else name(device->name ? device->name : ""), source(static_cast(device->source)), #endif link(), liveAxes(0), liveButtons(0) { id = createId(name, source, knownIDs); } Glib::ustring InputDeviceImpl::createId(Glib::ustring const &id, Gdk::InputSource source, std::set &knownIDs) { // Start with only allowing printable ASCII. Check later for more refinements. bool badName = id.empty() || !id.is_ascii(); for (Glib::ustring::const_iterator it = id.begin(); (it != id.end()) && !badName; ++it) { badName = *it < 0x20; } Glib::ustring base; switch ( source ) { case Gdk::SOURCE_MOUSE: base = "M:"; break; case Gdk::SOURCE_CURSOR: base = "C:"; break; case Gdk::SOURCE_PEN: base = "P:"; break; case Gdk::SOURCE_ERASER: base = "E:"; break; default: base = "?:"; } if (badName) { base += getBaseDeviceName(source); } else { base += id; } // now ensure that all IDs become unique in a session. int num = 1; Glib::ustring result = base; while ((knownIDs.find(result) != knownIDs.end()) && (num < RUNAWAY_MAX)) { result = Glib::ustring::compose("%1%2", base, ++num); } knownIDs.insert(result); return result; } class DeviceManagerImpl : public DeviceManager { public: DeviceManagerImpl(); virtual void loadConfig(); virtual void saveConfig(); virtual std::list > getDevices(); virtual sigc::signal > signalDeviceChanged(); virtual sigc::signal > signalAxesChanged(); virtual sigc::signal > signalButtonsChanged(); virtual sigc::signal > signalLinkChanged(); virtual void addAxis(Glib::ustring const & id, gint axis); virtual void addButton(Glib::ustring const & id, gint button); virtual void setLinkedTo(Glib::ustring const & id, Glib::ustring const& link); virtual void setMode( Glib::ustring const & id, Gdk::InputMode mode ); virtual void setAxisUse( Glib::ustring const & id, guint index, Gdk::AxisUse use ); virtual void setKey( Glib::ustring const & id, guint index, guint keyval, Gdk::ModifierType mods ); protected: std::list > devices; sigc::signal > signalDeviceChangedPriv; sigc::signal > signalAxesChangedPriv; sigc::signal > signalButtonsChangedPriv; sigc::signal > signalLinkChangedPriv; }; DeviceManagerImpl::DeviceManagerImpl() : DeviceManager(), devices() { #if GTK_CHECK_VERSION(3,0,0) GdkDisplay *display = gdk_display_get_default(); GdkDeviceManager *dm = gdk_display_get_device_manager(display); GList* devList = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_SLAVE); #else GList* devList = gdk_devices_list(); #endif if ( !fakeList ) { createFakeList(); } //devList = fakeList; std::set knownIDs; for ( GList* curr = devList; curr; curr = g_list_next(curr) ) { GdkDevice* dev = reinterpret_cast(curr->data); if ( dev ) { #if DEBUG_VERBOSE 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, dev->has_cursor?"Yes":"no", dev->num_axes, dev->num_keys); #endif InputDeviceImpl* device = new InputDeviceImpl(dev, knownIDs); device->reference(); devices.push_back(Glib::RefPtr(device)); } } #if GTK_CHECK_VERSION(3,0,0) g_list_free(devList); #endif } void DeviceManagerImpl::loadConfig() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); for (std::list >::iterator it = devices.begin(); it != devices.end(); ++it) { if ((*it)->getSource() != Gdk::SOURCE_MOUSE) { Glib::ustring path = "/devices/" + (*it)->getId(); Gdk::InputMode mode = Gdk::MODE_DISABLED; Glib::ustring val = prefs->getString(path + "/mode"); if (getStringToMode().find(val) != getStringToMode().end()) { mode = getStringToMode()[val]; } if ((*it)->getMode() != mode) { setMode( (*it)->getId(), mode ); } // val = prefs->getString(path + "/axes"); if (!val.empty()) { std::vector parts = Glib::Regex::split_simple(";", val); for (size_t i = 0; i < parts.size(); ++i) { Glib::ustring name = parts[i]; if (getStringToAxis().find(name) != getStringToAxis().end()) { Gdk::AxisUse use = getStringToAxis()[name]; setAxisUse( (*it)->getId(), i, use ); } } } val = prefs->getString(path + "/keys"); if (!val.empty()) { std::vector parts = Glib::Regex::split_simple(";", val); for (size_t i = 0; i < parts.size(); ++i) { Glib::ustring keyStr = parts[i]; if (!keyStr.empty()) { guint key = 0; GdkModifierType mods = static_cast(0); gtk_accelerator_parse( keyStr.c_str(), &key, &mods ); setKey( (*it)->getId(), i, key, static_cast(mods) ); } } } } } } void DeviceManagerImpl::saveConfig() { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); for (std::list >::iterator it = devices.begin(); it != devices.end(); ++it) { if ((*it)->getSource() != Gdk::SOURCE_MOUSE) { Glib::ustring path = "/devices/" + (*it)->getId(); prefs->setString( path + "/mode", getModeToString()[(*it)->getMode()].c_str() ); Glib::ustring tmp; for (gint i = 0; i < (*it)->getNumAxes(); ++i) { if (i > 0) { tmp += ";"; } GdkDevice *device = (*it)->getDevice(); #if GTK_CHECK_VERSION (2, 22, 0) tmp += getAxisToString()[static_cast(gdk_device_get_axis_use (device, i))]; #else tmp += getAxisToString()[static_cast(device->axes[i].use)]; #endif } prefs->setString( path + "/axes", tmp ); tmp = ""; for (gint i = 0; i < (*it)->getNumKeys(); ++i) { if (i > 0) { tmp += ";"; } GdkDevice *device = (*it)->getDevice(); #if GTK_CHECK_VERSION (2, 22, 0) guint keyval; GdkModifierType modifiers; gdk_device_get_key (device, i, &keyval, &modifiers); tmp += gtk_accelerator_name(keyval, modifiers); #else tmp += gtk_accelerator_name(device->keys[i].keyval, device->keys[i].modifiers); #endif } prefs->setString( path + "/keys", tmp ); } } } std::list > DeviceManagerImpl::getDevices() { std::list > tmp; for ( std::list >::const_iterator it = devices.begin(); it != devices.end(); ++it ) { tmp.push_back(*it); } return tmp; } void DeviceManagerImpl::setMode( Glib::ustring const & id, Gdk::InputMode mode ) { std::list >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id)); if ( it != devices.end() ) { if (isValidDevice((*it)->getDevice()) && ((*it)->getMode() != mode) ) { bool success = gdk_device_set_mode((*it)->getDevice(), static_cast(mode)); if (success) { signalDeviceChangedPriv.emit(*it); } else { g_warning("Unable to set mode on extended input device [%s]", (*it)->getId().c_str()); } } } } void DeviceManagerImpl::setAxisUse( Glib::ustring const & id, guint index, Gdk::AxisUse use ) { std::list >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id)); if ( it != devices.end() ) { if (isValidDevice((*it)->getDevice())) { if (static_cast(index) <= (*it)->getNumAxes()) { GdkDevice *device = (*it)->getDevice(); #if GTK_CHECK_VERSION (2, 22, 0) if (gdk_device_get_axis_use (device, index) != static_cast(use)) { #else if (device->axes[index].use != static_cast(use)) { #endif gdk_device_set_axis_use(device, index, static_cast(use)); signalDeviceChangedPriv.emit(*it); } } else { g_warning("Invalid device axis number %d on extended input device [%s]", index, (*it)->getId().c_str()); } } } } void DeviceManagerImpl::setKey( Glib::ustring const & id, guint index, guint keyval, Gdk::ModifierType mods ) { //static void setDeviceKey( GdkDevice* device, guint index, guint keyval, GdkModifierType modifiers ) // std::list >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id)); if ( it != devices.end() ) { if (isValidDevice((*it)->getDevice())) { gdk_device_set_key((*it)->getDevice(), index, keyval, static_cast(mods)); signalDeviceChangedPriv.emit(*it); } } } sigc::signal > DeviceManagerImpl::signalDeviceChanged() { return signalDeviceChangedPriv; } sigc::signal > DeviceManagerImpl::signalAxesChanged() { return signalAxesChangedPriv; } sigc::signal > DeviceManagerImpl::signalButtonsChanged() { return signalButtonsChangedPriv; } sigc::signal > DeviceManagerImpl::signalLinkChanged() { return signalLinkChangedPriv; } void DeviceManagerImpl::addAxis(Glib::ustring const & id, gint axis) { if ( axis >= 0 && axis < static_cast(bitVals.size()) ) { std::list >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id)); if ( it != devices.end() ) { gint mask = bitVals[axis]; if ( (mask & (*it)->getLiveAxes()) == 0 ) { (*it)->setLiveAxes((*it)->getLiveAxes() | mask); // Only signal if a new axis was added (*it)->reference(); signalAxesChangedPriv.emit(*it); } } } } void DeviceManagerImpl::addButton(Glib::ustring const & id, gint button) { if ( button >= 0 && button < static_cast(bitVals.size()) ) { std::list >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id)); if ( it != devices.end() ) { gint mask = bitVals[button]; if ( (mask & (*it)->getLiveButtons()) == 0 ) { (*it)->setLiveButtons((*it)->getLiveButtons() | mask); // Only signal if a new button was added (*it)->reference(); signalButtonsChangedPriv.emit(*it); } } } } void DeviceManagerImpl::setLinkedTo(Glib::ustring const & id, Glib::ustring const& link) { std::list >::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id)); if ( it != devices.end() ) { Glib::RefPtr dev = *it; Glib::RefPtr targetDev; if ( !link.empty() ) { // Need to be sure the target of the link exists it = std::find_if(devices.begin(), devices.end(), IdMatcher(link)); if ( it != devices.end() ) { targetDev = *it; } } if ( (link.empty() && !dev->getLink().empty()) || (targetDev && (targetDev->getLink() != id)) ) { // only muck about if they aren't already linked std::list > changedItems; if ( targetDev ) { // Is something else already using that link? it = std::find_if(devices.begin(), devices.end(), LinkMatcher(link)); if ( it != devices.end() ) { (*it)->setLink(""); changedItems.push_back(*it); } } it = std::find_if(devices.begin(), devices.end(), LinkMatcher(id)); if ( it != devices.end() ) { (*it)->setLink(""); changedItems.push_back(*it); } if ( targetDev ) { targetDev->setLink(id); changedItems.push_back(targetDev); } dev->setLink(link); changedItems.push_back(dev); for ( std::list >::const_iterator iter = changedItems.begin(); iter != changedItems.end(); ++iter ) { (*iter)->reference(); signalLinkChangedPriv.emit(*iter); } } } } static DeviceManagerImpl* theInstance = 0; DeviceManager::DeviceManager() : Glib::Object() { } DeviceManager::~DeviceManager() { } DeviceManager& DeviceManager::getManager() { if ( !theInstance ) { theInstance = new DeviceManagerImpl(); } return *theInstance; } } // namespace Inkscape /* FIXME: Device Axis and Key details are inaccessible in GTK+ 3 * and are deprecated in GTK+ 2. Perhaps there is a way of specifying * this in underlying API? * GdkDeviceAxis padAxes[] = {{GDK_AXIS_X, 0.0, 0.0}, {GDK_AXIS_Y, 0.0, 0.0}, {GDK_AXIS_PRESSURE, 0.0, 1.0}, {GDK_AXIS_XTILT, -1.0, 1.0}, {GDK_AXIS_YTILT, -1.0, 1.0}, {GDK_AXIS_WHEEL, 0.0, 1.0}}; GdkDeviceKey padKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}}; GdkDeviceAxis eraserAxes[] = {{GDK_AXIS_X, 0.0, 0.0}, {GDK_AXIS_Y, 0.0, 0.0}, {GDK_AXIS_PRESSURE, 0.0, 1.0}, {GDK_AXIS_XTILT, -1.0, 1.0}, {GDK_AXIS_YTILT, -1.0, 1.0}, {GDK_AXIS_WHEEL, 0.0, 1.0}}; GdkDeviceKey eraserKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}}; GdkDeviceAxis cursorAxes[] = {{GDK_AXIS_X, 0.0, 0.0}, {GDK_AXIS_Y, 0.0, 0.0}, {GDK_AXIS_PRESSURE, 0.0, 1.0}, {GDK_AXIS_XTILT, -1.0, 1.0}, {GDK_AXIS_YTILT, -1.0, 1.0}, {GDK_AXIS_WHEEL, 0.0, 1.0}}; GdkDeviceKey cursorKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}}; GdkDeviceAxis stylusAxes[] = {{GDK_AXIS_X, 0.0, 0.0}, {GDK_AXIS_Y, 0.0, 0.0}, {GDK_AXIS_PRESSURE, 0.0, 1.0}, {GDK_AXIS_XTILT, -1.0, 1.0}, {GDK_AXIS_YTILT, -1.0, 1.0}, {GDK_AXIS_WHEEL, 0.0, 1.0}}; GdkDeviceKey stylusKeys[] = {{0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}, {0, (GdkModifierType)0}}; GdkDeviceAxis coreAxes[] = {{GDK_AXIS_X, 0.0, 0.0}, {GDK_AXIS_Y, 0.0, 0.0}}; */ static void createFakeList() { if ( !fakeList ) { fakeout[0].name = g_strdup("pad"); fakeout[0].source = GDK_SOURCE_PEN; fakeout[0].mode = GDK_MODE_SCREEN; fakeout[0].has_cursor = TRUE; fakeout[0].num_axes = 6; // fakeout[0].axes = padAxes; fakeout[0].num_keys = 8; // fakeout[0].keys = padKeys; fakeout[1].name = g_strdup("eraser"); fakeout[1].source = GDK_SOURCE_ERASER; fakeout[1].mode = GDK_MODE_SCREEN; fakeout[1].has_cursor = TRUE; fakeout[1].num_axes = 6; // fakeout[1].axes = eraserAxes; fakeout[1].num_keys = 7; // fakeout[1].keys = eraserKeys; fakeout[2].name = g_strdup("cursor"); fakeout[2].source = GDK_SOURCE_CURSOR; fakeout[2].mode = GDK_MODE_SCREEN; fakeout[2].has_cursor = TRUE; fakeout[2].num_axes = 6; // fakeout[2].axes = cursorAxes; fakeout[2].num_keys = 7; // fakeout[2].keys = cursorKeys; fakeout[3].name = g_strdup("stylus"); fakeout[3].source = GDK_SOURCE_PEN; fakeout[3].mode = GDK_MODE_SCREEN; fakeout[3].has_cursor = TRUE; fakeout[3].num_axes = 6; // fakeout[3].axes = stylusAxes; fakeout[3].num_keys = 7; // fakeout[3].keys = stylusKeys; // try to find the first *real* core pointer #if GTK_CHECK_VERSION(3,0,0) GdkDisplay *display = gdk_display_get_default(); GdkDeviceManager *dm = gdk_display_get_device_manager(display); GList* devList = gdk_device_manager_list_devices(dm, GDK_DEVICE_TYPE_SLAVE); #else GList* devList = gdk_devices_list(); #endif #if GTK_CHECK_VERSION (2, 22, 0) while ( devList && devList->data && (gdk_device_get_source ((GdkDevice*)devList->data) != GDK_SOURCE_MOUSE)) { #else while ( devList && devList->data && (((GdkDevice*)devList->data)->source != GDK_SOURCE_MOUSE)) { #endif devList = g_list_next(devList); } if ( devList && devList->data ) { //fakeout[4] = *((GdkDevice*)devList->data); // We should probably copy the axes and keys too GdkDevice *device = (GdkDevice*)devList->data; #if GTK_CHECK_VERSION (2, 22, 0) fakeout[4].name = g_strdup(gdk_device_get_name (device)); fakeout[4].source = gdk_device_get_source (device); fakeout[4].mode = gdk_device_get_mode (device); fakeout[4].has_cursor = gdk_device_get_has_cursor (device); fakeout[4].num_axes = gdk_device_get_n_axes (device); #else fakeout[4].name = g_strdup(device->name); fakeout[4].source = device->source; fakeout[4].mode = device->mode; fakeout[4].has_cursor = device->has_cursor; fakeout[4].num_axes = device->num_axes; #endif #if GTK_CHECK_VERSION (2, 24, 0) fakeout[4].num_keys = gdk_device_get_n_keys (device); #else fakeout[4].num_keys = device->num_keys; #endif } else { fakeout[4].name = g_strdup("Core Pointer"); fakeout[4].source = GDK_SOURCE_MOUSE; fakeout[4].mode = GDK_MODE_SCREEN; fakeout[4].has_cursor = TRUE; fakeout[4].num_axes = 2; // fakeout[4].axes = coreAxes; fakeout[4].num_keys = 0; // fakeout[4].keys = NULL; } for ( guint pos = 0; pos < G_N_ELEMENTS(fakeout); pos++) { fakeList = g_list_append(fakeList, &(fakeout[pos])); } #if GTK_CHECK_VERSION(3,0,0) g_list_free(devList); #endif } } /* Local Variables: mode:c++ c-file-style:"stroustrup" c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) indent-tabs-mode:nil fill-column:99 End: */ // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :