device-manager.cpp revision eaa4f8464b53be0b2b1bb7d0a06f70c7f3d43b0e
/*
* Inkscape::DeviceManager - a view of input devices available.
*
* Copyright 2006 Jon A. Cruz <jon@joncruz.org>
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <glib.h>
#include <map>
#include "device-manager.h"
static void createFakeList();
GdkDevice fakeout[5];
static GList* fakeList = 0;
namespace Inkscape {
using std::pair;
static pair<gint, gint> vals[] = {
pair<gint, gint>(0, 1), pair<gint, gint>(1, 1 << 1), pair<gint, gint>(2, 1 << 2), pair<gint, gint>(3, 1 << 3),
pair<gint, gint>(4, 1 << 4), pair<gint, gint>(5, 1 << 5), pair<gint, gint>(6, 1 << 6), pair<gint, gint>(7, 1 << 7),
pair<gint, gint>(8, 1 << 8), pair<gint, gint>(9, 1 << 9), pair<gint, gint>(10, 1 << 10), pair<gint, gint>(11, 1 << 11),
pair<gint, gint>(12, 1 << 12), pair<gint, gint>(13, 1 << 13), pair<gint, gint>(14, 1 << 14), pair<gint, gint>(15, 1 << 15),
pair<gint, gint>(16, 1 << 16), pair<gint, gint>(17, 1 << 17), pair<gint, gint>(18, 1 << 18), pair<gint, gint>(19, 1 << 19),
pair<gint, gint>(20, 1 << 20), pair<gint, gint>(21, 1 << 21), pair<gint, gint>(22, 1 << 22), pair<gint, gint>(23, 1 << 23)
};
static std::map<gint, gint> bitVals(vals, &vals[G_N_ELEMENTS(vals)]);
InputDevice::InputDevice()
: Glib::Object()
{}
InputDevice::~InputDevice() {}
class InputDeviceImpl : public InputDevice {
public:
virtual Glib::ustring getId() const {return id;}
virtual Glib::ustring getName() const {return name;}
virtual Gdk::InputSource getSource() const {return source;}
virtual Gdk::InputMode getMode() const {return static_cast<Gdk::InputMode>(device->mode);}
virtual bool hasCursor() const {return device->has_cursor;}
virtual gint getNumAxes() const {return device->num_axes;}
virtual gint getNumKeys() const {return device->num_keys;}
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;}
InputDeviceImpl(GdkDevice* device);
virtual ~InputDeviceImpl() {}
private:
InputDeviceImpl(InputDeviceImpl const &); // no copy
void operator=(InputDeviceImpl const &); // no assign
GdkDevice* device;
Glib::ustring id;
Glib::ustring name;
Gdk::InputSource source;
Glib::ustring link;
guint liveAxes;
guint liveButtons;
};
class IdMatcher : public std::unary_function<InputDeviceImpl*, bool> {
public:
IdMatcher(Glib::ustring const& target):target(target) {}
bool operator ()(InputDeviceImpl* dev) {return dev && (target == dev->getId());}
private:
Glib::ustring const& target;
};
class LinkMatcher : public std::unary_function<InputDeviceImpl*, bool> {
public:
LinkMatcher(Glib::ustring const& target):target(target) {}
bool operator ()(InputDeviceImpl* dev) {return dev && (target == dev->getLink());}
private:
Glib::ustring const& target;
};
InputDeviceImpl::InputDeviceImpl(GdkDevice* device)
: InputDevice(),
device(device),
id(),
name(device->name ? device->name : ""),
source(static_cast<Gdk::InputSource>(device->source)),
link(),
liveAxes(0),
liveButtons(0)
{
switch ( source ) {
case Gdk::SOURCE_MOUSE:
id = "M:";
break;
case Gdk::SOURCE_CURSOR:
id = "C:";
break;
case Gdk::SOURCE_PEN:
id = "P:";
break;
case Gdk::SOURCE_ERASER:
id = "E:";
break;
default:
id = "?:";
}
id += name;
}
class DeviceManagerImpl : public DeviceManager {
public:
DeviceManagerImpl();
virtual std::list<InputDevice const *> getDevices();
virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalDeviceChanged();
virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalAxesChanged();
virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalButtonsChanged();
virtual sigc::signal<void, const Glib::RefPtr<InputDevice>& > 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);
protected:
std::list<InputDeviceImpl*> devices;
sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalDeviceChangedPriv;
sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalAxesChangedPriv;
sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalButtonsChangedPriv;
sigc::signal<void, const Glib::RefPtr<InputDevice>& > signalLinkChangedPriv;
};
DeviceManagerImpl::DeviceManagerImpl() :
DeviceManager(),
devices()
{
GList* devList = gdk_devices_list();
if ( !fakeList ) {
createFakeList();
}
// devList = fakeList;
for ( GList* curr = devList; curr; curr = g_list_next(curr) ) {
GdkDevice* dev = reinterpret_cast<GdkDevice*>(curr->data);
if ( dev ) {
// 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);
InputDeviceImpl* device = new InputDeviceImpl(dev);
devices.push_back(device);
}
}
}
std::list<InputDevice const *> DeviceManagerImpl::getDevices()
{
std::list<InputDevice const *> tmp;
for ( std::list<InputDeviceImpl*>::const_iterator it = devices.begin(); it != devices.end(); ++it ) {
tmp.push_back(*it);
}
return tmp;
}
sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalDeviceChanged()
{
return signalDeviceChangedPriv;
}
sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalAxesChanged()
{
return signalAxesChangedPriv;
}
sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalButtonsChanged()
{
return signalButtonsChangedPriv;
}
sigc::signal<void, const Glib::RefPtr<InputDevice>& > DeviceManagerImpl::signalLinkChanged()
{
return signalLinkChangedPriv;
}
void DeviceManagerImpl::addAxis(Glib::ustring const & id, gint axis)
{
if ( axis >= 0 && axis < static_cast<gint>(bitVals.size()) ) {
std::list<InputDeviceImpl*>::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(Glib::RefPtr<InputDevice>(*it));
}
}
}
}
void DeviceManagerImpl::addButton(Glib::ustring const & id, gint button)
{
if ( button >= 0 && button < static_cast<gint>(bitVals.size()) ) {
std::list<InputDeviceImpl*>::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(Glib::RefPtr<InputDevice>(*it));
}
}
}
}
void DeviceManagerImpl::setLinkedTo(Glib::ustring const & id, Glib::ustring const& link)
{
std::list<InputDeviceImpl*>::iterator it = std::find_if(devices.begin(), devices.end(), IdMatcher(id));
if ( it != devices.end() ) {
InputDeviceImpl* dev = *it;
InputDeviceImpl* targetDev = 0;
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<InputDeviceImpl*> 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<InputDeviceImpl*>::const_iterator iter = changedItems.begin(); iter != changedItems.end(); ++iter ) {
(*iter)->reference();
signalLinkChangedPriv.emit(Glib::RefPtr<InputDevice>(*iter));
}
}
}
}
static DeviceManagerImpl* theInstance = 0;
DeviceManager::DeviceManager()
: Glib::Object()
{
}
DeviceManager::~DeviceManager() {
}
DeviceManager& DeviceManager::getManager() {
if ( !theInstance ) {
theInstance = new DeviceManagerImpl();
}
return *theInstance;
}
} // namespace Inkscape
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 = "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 = "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 = "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 = "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
GList* devList = gdk_devices_list();
while ( devList && devList->data && (((GdkDevice*)devList->data)->source != GDK_SOURCE_MOUSE) ) {
devList = g_list_next(devList);
}
if ( devList && devList->data ) {
fakeout[4] = *((GdkDevice*)devList->data);
} else {
fakeout[4].name = "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]));
}
}
}
/*
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:encoding=utf-8:textwidth=99 :