summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Braun2010-10-04 00:22:14 +0200
committerSebastien Braun2010-10-05 18:15:48 +0200
commit266eb5fb14c07e67aa211a5860e9abf3009136e3 (patch)
tree9eeb8b159edf6e83880c056f1177cebec2ad354c
parentDefect #715, apply patch by Sébastien (diff)
downloadpvs-266eb5fb14c07e67aa211a5860e9abf3009136e3.tar.gz
pvs-266eb5fb14c07e67aa211a5860e9abf3009136e3.tar.xz
pvs-266eb5fb14c07e67aa211a5860e9abf3009136e3.zip
Implement first version of basic input event support
-rw-r--r--CMakeLists.txt12
-rw-r--r--icons/README3
-rw-r--r--icons/remote-control-all.pngbin0 -> 5365 bytes
-rw-r--r--icons/remote-control.pngbin0 -> 3657 bytes
-rw-r--r--pvsmgr.qrc2
-rw-r--r--src/gui/frame.cpp246
-rw-r--r--src/gui/frame.h27
-rw-r--r--src/input/CMakeLists.txt19
-rw-r--r--src/input/inputEvent.cpp98
-rw-r--r--src/input/inputEvent.h218
-rw-r--r--src/input/inputEventHandler.h187
-rw-r--r--src/input/inputEventNonQt.cpp17
-rw-r--r--src/input/unprivilegedHandlerChain.h34
-rw-r--r--src/input/x11FakeKeyboardHandler.cpp800
-rw-r--r--src/input/x11FakeKeyboardHandler.h29
-rw-r--r--src/input/x11FakeMouseHandler.cpp59
-rw-r--r--src/input/x11FakeMouseHandler.h34
-rw-r--r--src/input/x11InputUtils.cpp29
-rw-r--r--src/input/x11InputUtils.h27
-rw-r--r--src/pvs.cpp24
-rw-r--r--src/pvs.h4
-rw-r--r--src/util/clientGUIUtils.cpp13
-rw-r--r--src/util/clientGUIUtils.h6
23 files changed, 1874 insertions, 14 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2153497..ec688b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,8 +29,16 @@ FIND_PACKAGE( VNC REQUIRED )
INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
+ ${X11_INCLUDE_DIR}
+ ${X11_XTest_INCLUDE_PATH}
)
+IF(NOT X11_XTest_FOUND)
+ MESSAGE(FATAL_ERROR "Could not find X11 extension XTest. It is needed for PVS")
+ENDIF()
+
+ADD_SUBDIRECTORY(src/input)
+
################################################################################
# Variables
################################################################################
@@ -299,18 +307,22 @@ TARGET_LINK_LIBRARIES( pvsmgr
${QT_LIBRARIES}
${VNC_LIBRARIES}
${X11_LIBRARIES}
+ pvsinput
)
TARGET_LINK_LIBRARIES( pvsmgrtouch
${QT_LIBRARIES}
${VNC_LIBRARIES}
${X11_LIBRARIES}
+ pvsinput
)
TARGET_LINK_LIBRARIES( pvs
${QT_LIBRARIES}
${VNC_LIBRARIES}
${X11_LIBRARIES}
+ ${X11_XTest_LIB}
+ pvsinput
)
TARGET_LINK_LIBRARIES( pvsgui
diff --git a/icons/README b/icons/README
new file mode 100644
index 0000000..823d998
--- /dev/null
+++ b/icons/README
@@ -0,0 +1,3 @@
+remote-control.png and remote-control-all.png have been taken from the
+Nuvola 1.0 Icon Set, generously provided under the LGPL by its designer,
+David Vignoni. See http://www.icon-king.com/projects/nuvola/
diff --git a/icons/remote-control-all.png b/icons/remote-control-all.png
new file mode 100644
index 0000000..bc7e2ae
--- /dev/null
+++ b/icons/remote-control-all.png
Binary files differ
diff --git a/icons/remote-control.png b/icons/remote-control.png
new file mode 100644
index 0000000..ba460dd
--- /dev/null
+++ b/icons/remote-control.png
Binary files differ
diff --git a/pvsmgr.qrc b/pvsmgr.qrc
index 171412e..cd26abc 100644
--- a/pvsmgr.qrc
+++ b/pvsmgr.qrc
@@ -19,6 +19,8 @@
<file alias="dozent2" >icons/dozent.png</file>
<file alias="chat" >icons/chat.png</file>
<file alias="cam32" >icons/cam32.svg</file>
+ <file alias="remotecontrol" >icons/remote-control.png</file>
+ <file alias="remotecontrolall" >icons/remote-control-all.png</file>
<file alias="AUTHORS">AUTHORS</file>
<file alias="TRANSLATION">TRANSLATION</file>
</qresource>
diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp
index cb79643..96ea26c 100644
--- a/src/gui/frame.cpp
+++ b/src/gui/frame.cpp
@@ -18,11 +18,14 @@
# -----------------------------------------------------------------------------
*/
+#include <src/input/inputEvent.h>
#include "frame.h"
#include <src/gui/mainWindow.h>
#include <iostream>
#include <QPixmap>
+#define MOUSE_MOTION_SEND_INTERVAL 100 /* msecs */
+
Frame::Frame(const QString & text, QWidget * parent) :
QLabel(parent), _clientVNCThread(0)
{
@@ -51,10 +54,25 @@ Frame::Frame(const QString & text, QWidget * parent) :
button_lock = createToolButton(tr("Lock this client"), QIcon(":/lock"),SLOT(setLock()));
//button_unlock = createToolButton(tr("Unlock this client"), QIcon(":/lock"),SLOT(setLock()));
button_dozent = createToolButton(tr("Set as Superclient"), QIcon(":/dozent2"),SLOT(setDozent()));
+ button_control = createToolButton(tr("Enable Remote Control"), QIcon(":/remotecontrol"), SLOT(remoteControlClicked()));
+ button_control->setCheckable(true);
+ button_control_all = createToolButton(tr("Remote Control All Clients"), QIcon(":/remotecontrolall"), SLOT(remoteControlAllClicked()));
+ button_control_all->setCheckable(true);
connect(this, SIGNAL(clicked()), this, SLOT(slotClicked()));
ip = "";
setToolButtonListVisible(false);
+
+ _remoteControlEnabled = false;
+ _remoteControlToAll = false;
+
+ _mouseMotionEventTimer = new QTimer(this);
+ _mouseMotionEventTimer->setInterval(MOUSE_MOTION_SEND_INTERVAL);
+ _mouseMotionEventTimer->setSingleShot(false);
+ connect(_mouseMotionEventTimer, SIGNAL(timeout()), this, SLOT(sendMouseMotionEvent()));
+
+ _mousePositionChanged = true;
+
}
Frame::~Frame()
@@ -216,23 +234,45 @@ void Frame::slotClicked()
void Frame::mousePressEvent(QMouseEvent* event)
{
- emit clicked();
- if (event->button() == Qt::RightButton)
- {
- /*if (!_dummy)
- DelDummy->setDisabled(true);
- menu->exec(QCursor::pos());*/
- }
- else
- {
+ if(!_remoteControlEnabled)
+ {
+ emit clicked();
+ if (event->button() == Qt::RightButton)
+ {
+ /*if (!_dummy)
+ DelDummy->setDisabled(true);
+ menu->exec(QCursor::pos());*/
+ }
+ else
+ {
- }
- QLabel::mousePressEvent(event);
+ }
+ QLabel::mousePressEvent(event);
+ }
+ else
+ {
+ event->accept();
+ ConsoleLog writeLine("Captured remote control mousePressEvent");
+
+ updateMousePosition(event);
+ sendInputEvent(InputEvent::mousePressRelease(event));
+ }
}
void Frame::mouseReleaseEvent ( QMouseEvent * event )
{
- QLabel::mouseReleaseEvent(event);
+ if(!_remoteControlEnabled)
+ {
+ QLabel::mouseReleaseEvent(event);
+ }
+ else
+ {
+ event->accept();
+ ConsoleLog writeLine("Captured remote control mouseReleaseEvent");
+
+ updateMousePosition(event);
+ sendInputEvent(InputEvent::mousePressRelease(event));
+ }
}
QToolButton* Frame::createToolButton(const QString &toolTip, const QIcon &icon, const char *member)
@@ -330,3 +370,185 @@ void Frame::setDozent()
getConFrame()->setDozent(true);
}
}
+
+void Frame::remoteControlClicked()
+{
+ if(_remoteControlEnabled)
+ {
+ setMouseTracking(false);
+ _mouseMotionEventTimer->stop();
+ button_control->setToolTip(tr("Enable Remote Control"));
+ _remoteControlEnabled = false;
+ button_control->setChecked(false);
+ releaseKeyboard();
+ }
+ else
+ {
+ button_control->setToolTip(tr("Disable Remote Control"));
+ _remoteControlEnabled = true;
+ button_control->setChecked(true);
+ _mouseMotionEventTimer->start();
+ setMouseTracking(true);
+ if(_mouseOver)
+ grabKeyboard();
+ }
+}
+
+void Frame::remoteControlAllClicked()
+{
+ if(_remoteControlToAll)
+ {
+ button_control_all->setToolTip(tr("Remote Control only this Client"));
+ button_control_all->setChecked(false);
+ _remoteControlToAll = false;
+ }
+ else
+ {
+ button_control_all->setToolTip(tr("Remote Control All Clients"));
+ button_control_all->setChecked(true);
+ _remoteControlToAll = true;
+ }
+}
+
+
+
+void Frame::sendMouseMotionEvent()
+{
+ InputEvent evt = InputEvent::mouseMotion(_lastRecordedMousePosition.x(), _lastRecordedMousePosition.y());
+
+ if(!_mousePositionChanged)
+ return;
+
+ _mousePositionChanged = false;
+ sendInputEvent(evt);
+}
+
+void Frame::sendInputEvent(InputEvent const& evt)
+{
+ QString str;
+ eventToString(evt, str);
+ std::string evtStr = evt.toString();
+ PVSMsg msg(PVSCOMMAND, "INPUTEVENT", str);
+
+ if(_remoteControlEnabled)
+ {
+ if(_remoteControlToAll)
+ {
+ ConsoleLog writeLine(QString("sendInputEvent(%1) to one").arg(evtStr.c_str()));
+ PVSConnectionManager::getManager()->getServer()->sendToAll(msg);
+ }
+ else
+ {
+ ConsoleLog writeLine(QString("sendInputEvent(%1) to all").arg(evtStr.c_str()));
+ _cFrame->getConnection()->sendMessage(msg);
+ }
+ }
+ else
+ {
+ ConsoleLog writeLine("sendMouseMotionEvent() disabled");
+ }
+}
+
+void Frame::mouseMoveEvent(QMouseEvent* event)
+{
+ QPoint newPosition = rescalePosition(event->posF());
+ if(newPosition != _lastRecordedMousePosition) {
+ _lastRecordedMousePosition = newPosition;
+ _mousePositionChanged = true;
+ ConsoleLog writeLine(QString("Mouse moved to (%1,%2)").arg(_lastRecordedMousePosition.x()).arg(_lastRecordedMousePosition.y()));
+ }
+}
+
+QPoint Frame::rescalePosition(QPointF guipos)
+{
+ QSize s = size();
+ QSize t = _clientVNCThread->getSize();
+ qreal px, py;
+ px = guipos.x() * t.width() / (qreal)s.width();
+ py = guipos.y() * t.height() / (qreal)s.height();
+ return QPoint((int)px, (int)py);
+}
+
+void Frame::updateMousePosition(QMouseEvent* event)
+{
+ QPoint oldPosition = _lastRecordedMousePosition;
+ _lastRecordedMousePosition = rescalePosition(event->posF());
+ _mousePositionChanged = oldPosition != _lastRecordedMousePosition;
+ sendMouseMotionEvent();
+}
+
+void Frame::enterEvent(QEvent* event)
+{
+ _mouseOver = true;
+ if(_remoteControlEnabled)
+ {
+ grabKeyboard();
+ }
+}
+
+void Frame::leaveEvent(QEvent* event)
+{
+ _mouseOver = false;
+ if(_remoteControlEnabled)
+ {
+ releaseKeyboard();
+ }
+}
+
+void Frame::keyPressEvent(QKeyEvent* event)
+{
+ if(_remoteControlEnabled)
+ {
+ // The action of the keyboard may depend on the position of the pointer
+ sendMouseMotionEvent();
+ InputEvent evt = InputEvent::keyboardPress(event);
+ sendInputEvent(evt);
+ }
+ else
+ {
+ QLabel::keyPressEvent(event);
+ }
+}
+
+void Frame::keyReleaseEvent(QKeyEvent* event)
+{
+ if(_remoteControlEnabled)
+ {
+ // The action of the keyboard may depend on the position of the pointer
+ sendMouseMotionEvent();
+ InputEvent evt = InputEvent::keyboardRelease(event);
+ sendInputEvent(evt);
+ }
+ else
+ {
+ QLabel::keyReleaseEvent(event);
+ }
+}
+
+bool Frame::event(QEvent* event)
+{
+ if(_remoteControlEnabled)
+ {
+ bool recognized;
+ switch(event->type())
+ {
+ case QEvent::ShortcutOverride:
+ recognized = true;
+ event->accept();
+ break;
+ case QEvent::KeyPress:
+ recognized = true;
+ keyPressEvent(static_cast<QKeyEvent*>(event));
+ break;
+ case QEvent::KeyRelease:
+ recognized = true;
+ keyReleaseEvent(static_cast<QKeyEvent*>(event));
+ break;
+ default:
+ recognized = false;
+ }
+ if(recognized && event->isAccepted())
+ return true;
+ }
+ return QLabel::event(event);
+}
diff --git a/src/gui/frame.h b/src/gui/frame.h
index 3004e0c..19b330a 100644
--- a/src/gui/frame.h
+++ b/src/gui/frame.h
@@ -8,6 +8,7 @@ class VNCClientThread;
class ConnectionWindow;
class ConnectionFrame;
class MainWindow;
+class InputEvent;
class Frame: public QLabel
{
@@ -48,8 +49,13 @@ public:
QToolButton* button_lock;
QToolButton* button_unlock;
QToolButton* button_dozent;
+ QToolButton* button_control;
+ QToolButton* button_control_all;
QList<QToolButton*> toolButtonList;
+ bool _remoteControlEnabled;
+ bool _remoteControlToAll;
+
public Q_SLOTS:
void updateImage(int x, int y, int w, int h);
void iamDown();
@@ -68,13 +74,23 @@ public Q_SLOTS:
void setLock();
//void unlock();
void setDozent();
+private Q_SLOTS:
+ void remoteControlClicked();
+ void remoteControlAllClicked();
+ void sendMouseMotionEvent();
signals:
- void clicked();
+ void clicked();
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent ( QMouseEvent * event );
void mouseReleaseEvent ( QMouseEvent * event );
+ void mouseMoveEvent ( QMouseEvent * event );
+ void enterEvent(QEvent* event);
+ void leaveEvent(QEvent* event);
+ void keyPressEvent(QKeyEvent* event);
+ void keyReleaseEvent(QKeyEvent* event);
+ bool event(QEvent* event);
private:
QToolButton* createToolButton(const QString &toolTip, const QIcon &icon, const char *member);
@@ -85,6 +101,15 @@ private:
bool _isLocked;
bool _dozent;
int _ux, _uy;
+
+ // for remote control:
+ QPoint _lastRecordedMousePosition;
+ bool _mousePositionChanged;
+ QTimer* _mouseMotionEventTimer;
+ bool _mouseOver;
+ QPoint rescalePosition(QPointF guiPosition);
+ void updateMousePosition(QMouseEvent* event);
+ void sendInputEvent(InputEvent const&);
};
#endif /* FRAME_H_ */
diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt
new file mode 100644
index 0000000..aa52ec3
--- /dev/null
+++ b/src/input/CMakeLists.txt
@@ -0,0 +1,19 @@
+INCLUDE(${QT_USE_FILE})
+
+SET(pvsinput_SRCS
+ inputEvent.cpp
+ )
+
+IF(UNIX)
+ list(APPEND pvsinput_SRCS
+ x11InputUtils.cpp
+ x11FakeKeyboardHandler.cpp
+ x11FakeMouseHandler.cpp)
+ENDIF()
+
+ADD_LIBRARY(
+ pvsinput
+ STATIC
+ ${pvsinput_HDRS}
+ ${pvsinput_SRCS}
+)
diff --git a/src/input/inputEvent.cpp b/src/input/inputEvent.cpp
new file mode 100644
index 0000000..04a84e7
--- /dev/null
+++ b/src/input/inputEvent.cpp
@@ -0,0 +1,98 @@
+/*
+ * inputEvent.cpp
+ *
+ * Created on: 06.09.2010
+ * Author: brs
+ */
+
+#include <QBuffer>
+#include <QByteArray>
+#include <QDataStream>
+#include <QKeyEvent>
+#include <QMouseEvent>
+#include <QString>
+#include "inputEvent.h"
+#include <src/util/consoleLogger.h>
+
+// We implement operators to serialize and load an event:
+QDataStream& operator <<(QDataStream& ostrm, InputEvent const& evt)
+{
+ ostrm << evt.type_ << evt.code_ << evt.value_;
+ return ostrm;
+}
+
+QDataStream& operator >>(QDataStream& istrm, InputEvent& evt)
+{
+ istrm >> evt.type_ >> evt.code_ >> evt.value_;
+ return istrm;
+}
+
+void eventToString(InputEvent const& evt, QString& str)
+{
+ QByteArray ba;
+ QBuffer buf(&ba);
+ buf.open(QIODevice::WriteOnly);
+ QDataStream out(&buf);
+ out << evt;
+ str = QString::fromAscii(ba.toBase64());
+}
+
+bool eventFromString(QString const& str, InputEvent& evt)
+{
+ // TODO This does not do proper error checking. Only use from trusted sources!
+ QByteArray ba = QByteArray::fromBase64(str.toAscii());
+ QBuffer buf(&ba);
+ buf.open(QIODevice::ReadOnly);
+ QDataStream in(&buf);
+ in >> evt;
+ return true;
+}
+
+quint16 InputEvent::mouseButtonsFromQt(int b)
+{
+ quint16 ret = 0;
+ if(b & Qt::LeftButton)
+ {
+ ret |= EB_LEFT;
+ }
+ if(b & Qt::RightButton)
+ {
+ ret |= EB_RIGHT;
+ }
+ if(b & Qt::MidButton)
+ {
+ ret |= EB_MIDDLE;
+ }
+ return ret;
+}
+
+InputEvent InputEvent::mousePressRelease(QMouseEvent const* evt)
+{
+ quint16 button = mouseButtonsFromQt(evt->button());
+ quint16 buttons = mouseButtonsFromQt(evt->buttons());
+ quint16 code;
+
+ if(buttons & button)
+ {
+ code = EC_PRESS;
+ }
+ else
+ {
+ code = EC_RELEASE;
+ }
+
+ quint32 value = ((quint32)button << 16) | buttons;
+ return InputEvent(ET_BUTTON, code, value);
+}
+
+InputEvent InputEvent::keyboardPress(QKeyEvent const* evt)
+{
+ quint32 value = evt->key() | evt->modifiers();
+ return InputEvent(ET_KEY, EC_PRESS, value);
+}
+
+InputEvent InputEvent::keyboardRelease(QKeyEvent const* evt)
+{
+ quint32 value = evt->key() | evt->modifiers();
+ return InputEvent(ET_KEY, EC_RELEASE, value);
+}
diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h
new file mode 100644
index 0000000..917cc64
--- /dev/null
+++ b/src/input/inputEvent.h
@@ -0,0 +1,218 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # inputEvent.h:
+ # - Definition of an input event
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef INPUTEVENT_H_
+#define INPUTEVENT_H_
+
+#include <cassert>
+#include <string>
+#include <sstream>
+#include <stdint.h>
+
+#ifndef __linux
+# error "This will only run on a Linux system. Porting is required for other systems."
+#endif
+
+struct QDataStream;
+struct QString;
+struct QMouseEvent;
+struct QKeyEvent;
+
+class InputEvent
+{
+private:
+ friend QDataStream& operator<<(QDataStream&, InputEvent const&);
+ friend QDataStream& operator>>(QDataStream&, InputEvent&);
+
+ friend void eventToString(InputEvent const& evt, QString& str);
+ friend bool eventFromString(QString const& str, InputEvent& evt);
+
+ uint16_t type_;
+ uint16_t code_;
+ uint32_t value_;
+
+ // InputEvents are immutable. Prohibit assignment:
+ InputEvent& operator=(InputEvent const&); // There intentionally is no implementation.
+public:
+ InputEvent(uint16_t type, uint16_t code, uint32_t value) : type_(type), code_(code), value_(value)
+ {
+ }
+
+ InputEvent()
+ {
+ }
+
+ static InputEvent mouseMotion(uint16_t x, uint16_t y)
+ {
+ return InputEvent(ET_POINTER, 0, ((uint32_t)x << 16) | y);
+ }
+
+ static uint16_t mouseButtonsFromQt(int b);
+
+ static InputEvent mousePressRelease(QMouseEvent const* event);
+ static InputEvent keyboardPress(QKeyEvent const* event);
+ static InputEvent keyboardRelease(QKeyEvent const* event);
+
+ static const uint16_t ET_KEY = 0;
+ static const uint16_t ET_BUTTON = 1;
+ static const uint16_t ET_POINTER = 2;
+ static const uint16_t ET_SPECIAL = 3;
+
+ static const uint16_t EC_PRESS = 0;
+ static const uint16_t EC_RELEASE = 1;
+ static const uint16_t EC_REBOOT = 2;
+ static const uint16_t EC_SYSRQ = 3;
+ static const uint16_t EC_KILL_X = 4;
+
+ typedef uint32_t event_key;
+
+ typedef uint32_t event_key_modifiers;
+
+ static const uint16_t EB_LEFT = 1;
+ static const uint16_t EB_MIDDLE = 2;
+ static const uint16_t EB_RIGHT = 4;
+
+ static const uint32_t MODIFIER_MASK =
+ 0x7e000000;
+
+ uint16_t type() const
+ {
+ return type_;
+ }
+
+ uint16_t code() const
+ {
+ return code_;
+ }
+
+ uint32_t value() const
+ {
+ return value_;
+ }
+
+ bool isKeyboard() const
+ {
+ return type_ == ET_KEY;
+ }
+
+ bool isButton() const
+ {
+ return type_ == ET_BUTTON;
+ }
+
+ bool isPointer() const
+ {
+ return type_ == ET_POINTER;
+ }
+
+ bool isSpecial() const
+ {
+ return type_ == ET_SPECIAL;
+ }
+
+ bool isPress() const
+ {
+ return code_ == EC_PRESS;
+ }
+
+ bool isRelease() const
+ {
+ return code_ == EC_RELEASE;
+ }
+
+ uint16_t pressedButton() const
+ {
+ assert(type_ == ET_BUTTON);
+ return (value_ >> 16);
+ }
+
+ uint16_t heldButtons() const
+ {
+ assert(type_ == ET_BUTTON);
+ return (value_ & 0xffff);
+ }
+
+ uint16_t xCoord() const
+ {
+ assert(type_ == ET_POINTER);
+ return (value_ >> 16);
+ }
+
+ uint16_t yCoord() const
+ {
+ assert(type_ == ET_POINTER);
+ return (value_ & 0xffff);
+ }
+
+ static std::string typeToString(uint16_t type)
+ {
+ switch(type)
+ {
+ case ET_BUTTON:
+ return "BUTTON";
+ case ET_KEY:
+ return "KEY";
+ case ET_POINTER:
+ return "POINTER";
+ case ET_SPECIAL:
+ return "SPECIAL";
+ default:
+ std::ostringstream s;
+ s << std::hex << type;
+ return s.str();
+ }
+ }
+
+ static std::string codeToString(uint16_t code)
+ {
+ switch(code)
+ {
+ case EC_PRESS:
+ return "PRESS";
+ case EC_RELEASE:
+ return "RELEASE";
+ case EC_SYSRQ:
+ return "SYSRQ";
+ case EC_REBOOT:
+ return "REBOOT";
+ case EC_KILL_X:
+ return "KILL_X";
+ default:
+ std::ostringstream s;
+ s << std::hex << code;
+ return s.str();
+ }
+ }
+
+ std::string toString() const
+ {
+ std::ostringstream s;
+ s << typeToString(type_) << ':' << codeToString(code_) << ':' << std::hex << value_;
+ return s.str();
+ }
+
+ uint32_t qt_keysym() const
+ {
+ return value_ & ~MODIFIER_MASK;
+ }
+
+ uint32_t qt_modifiers() const
+ {
+ return value_ & MODIFIER_MASK;
+ }
+};
+
+#endif /* INPUTEVENT_H_ */
diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h
new file mode 100644
index 0000000..3910f93
--- /dev/null
+++ b/src/input/inputEventHandler.h
@@ -0,0 +1,187 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # inputEventHandler.h:
+ # - Common definitions for input event handlers
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef INPUTEVENTHANDLER_H_
+#define INPUTEVENTHANDLER_H_
+
+#include <QtGlobal>
+#include <boost/mpl/contains.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/mpl/vector.hpp>
+#include <src/input/inputEvent.h>
+
+#define HANDLER_TYPE_DONT_CARE 0xffff
+#define HANDLER_CODE_DONT_CARE 0xffff
+#define HANDLER_VALUE_DONT_CARE 0xffffffff
+
+template<quint16 Type = HANDLER_TYPE_DONT_CARE,
+ quint16 Code = HANDLER_CODE_DONT_CARE,
+ quint32 Value = HANDLER_VALUE_DONT_CARE>
+class DefaultInputEventHandler {
+public:
+ static bool matches(InputEvent const& evt) {
+ if(Type != 0xffff) {
+ if(evt.type() != Type)
+ return false;
+ }
+ if(Code != 0xffff) {
+ if(evt.code() != Code)
+ return false;
+ }
+ if(Value != 0xffffffff) {
+ if(evt.value() != Value)
+ return false;
+ }
+ return true;
+ }
+
+ static void initialize()
+ {
+ }
+};
+
+namespace policy {
+
+struct NoSecurityCheck {
+ static bool allow(InputEvent const&) {
+ return true;
+ }
+};
+
+struct PhysicalSeatSecurityCheck {
+ static bool allow(InputEvent const&) {
+ return /* TODO implement */ true;
+ }
+};
+
+struct AlwaysDenySecurityCheck {
+ static bool allow(InputEvent const&) {
+ return false;
+ }
+};
+
+struct UnixLike;
+struct Linux;
+struct Windows;
+
+#if defined(__linux)
+typedef boost::mpl::vector2<UnixLike,Linux>::type Systems;
+#elif defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
+typedef boost::mpl::vector1<Windows>::type Systems;
+#else
+# error "Porting is needed!"
+#endif
+
+struct SystemEnabled;
+struct SystemDisabled;
+
+template<typename System>
+struct RequireSystem
+{
+ typedef typename boost::mpl::contains<Systems, System>::type enabled_type;
+ static const bool enabled = enabled_type::value;
+};
+
+struct RequireNoSystem
+{
+ typedef boost::mpl::bool_<true>::type enabled_type;
+ static const bool enabled = enabled_type::value;
+};
+
+}
+
+template<bool Enabled, typename Delegate, typename SecurityPolicy>
+class HandlerHelper
+{
+public:
+ static bool handle(InputEvent const& evt) {
+ if(!SecurityPolicy::allow(evt))
+ {
+ return true;
+ }
+ if(Delegate::matches(evt)) {
+ Delegate::handle(evt);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ static void initialize()
+ {
+ Delegate::initialize();
+ }
+};
+
+template<typename Delegate, typename SecurityPolicy>
+class HandlerHelper<false, Delegate, SecurityPolicy>
+{
+public:
+ static bool handle(InputEvent const& evt) {
+ return false;
+ }
+
+ static void initialize()
+ {
+ }
+};
+
+template<typename Delegate, typename SecurityPolicy = policy::NoSecurityCheck, typename SystemPolicy = policy::RequireNoSystem>
+struct Handler : public HandlerHelper<SystemPolicy::enabled, Delegate, SecurityPolicy>
+{
+};
+
+template<typename Begin, typename End>
+struct InputEventHandlerChainHelper
+{
+private:
+ typedef typename boost::mpl::next<Begin>::type next_iterator_type;
+ typedef InputEventHandlerChainHelper<next_iterator_type, End> next_in_chain;
+
+ typedef typename boost::mpl::deref<Begin>::type handler_type;
+
+public:
+ static void handle(InputEvent const& evt) {
+ if(!handler_type::handle(evt)) {
+ next_in_chain::handle(evt);
+ }
+ }
+
+ static void initialize() {
+ handler_type::initialize();
+ next_in_chain::initialize();
+ }
+};
+
+template<typename End>
+struct InputEventHandlerChainHelper<End, End>
+{
+public:
+ static void handle(InputEvent const&) {
+ // do nothing
+ }
+
+ static void initialize() {
+ // do nothing
+ }
+};
+
+template<typename Collection>
+struct InputEventHandlerChain : public InputEventHandlerChainHelper<typename boost::mpl::begin<Collection>::type, typename boost::mpl::end<Collection>::type>
+{
+};
+
+#endif /* INPUTEVENTHANDLER_H_ */
diff --git a/src/input/inputEventNonQt.cpp b/src/input/inputEventNonQt.cpp
new file mode 100644
index 0000000..a7455fd
--- /dev/null
+++ b/src/input/inputEventNonQt.cpp
@@ -0,0 +1,17 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # inputEvent.h:
+ # - Input Event routines that need not be linked against Qt
+ # --------------------------------------------------------------------------
+ */
+
+
diff --git a/src/input/unprivilegedHandlerChain.h b/src/input/unprivilegedHandlerChain.h
new file mode 100644
index 0000000..734720a
--- /dev/null
+++ b/src/input/unprivilegedHandlerChain.h
@@ -0,0 +1,34 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # inputHandlerChain.h:
+ # - Definition of the input handler chain
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef INPUTHANDLERCHAIN_H_
+#define INPUTHANDLERCHAIN_H_
+
+#include <boost/mpl/list.hpp>
+#include "inputEventHandler.h"
+
+#include "x11FakeKeyboardHandler.h"
+#include "x11FakeMouseHandler.h"
+
+typedef boost::mpl::list<
+ Handler<X11FakeKeyboardHandler, policy::NoSecurityCheck, policy::RequireSystem<policy::UnixLike> >,
+ Handler<X11FakeMouseButtonHandler, policy::NoSecurityCheck, policy::RequireSystem<policy::UnixLike> >,
+ Handler<X11FakeMouseMovementHandler, policy::NoSecurityCheck, policy::RequireSystem<policy::UnixLike> >
+>::type unprivileged_handler_list;
+
+typedef InputEventHandlerChain<unprivileged_handler_list> unprivileged_handler_chain;
+
+#endif /* INPUTHANDLERCHAIN_H_ */
diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp
new file mode 100644
index 0000000..bb14b76
--- /dev/null
+++ b/src/input/x11FakeKeyboardHandler.cpp
@@ -0,0 +1,800 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # x11FakeKeyboardHandler.h:
+ # - Handle keyboard events on X11 - interface
+ # --------------------------------------------------------------------------
+ */
+
+#include <map>
+#include <set>
+#include <cassert>
+// Qt headers need to be included before X11 headers
+#include <QApplication>
+#include <QtCore>
+// #include <multimap>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/keysymdef.h>
+#include <X11/extensions/XTest.h>
+#include <X11/XKBlib.h>
+#include <src/util/consoleLogger.h>
+#include "x11InputUtils.h"
+#include "x11FakeKeyboardHandler.h"
+
+//////////////////////// INPUT EVENT TRANSLATION /////////////////////////////////
+
+typedef unsigned char xmodifier_type;
+
+char modifiernames[][8] = {
+ "SHIFT",
+ "LOCK",
+ "CONTROL",
+ "MOD1",
+ "MOD2",
+ "MOD3",
+ "MOD4",
+ "MOD5"
+};
+
+QString modifiers_to_string(xmodifier_type mods)
+{
+ QString s;
+ for(int i = 0; i < 8; i++)
+ {
+ if(mods & (1<<i))
+ {
+ s += modifiernames[i];
+ s += ", ";
+ }
+ }
+ s.chop(2);
+ return s;
+}
+
+
+typedef std::map<quint32, KeySym> lookup_table_type;
+typedef lookup_table_type::const_iterator lookup_table_const_iterator;
+typedef lookup_table_type::iterator lookup_table_iterator;
+lookup_table_type keysyms;
+void initialize_keysyms() {
+ keysyms[Qt::Key_Escape] = XK_Escape;
+ keysyms[Qt::Key_Tab] = XK_Tab;
+// keysyms[Qt::Key_Backtab] = XK_Backtab;
+ keysyms[Qt::Key_Backspace] = XK_BackSpace;
+ keysyms[Qt::Key_Return] = XK_Return;
+ keysyms[Qt::Key_Enter] = XK_KP_Enter;
+ keysyms[Qt::Key_Insert] = XK_Insert;
+ keysyms[Qt::Key_Delete] = XK_Delete;
+ keysyms[Qt::Key_Pause] = XK_Pause;
+ keysyms[Qt::Key_Print] = XK_Print;
+ keysyms[Qt::Key_SysReq] = XK_Sys_Req;
+ keysyms[Qt::Key_Clear] = XK_Clear;
+ keysyms[Qt::Key_Home] = XK_Home;
+ keysyms[Qt::Key_End] = XK_End;
+ keysyms[Qt::Key_Left] = XK_Left;
+ keysyms[Qt::Key_Up] = XK_Up;
+ keysyms[Qt::Key_Right] = XK_Right;
+ keysyms[Qt::Key_Down] = XK_Down;
+ keysyms[Qt::Key_PageUp] = XK_Page_Up;
+ keysyms[Qt::Key_PageDown] = XK_Page_Down;
+ keysyms[Qt::Key_Shift] = XK_Shift_L;
+ keysyms[Qt::Key_Control] = XK_Control_L;
+ keysyms[Qt::Key_Meta] = XK_Meta_L;
+ keysyms[Qt::Key_Alt] = XK_Alt_L;
+ keysyms[Qt::Key_CapsLock] = XK_Caps_Lock;
+ keysyms[Qt::Key_NumLock] = XK_Num_Lock;
+ keysyms[Qt::Key_ScrollLock] = XK_Scroll_Lock;
+ keysyms[Qt::Key_F1] = XK_F1;
+ keysyms[Qt::Key_F2] = XK_F2;
+ keysyms[Qt::Key_F3] = XK_F3;
+ keysyms[Qt::Key_F4] = XK_F4;
+ keysyms[Qt::Key_F5] = XK_F5;
+ keysyms[Qt::Key_F6] = XK_F6;
+ keysyms[Qt::Key_F7] = XK_F7;
+ keysyms[Qt::Key_F8] = XK_F8;
+ keysyms[Qt::Key_F9] = XK_F9;
+ keysyms[Qt::Key_F10] = XK_F10;
+ keysyms[Qt::Key_F11] = XK_F11;
+ keysyms[Qt::Key_F12] = XK_F12;
+ keysyms[Qt::Key_F13] = XK_F13;
+ keysyms[Qt::Key_F14] = XK_F14;
+ keysyms[Qt::Key_F15] = XK_F15;
+ keysyms[Qt::Key_F16] = XK_F16;
+ keysyms[Qt::Key_F17] = XK_F17;
+ keysyms[Qt::Key_F18] = XK_F18;
+ keysyms[Qt::Key_F19] = XK_F19;
+ keysyms[Qt::Key_F20] = XK_F20;
+ keysyms[Qt::Key_F21] = XK_F21;
+ keysyms[Qt::Key_F22] = XK_F22;
+ keysyms[Qt::Key_F23] = XK_F23;
+ keysyms[Qt::Key_F24] = XK_F24;
+ keysyms[Qt::Key_F25] = XK_F25;
+ keysyms[Qt::Key_F26] = XK_F26;
+ keysyms[Qt::Key_F27] = XK_F27;
+ keysyms[Qt::Key_F28] = XK_F28;
+ keysyms[Qt::Key_F29] = XK_F29;
+ keysyms[Qt::Key_F30] = XK_F30;
+ keysyms[Qt::Key_F31] = XK_F31;
+ keysyms[Qt::Key_F32] = XK_F32;
+ keysyms[Qt::Key_F33] = XK_F33;
+ keysyms[Qt::Key_F34] = XK_F34;
+ keysyms[Qt::Key_F35] = XK_F35;
+ keysyms[Qt::Key_Super_L] = XK_Super_L;
+ keysyms[Qt::Key_Super_R] = XK_Super_R;
+ keysyms[Qt::Key_Menu] = XK_Menu;
+ keysyms[Qt::Key_Hyper_L] = XK_Hyper_L;
+ keysyms[Qt::Key_Hyper_R] = XK_Hyper_R;
+ keysyms[Qt::Key_Help] = XK_Help;
+// keysyms[Qt::Key_Direction_L] = XK_Direction_L;
+// keysyms[Qt::Key_Direction_R] = XK_Direction_R;
+ keysyms[Qt::Key_Space] = XK_space;
+ keysyms[Qt::Key_Exclam] = XK_exclam;
+ keysyms[Qt::Key_QuoteDbl] = XK_quotedbl;
+ keysyms[Qt::Key_NumberSign] = XK_numbersign;
+ keysyms[Qt::Key_Dollar] = XK_dollar;
+ keysyms[Qt::Key_Percent] = XK_percent;
+ keysyms[Qt::Key_Ampersand] = XK_ampersand;
+ keysyms[Qt::Key_Apostrophe] = XK_apostrophe;
+ keysyms[Qt::Key_ParenLeft] = XK_parenleft;
+ keysyms[Qt::Key_ParenRight] = XK_parenright;
+ keysyms[Qt::Key_Asterisk] = XK_asterisk;
+ keysyms[Qt::Key_Plus] = XK_plus;
+ keysyms[Qt::Key_Comma] = XK_comma;
+ keysyms[Qt::Key_Minus] = XK_minus;
+ keysyms[Qt::Key_Period] = XK_period;
+ keysyms[Qt::Key_Slash] = XK_slash;
+ keysyms[Qt::Key_0] = XK_0;
+ keysyms[Qt::Key_1] = XK_1;
+ keysyms[Qt::Key_2] = XK_2;
+ keysyms[Qt::Key_3] = XK_3;
+ keysyms[Qt::Key_4] = XK_4;
+ keysyms[Qt::Key_5] = XK_5;
+ keysyms[Qt::Key_6] = XK_6;
+ keysyms[Qt::Key_7] = XK_7;
+ keysyms[Qt::Key_8] = XK_8;
+ keysyms[Qt::Key_9] = XK_9;
+ keysyms[Qt::Key_Colon] = XK_colon;
+ keysyms[Qt::Key_Semicolon] = XK_semicolon;
+ keysyms[Qt::Key_Less] = XK_less;
+ keysyms[Qt::Key_Equal] = XK_equal;
+ keysyms[Qt::Key_Greater] = XK_greater;
+ keysyms[Qt::Key_Question] = XK_question;
+ keysyms[Qt::Key_At] = XK_at;
+ keysyms[Qt::Key_A] = XK_A;
+ keysyms[Qt::Key_B] = XK_B;
+ keysyms[Qt::Key_C] = XK_C;
+ keysyms[Qt::Key_D] = XK_D;
+ keysyms[Qt::Key_E] = XK_E;
+ keysyms[Qt::Key_F] = XK_F;
+ keysyms[Qt::Key_G] = XK_G;
+ keysyms[Qt::Key_H] = XK_H;
+ keysyms[Qt::Key_I] = XK_I;
+ keysyms[Qt::Key_J] = XK_J;
+ keysyms[Qt::Key_K] = XK_K;
+ keysyms[Qt::Key_L] = XK_L;
+ keysyms[Qt::Key_M] = XK_M;
+ keysyms[Qt::Key_N] = XK_N;
+ keysyms[Qt::Key_O] = XK_O;
+ keysyms[Qt::Key_P] = XK_P;
+ keysyms[Qt::Key_Q] = XK_Q;
+ keysyms[Qt::Key_R] = XK_R;
+ keysyms[Qt::Key_S] = XK_S;
+ keysyms[Qt::Key_T] = XK_T;
+ keysyms[Qt::Key_U] = XK_U;
+ keysyms[Qt::Key_V] = XK_V;
+ keysyms[Qt::Key_W] = XK_W;
+ keysyms[Qt::Key_X] = XK_X;
+ keysyms[Qt::Key_Y] = XK_Y;
+ keysyms[Qt::Key_Z] = XK_Z;
+ keysyms[Qt::Key_BracketLeft] = XK_bracketleft;
+ keysyms[Qt::Key_Backslash] = XK_backslash;
+ keysyms[Qt::Key_BracketRight] = XK_bracketright;
+ keysyms[Qt::Key_AsciiCircum] = XK_asciicircum;
+ keysyms[Qt::Key_Underscore] = XK_underscore;
+ keysyms[Qt::Key_QuoteLeft] = XK_quoteleft;
+ keysyms[Qt::Key_BraceLeft] = XK_braceleft;
+ keysyms[Qt::Key_Bar] = XK_bar;
+ keysyms[Qt::Key_BraceRight] = XK_braceright;
+ keysyms[Qt::Key_AsciiTilde] = XK_asciitilde;
+ keysyms[Qt::Key_nobreakspace] = XK_nobreakspace;
+ keysyms[Qt::Key_exclamdown] = XK_exclamdown;
+ keysyms[Qt::Key_cent] = XK_cent;
+ keysyms[Qt::Key_sterling] = XK_sterling;
+ keysyms[Qt::Key_currency] = XK_currency;
+ keysyms[Qt::Key_yen] = XK_yen;
+ keysyms[Qt::Key_brokenbar] = XK_brokenbar;
+ keysyms[Qt::Key_section] = XK_section;
+ keysyms[Qt::Key_diaeresis] = XK_diaeresis;
+ keysyms[Qt::Key_copyright] = XK_copyright;
+ keysyms[Qt::Key_ordfeminine] = XK_ordfeminine;
+ keysyms[Qt::Key_guillemotleft] = XK_guillemotleft;
+ keysyms[Qt::Key_notsign] = XK_notsign;
+ keysyms[Qt::Key_hyphen] = XK_hyphen;
+ keysyms[Qt::Key_registered] = XK_registered;
+ keysyms[Qt::Key_macron] = XK_macron;
+ keysyms[Qt::Key_degree] = XK_degree;
+ keysyms[Qt::Key_plusminus] = XK_plusminus;
+ keysyms[Qt::Key_twosuperior] = XK_twosuperior;
+ keysyms[Qt::Key_threesuperior] = XK_threesuperior;
+ keysyms[Qt::Key_acute] = XK_acute;
+ keysyms[Qt::Key_mu] = XK_mu;
+ keysyms[Qt::Key_paragraph] = XK_paragraph;
+ keysyms[Qt::Key_periodcentered] = XK_periodcentered;
+ keysyms[Qt::Key_cedilla] = XK_cedilla;
+ keysyms[Qt::Key_onesuperior] = XK_onesuperior;
+ keysyms[Qt::Key_masculine] = XK_masculine;
+ keysyms[Qt::Key_guillemotright] = XK_guillemotright;
+ keysyms[Qt::Key_onequarter] = XK_onequarter;
+ keysyms[Qt::Key_onehalf] = XK_onehalf;
+ keysyms[Qt::Key_threequarters] = XK_threequarters;
+ keysyms[Qt::Key_questiondown] = XK_questiondown;
+ keysyms[Qt::Key_Agrave] = XK_Agrave;
+ keysyms[Qt::Key_Aacute] = XK_Aacute;
+ keysyms[Qt::Key_Acircumflex] = XK_Acircumflex;
+ keysyms[Qt::Key_Atilde] = XK_Atilde;
+ keysyms[Qt::Key_Adiaeresis] = XK_Adiaeresis;
+ keysyms[Qt::Key_Aring] = XK_Aring;
+ keysyms[Qt::Key_AE] = XK_AE;
+ keysyms[Qt::Key_Ccedilla] = XK_Ccedilla;
+ keysyms[Qt::Key_Egrave] = XK_Egrave;
+ keysyms[Qt::Key_Eacute] = XK_Eacute;
+ keysyms[Qt::Key_Ecircumflex] = XK_Ecircumflex;
+ keysyms[Qt::Key_Ediaeresis] = XK_Ediaeresis;
+ keysyms[Qt::Key_Igrave] = XK_Igrave;
+ keysyms[Qt::Key_Iacute] = XK_Iacute;
+ keysyms[Qt::Key_Icircumflex] = XK_Icircumflex;
+ keysyms[Qt::Key_Idiaeresis] = XK_Idiaeresis;
+ keysyms[Qt::Key_ETH] = XK_ETH;
+ keysyms[Qt::Key_Ntilde] = XK_Ntilde;
+ keysyms[Qt::Key_Ograve] = XK_Ograve;
+ keysyms[Qt::Key_Oacute] = XK_Oacute;
+ keysyms[Qt::Key_Ocircumflex] = XK_Ocircumflex;
+ keysyms[Qt::Key_Otilde] = XK_Otilde;
+ keysyms[Qt::Key_Odiaeresis] = XK_Odiaeresis;
+ keysyms[Qt::Key_multiply] = XK_multiply;
+ keysyms[Qt::Key_Ooblique] = XK_Ooblique;
+ keysyms[Qt::Key_Ugrave] = XK_Ugrave;
+ keysyms[Qt::Key_Uacute] = XK_Uacute;
+ keysyms[Qt::Key_Ucircumflex] = XK_Ucircumflex;
+ keysyms[Qt::Key_Udiaeresis] = XK_Udiaeresis;
+ keysyms[Qt::Key_Yacute] = XK_Yacute;
+ keysyms[Qt::Key_THORN] = XK_THORN;
+ keysyms[Qt::Key_ssharp] = XK_ssharp;
+ keysyms[Qt::Key_Agrave] = XK_Agrave;
+ keysyms[Qt::Key_Aacute] = XK_Aacute;
+ keysyms[Qt::Key_Acircumflex] = XK_Acircumflex;
+ keysyms[Qt::Key_Atilde] = XK_Atilde;
+ keysyms[Qt::Key_Adiaeresis] = XK_Adiaeresis;
+ keysyms[Qt::Key_Aring] = XK_Aring;
+ keysyms[Qt::Key_AE] = XK_AE;
+ keysyms[Qt::Key_Ccedilla] = XK_Ccedilla;
+ keysyms[Qt::Key_Egrave] = XK_Egrave;
+ keysyms[Qt::Key_Eacute] = XK_Eacute;
+ keysyms[Qt::Key_Ecircumflex] = XK_Ecircumflex;
+ keysyms[Qt::Key_Ediaeresis] = XK_Ediaeresis;
+ keysyms[Qt::Key_Igrave] = XK_Igrave;
+ keysyms[Qt::Key_Iacute] = XK_Iacute;
+ keysyms[Qt::Key_Icircumflex] = XK_Icircumflex;
+ keysyms[Qt::Key_Idiaeresis] = XK_Idiaeresis;
+ keysyms[Qt::Key_ETH] = XK_ETH;
+ keysyms[Qt::Key_Ntilde] = XK_Ntilde;
+ keysyms[Qt::Key_Ograve] = XK_Ograve;
+ keysyms[Qt::Key_Oacute] = XK_Oacute;
+ keysyms[Qt::Key_Ocircumflex] = XK_Ocircumflex;
+ keysyms[Qt::Key_Otilde] = XK_Otilde;
+ keysyms[Qt::Key_Odiaeresis] = XK_Odiaeresis;
+ keysyms[Qt::Key_division] = XK_division;
+ keysyms[Qt::Key_Ooblique] = XK_Ooblique;
+ keysyms[Qt::Key_Ugrave] = XK_Ugrave;
+ keysyms[Qt::Key_Uacute] = XK_Uacute;
+ keysyms[Qt::Key_Ucircumflex] = XK_Ucircumflex;
+ keysyms[Qt::Key_Udiaeresis] = XK_Udiaeresis;
+ keysyms[Qt::Key_Yacute] = XK_Yacute;
+ keysyms[Qt::Key_THORN] = XK_THORN;
+ keysyms[Qt::Key_ydiaeresis] = XK_ydiaeresis;
+ keysyms[Qt::Key_AltGr] = XK_ISO_Level3_Shift;
+ keysyms[Qt::Key_Multi_key] = XK_Multi_key;
+ keysyms[Qt::Key_Codeinput] = XK_Codeinput;
+ keysyms[Qt::Key_SingleCandidate] = XK_SingleCandidate;
+ keysyms[Qt::Key_MultipleCandidate] = XK_MultipleCandidate;
+ keysyms[Qt::Key_PreviousCandidate] = XK_PreviousCandidate;
+ keysyms[Qt::Key_Mode_switch] = XK_Mode_switch;
+// keysyms[Qt::Key_script_switch] = XK_script_switch;
+ keysyms[Qt::Key_Kanji] = XK_Kanji;
+ keysyms[Qt::Key_Muhenkan] = XK_Muhenkan;
+// keysyms[Qt::Key_Henkan_Mode] = XK_Henkan_Mode;
+ keysyms[Qt::Key_Henkan] = XK_Henkan;
+ keysyms[Qt::Key_Romaji] = XK_Romaji;
+ keysyms[Qt::Key_Hiragana] = XK_Hiragana;
+ keysyms[Qt::Key_Katakana] = XK_Katakana;
+ keysyms[Qt::Key_Hiragana_Katakana] = XK_Hiragana_Katakana;
+ keysyms[Qt::Key_Zenkaku] = XK_Zenkaku;
+ keysyms[Qt::Key_Hankaku] = XK_Hankaku;
+ keysyms[Qt::Key_Zenkaku_Hankaku] = XK_Zenkaku_Hankaku;
+ keysyms[Qt::Key_Touroku] = XK_Touroku;
+ keysyms[Qt::Key_Massyo] = XK_Massyo;
+ keysyms[Qt::Key_Kana_Lock] = XK_Kana_Lock;
+ keysyms[Qt::Key_Kana_Shift] = XK_Kana_Shift;
+ keysyms[Qt::Key_Eisu_Shift] = XK_Eisu_Shift;
+ keysyms[Qt::Key_Eisu_toggle] = XK_Eisu_toggle;
+// keysyms[Qt::Key_Kanji_Bangou] = XK_Kanji_Bangou;
+// keysyms[Qt::Key_Zen_Koho] = XK_Zen_Koho;
+// keysyms[Qt::Key_Mae_Koho] = XK_Mae_Koho;
+ keysyms[Qt::Key_Hangul] = XK_Hangul;
+ keysyms[Qt::Key_Hangul_Hanja] = XK_Hangul_Hanja;
+ keysyms[Qt::Key_Hangul] = XK_Hangul;
+ keysyms[Qt::Key_Hangul_Start] = XK_Hangul_Start;
+ keysyms[Qt::Key_Hangul_End] = XK_Hangul_End;
+ keysyms[Qt::Key_Hangul_Hanja] = XK_Hangul_Hanja;
+ keysyms[Qt::Key_Hangul_Jamo] = XK_Hangul_Jamo;
+ keysyms[Qt::Key_Hangul_Romaja] = XK_Hangul_Romaja;
+// keysyms[Qt::Key_Hangul_Codeinput] = XK_Hangul_Codeinput;
+ keysyms[Qt::Key_Hangul_Jeonja] = XK_Hangul_Jeonja;
+ keysyms[Qt::Key_Hangul_Banja] = XK_Hangul_Banja;
+ keysyms[Qt::Key_Hangul_PreHanja] = XK_Hangul_PreHanja;
+ keysyms[Qt::Key_Hangul_PostHanja] = XK_Hangul_PostHanja;
+// keysyms[Qt::Key_Hangul_SingleCandidate] = XK_Hangul_SingleCandidate;
+// keysyms[Qt::Key_Hangul_MultipleCandidate] = XK_Hangul_MultipleCandidate;
+// keysyms[Qt::Key_Hangul_PreviousCandidate] = XK_Hangul_PreviousCandidate;
+ keysyms[Qt::Key_Hangul_Special] = XK_Hangul_Special;
+// keysyms[Qt::Key_Hangul_switch] = XK_Hangul_switch;
+ keysyms[Qt::Key_Dead_Grave] = XK_dead_grave;
+ keysyms[Qt::Key_Dead_Acute] = XK_dead_acute;
+ keysyms[Qt::Key_Dead_Circumflex] = XK_dead_circumflex;
+ keysyms[Qt::Key_Dead_Tilde] = XK_dead_tilde;
+ keysyms[Qt::Key_Dead_Macron] = XK_dead_macron;
+ keysyms[Qt::Key_Dead_Breve] = XK_dead_breve;
+ keysyms[Qt::Key_Dead_Abovedot] = XK_dead_abovedot;
+ keysyms[Qt::Key_Dead_Diaeresis] = XK_dead_diaeresis;
+ keysyms[Qt::Key_Dead_Abovering] = XK_dead_abovering;
+ keysyms[Qt::Key_Dead_Doubleacute] = XK_dead_doubleacute;
+ keysyms[Qt::Key_Dead_Caron] = XK_dead_caron;
+ keysyms[Qt::Key_Dead_Cedilla] = XK_dead_cedilla;
+ keysyms[Qt::Key_Dead_Ogonek] = XK_dead_ogonek;
+ keysyms[Qt::Key_Dead_Iota] = XK_dead_iota;
+ keysyms[Qt::Key_Dead_Voiced_Sound] = XK_dead_voiced_sound;
+ keysyms[Qt::Key_Dead_Semivoiced_Sound] = XK_dead_semivoiced_sound;
+ keysyms[Qt::Key_Dead_Belowdot] = XK_dead_belowdot;
+ keysyms[Qt::Key_Dead_Hook] = XK_dead_hook;
+ keysyms[Qt::Key_Dead_Horn] = XK_dead_horn;
+// keysyms[Qt::Key_Back] = XK_Back;
+// keysyms[Qt::Key_Forward] = XK_Forward;
+// keysyms[Qt::Key_Stop] = XK_Stop;
+// keysyms[Qt::Key_Refresh] = XK_Refresh;
+// keysyms[Qt::Key_VolumeDown] = XK_VolumeDown;
+// keysyms[Qt::Key_VolumeMute] = XK_VolumeMute;
+// keysyms[Qt::Key_VolumeUp] = XK_VolumeUp;
+// keysyms[Qt::Key_BassBoost] = XK_BassBoost;
+// keysyms[Qt::Key_BassUp] = XK_BassUp;
+// keysyms[Qt::Key_BassDown] = XK_BassDown;
+// keysyms[Qt::Key_TrebleUp] = XK_TrebleUp;
+// keysyms[Qt::Key_TrebleDown] = XK_TrebleDown;
+// keysyms[Qt::Key_MediaPlay] = XK_MediaPlay;
+// keysyms[Qt::Key_MediaStop] = XK_MediaStop;
+// keysyms[Qt::Key_MediaPrevious] = XK_MediaPrevious;
+// keysyms[Qt::Key_MediaNext] = XK_MediaNext;
+// keysyms[Qt::Key_MediaRecord] = XK_MediaRecord;
+// keysyms[Qt::Key_HomePage] = XK_HomePage;
+// keysyms[Qt::Key_Favorites] = XK_Favorites;
+// keysyms[Qt::Key_Search] = XK_Search;
+// keysyms[Qt::Key_Standby] = XK_Standby;
+// keysyms[Qt::Key_OpenUrl] = XK_OpenUrl;
+// keysyms[Qt::Key_LaunchMail] = XK_LaunchMail;
+// keysyms[Qt::Key_LaunchMedia] = XK_LaunchMedia;
+// keysyms[Qt::Key_Launch0] = XK_Launch0;
+// keysyms[Qt::Key_Launch1] = XK_Launch1;
+// keysyms[Qt::Key_Launch2] = XK_Launch2;
+// keysyms[Qt::Key_Launch3] = XK_Launch3;
+// keysyms[Qt::Key_Launch4] = XK_Launch4;
+// keysyms[Qt::Key_Launch5] = XK_Launch5;
+// keysyms[Qt::Key_Launch6] = XK_Launch6;
+// keysyms[Qt::Key_Launch7] = XK_Launch7;
+// keysyms[Qt::Key_Launch8] = XK_Launch8;
+// keysyms[Qt::Key_Launch9] = XK_Launch9;
+// keysyms[Qt::Key_LaunchA] = XK_LaunchA;
+// keysyms[Qt::Key_LaunchB] = XK_LaunchB;
+// keysyms[Qt::Key_LaunchC] = XK_LaunchC;
+// keysyms[Qt::Key_LaunchD] = XK_LaunchD;
+// keysyms[Qt::Key_LaunchE] = XK_LaunchE;
+// keysyms[Qt::Key_LaunchF] = XK_LaunchF;
+// keysyms[Qt::Key_Display] = XK_Display;
+// keysyms[Qt::Key_MediaLast] = XK_MediaLast;
+ keysyms[Qt::Key_Select] = XK_Select;
+// keysyms[Qt::Key_Yes] = XK_Yes;
+// keysyms[Qt::Key_No] = XK_No;
+ keysyms[Qt::Key_Cancel] = XK_Cancel;
+// keysyms[Qt::Key_Printer] = XK_Printer;
+ keysyms[Qt::Key_Execute] = XK_Execute;
+// keysyms[Qt::Key_Sleep] = XK_Sleep;
+// keysyms[Qt::Key_MediaPlay] = XK_MediaPlay;
+// keysyms[Qt::Key_Zoom] = XK_Zoom;
+// keysyms[Qt::Key_Jisho] = XK_Jisho;
+// keysyms[Qt::Key_Oyayubi_Left] = XK_Oyayubi_Left;
+// keysyms[Qt::Key_Oyayubi_Right] = XK_Oyayubi_Right;
+// keysyms[Qt::Key_Context1] = XK_Context1;
+// keysyms[Qt::Key_Context2] = XK_Context2;
+// keysyms[Qt::Key_Context3] = XK_Context3;
+// keysyms[Qt::Key_Context4] = XK_Context4;
+// keysyms[Qt::Key_Call] = XK_Call;
+// keysyms[Qt::Key_Hangup] = XK_Hangup;
+// keysyms[Qt::Key_Flip] = XK_Flip;
+ keysyms[Qt::Key_unknown] = XK_VoidSymbol;
+}
+
+/* Store Keycodes for "normal" Latin1 keys: */
+int basic_keycodes[0x100];
+int basic_modifiers[0x100];
+
+int modifier_keycodes[8];
+Qt::KeyboardModifier modifier_meaning[8];
+
+int xmodifier_from_qtmodifier(Qt::KeyboardModifier m) {
+ for(int i = 0; i < 8; i++) {
+ if(m == modifier_meaning[i])
+ return i;
+ }
+ return -1;
+}
+
+typedef std::map<Qt::KeyboardModifier, xmodifier_type> qt_to_xmodifier_type;
+typedef std::map<xmodifier_type, Qt::KeyboardModifier> x_to_qtmodifier_type;
+qt_to_xmodifier_type qt_to_xmodifier;
+x_to_qtmodifier_type x_to_qtmodifier;
+
+typedef std::multimap<xmodifier_type, int> modifier_to_keycode_map;
+modifier_to_keycode_map modifier_to_keycode;
+typedef std::map<int, xmodifier_type> keycode_to_modifier_map;
+keycode_to_modifier_map keycode_to_modifier;
+
+void initialize_basic_keycodes()
+{
+ for(int i = 0; i < 8; i++) {
+ modifier_keycodes[i] = -1;
+ }
+ for(int i = 0; i < 0x100; i++) {
+ basic_keycodes[i] = -1;
+ }
+
+ Display* dpy = X11InputUtils::display();
+ int min_keycode, max_keycode;
+ XDisplayKeycodes(dpy, &min_keycode, &max_keycode);
+
+ int xkb_opcode, xkb_event, xkb_error, xkb_major, xkb_minor;
+ bool xkb_present = XkbQueryExtension(dpy, &xkb_opcode, &xkb_event, &xkb_error, &xkb_major, &xkb_minor);
+ if(xkb_present) {
+ int keysyms_per_code;
+ const int count = max_keycode - min_keycode + 1;
+ KeySym* mapping = XGetKeyboardMapping(dpy, min_keycode, count, &keysyms_per_code);
+ for(int i = 0; i < count; i++)
+ {
+ for(int j = 0; j < keysyms_per_code; j++)
+ {
+ const int idx = i * keysyms_per_code + j;
+ const KeySym ks = mapping[idx];
+ const int keycode = min_keycode + i;
+
+ if(ks >= ' ' && ks < 0x100)
+ {
+ if(ks == XK_at) {
+ ConsoleLog writeLine(QString("Keycode %1 (%2) gives `@' with modifiers `%3', but it is really `%4'").arg(keycode).arg(XKeysymToString(XKeycodeToKeysym(dpy, keycode, 0))).arg(modifiers_to_string(j)).arg(XKeysymToString(XKeycodeToKeysym(dpy, keycode, j))));
+
+ }
+
+ if(basic_keycodes[ks] != -1)
+ continue; // already found
+
+ basic_keycodes[ks] = keycode;
+ basic_modifiers[ks] = j;
+ }
+ }
+ }
+ XFree(mapping);
+ }
+ else
+ {
+ for(int i = min_keycode; i <= max_keycode; i++)
+ {
+ for(int j = 0; j <= 0xff; j++)
+ {
+ KeySym ks = 0;
+ unsigned int unconsumed;
+ if(!XkbLookupKeySym(dpy, i, j, &unconsumed, &ks) || ks == NoSymbol)
+ continue;
+
+ if(ks && (ks < 0x100))
+ {
+// ConsoleLog writeLine(QString("Keycode %1 (%2) seems to give `%3' with modifiers `%4', of which `%5' are unconsumed")
+// .arg(i)
+// .arg(XKeysymToString(XKeycodeToKeysym(dpy, i, 0)))
+// .arg(XKeysymToString(ks))
+// .arg(modifiers_to_string(j))
+// .arg(modifiers_to_string(unconsumed)));
+ if(basic_keycodes[ks] != -1)
+ continue;
+
+ basic_keycodes[ks] = i;
+ basic_modifiers[ks] = unconsumed & j;
+ }
+ }
+ }
+ }
+
+ // find out which keycodes cause the modifier state bits:
+ XModifierKeymap* modkm;
+ modkm = XGetModifierMapping(dpy);
+
+ const int shift_kc = XKeysymToKeycode(dpy, XK_Shift_L);
+ const int control_kc = XKeysymToKeycode(dpy, XK_Control_L);
+ const int alt_kc = XKeysymToKeycode(dpy, XK_Alt_L);
+ const int meta_kc = XKeysymToKeycode(dpy, XK_Meta_L);
+ const int switch_kc = XKeysymToKeycode(dpy, XK_Mode_switch);
+
+ for(int i = 0; i < 8; i++) {
+ for(int j = 0; j < modkm->max_keypermod; j++) {
+ const int idx = i * modkm->max_keypermod + j;
+ const int kc = modkm->modifiermap[idx];
+
+ modifier_to_keycode.insert(std::make_pair((1<<i), kc));
+ keycode_to_modifier[kc] = (1<<i);
+#define remember_modifier(qmod) do { \
+ qt_to_xmodifier[Qt::qmod##Modifier] = 1<<i; \
+ x_to_qtmodifier[1<<i] = Qt::qmod##Modifier; \
+} while(false)
+ if(kc == shift_kc) {
+ remember_modifier(Shift);
+ } else if(kc == control_kc) {
+ remember_modifier(Control);
+ } else if(kc == alt_kc) {
+ remember_modifier(Alt);
+ } else if(kc == meta_kc) {
+ remember_modifier(Meta);
+ } else if(kc == switch_kc) {
+ remember_modifier(GroupSwitch);
+ }
+#undef remember_modifier
+
+ if(modifier_keycodes[i] != -1) {
+ continue; // already found
+ }
+
+ // select one arbitrarily
+ modifier_keycodes[i] = kc;
+ }
+ }
+
+ XFreeModifiermap(modkm);
+}
+
+xmodifier_type translate_modifiers(quint32 mods)
+{
+ xmodifier_type ret = 0;
+
+ for(int j = 1; j < 8; j++) {
+ xmodifier_type i = 1<<j;
+
+ if(mods & x_to_qtmodifier[i])
+ {
+ ret |= i;
+ }
+ }
+
+ return ret;
+}
+
+typedef std::set<int> int_set_type;
+int_set_type pressed_modifier_keys;
+xmodifier_type current_modifiers;
+
+void trackModifiers(int keycode, bool down)
+{
+ // is this a modifier key?
+ const bool is_modifier = keycode_to_modifier.find(keycode) != keycode_to_modifier.end();
+
+ if(!is_modifier)
+ {
+ return;
+ }
+
+ if(down) {
+ pressed_modifier_keys.insert(keycode);
+ } else {
+ pressed_modifier_keys.erase(keycode);
+ }
+
+ int_set_type::iterator i, end = pressed_modifier_keys.end();
+ xmodifier_type modifs = 0;
+ for(i = pressed_modifier_keys.begin(); i != end; i++)
+ {
+ keycode_to_modifier_map::iterator found_kc = keycode_to_modifier.find(*i);
+ if(found_kc != keycode_to_modifier.end())
+ {
+ modifs |= (*found_kc).second;
+ }
+ }
+ current_modifiers = modifs;
+
+ ConsoleLog writeLine(QString("[trackModifiers] current modifiers: %1").arg(modifiers_to_string(modifs)));
+}
+
+typedef std::pair<int, bool> modifier_tweak_type;
+typedef std::vector<modifier_tweak_type> tweak_sequence_type;
+
+void tweakModifiers(Display* dpy, xmodifier_type neededState, xmodifier_type actualState, tweak_sequence_type& tracker)
+{
+ ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiers_to_string(neededState)).arg(modifiers_to_string(actualState)));
+ for(int j = 0; j < 8; j++)
+ {
+ xmodifier_type i = 1<<j;
+
+ ConsoleLog writeLine(QString("Checking for %1...").arg(modifiers_to_string(i)));
+
+ if((i & neededState) && !(i & actualState))
+ {
+ ConsoleLog writeLine(QString("tweakModifiers: Modifier %1 needs to be pressed").arg(modifiernames[j]));
+
+ // needs to be pressed
+
+ //find the keycode:
+ int kc;
+ modifier_to_keycode_map::iterator iter = modifier_to_keycode.find(i);
+
+ if((iter == modifier_to_keycode.end()) || ((*iter).first != i))
+ {
+ continue; // we don't know a key that triggers this modifier
+ }
+
+ ConsoleLog writeLine(QString(" pressing key %1").arg((*iter).second));
+ XTestFakeKeyEvent(dpy, (*iter).second, 1, CurrentTime);
+
+ tracker.push_back(std::make_pair((*iter).second, true));
+ }
+ else if((!(i & neededState)) && (i & actualState))
+ {
+ ConsoleLog writeLine(QString("tweakModifiers: Modifier %1 needs to be released").arg(modifiernames[j]));
+
+ // needs to be released
+
+ int kc = -1;
+ // first, check whether any of the currently pressed keys has triggered this modifier:
+
+ int_set_type::iterator iter, end = pressed_modifier_keys.end();
+ for(iter = pressed_modifier_keys.begin(); iter != end; iter++)
+ {
+ keycode_to_modifier_map::iterator modmap_iter = keycode_to_modifier.find(*iter);
+ if(modmap_iter != keycode_to_modifier.end()) {
+ if(modmap_iter->second == i) {
+ kc = *iter;
+
+ // release this key:
+ ConsoleLog writeLine(QString(" releasing key %1").arg(kc));
+ XTestFakeKeyEvent(dpy, kc, 0, CurrentTime);
+ tracker.push_back(std::make_pair(kc, false));
+ }
+ }
+ }
+
+ if(kc == -1) {
+ // strange, but we need to release some other key:
+ // we don't know which one, so we abort this and hope for the best
+ continue;
+ }
+ }
+ }
+}
+
+void untweakModifiers(Display* dpy, tweak_sequence_type& tracker)
+{
+ tweak_sequence_type::iterator i, end = tracker.end();
+ for(i = tracker.begin(); i != end; i++) {
+ modifier_tweak_type& t = *i;
+ XTestFakeKeyEvent(dpy, t.first, !t.second, CurrentTime);
+ }
+}
+
+void X11FakeKeyboardHandler::initialize()
+{
+ initialize_keysyms();
+ initialize_basic_keycodes();
+ pressed_modifier_keys.clear();
+ current_modifiers = 0;
+}
+
+void X11FakeKeyboardHandler::handle(InputEvent const& evt)
+{
+ Display* dpy = X11InputUtils::display();
+
+ // find out which keysym caused this event:
+ lookup_table_const_iterator i = keysyms.find(evt.qt_keysym());
+ if(i == keysyms.end()) {
+ // Special cases. We don't know how to directly translate those, so we will try to emulate them.
+ switch(evt.qt_keysym())
+ {
+ case Qt::Key_Backtab:
+ handle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab));
+ break;
+ default:
+ ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qt_keysym(), 8, 16));
+ }
+ } else {
+ KeySym ks = (*i).second;
+
+ // is it a "normal" key?
+ if(ks >= ' ' && ks < 0x100)
+ {
+ if(basic_keycodes[ks] != -1)
+ {
+ if(evt.isPress())
+ {
+ // Try the simple way first:
+ // Does the keycode with current modifiers yield the requested symbol?
+ KeySym unmod_ks = XKeycodeToKeysym(dpy, basic_keycodes[ks], current_modifiers);
+ ConsoleLog writeLine(QString("Pressing the key for %1 would yield %2 right now.").arg(XKeysymToString(ks)).arg(XKeysymToString(unmod_ks)));
+
+ if(ks == XKeycodeToKeysym(dpy, basic_keycodes[ks], current_modifiers))
+ {
+ XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime);
+ }
+ else
+ {
+ // what modifier keys do we need to press?
+ xmodifier_type mods = translate_modifiers(evt.qt_modifiers());
+
+ // we may need to press additional modifiers to generate this keysym:
+ // but, since we do not differentiate upper and lower case,
+ // and instead let the sender handle those modifiers,
+ // we need to AND ShiftModifier and LockModifier out.
+ mods |= basic_modifiers[ks] & ~(1<<ShiftMapIndex) & ~(1<<LockMapIndex);
+
+ // now, tweak the modifiers
+ tweak_sequence_type tweaks;
+ tweakModifiers(dpy, mods, current_modifiers, tweaks);
+
+ // press the key:
+ XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime);
+
+ // and release the modifiers:
+ untweakModifiers(dpy, tweaks);
+ }
+ }
+ else
+ {
+ // just release the key.
+ XTestFakeKeyEvent(dpy, basic_keycodes[ks], 0, CurrentTime);
+ }
+ }
+ else
+ {
+ ConsoleLog writeLine(QString("No keycode is mapped to `%1'").arg(XKeysymToString(ks)));
+ }
+ }
+ else
+ {
+ // It is some kind of "special" key, so we just fake that, then:
+ KeyCode kc = XKeysymToKeycode(dpy, ks);
+ if(kc != 0)
+ {
+ ConsoleLog writeLine(QString("%1 special keycode %2, hopefully giving keysym %3").arg(evt.isPress() ? "Pressed" : "Released").arg(kc).arg(XKeysymToString(ks)));
+ XTestFakeKeyEvent(dpy, kc, evt.isPress(), CurrentTime);
+ // and track it if it is a modifier key:
+ trackModifiers(kc, evt.isPress());
+ }
+ else
+ {
+ ConsoleLog writeLine(QString("No keycode is mapped to %1").arg(XKeysymToString(ks)));
+ }
+ }
+ }
+
+ // Since there may not be a mainloop running, we need to manually flush the event queue
+ XFlush(dpy);
+}
diff --git a/src/input/x11FakeKeyboardHandler.h b/src/input/x11FakeKeyboardHandler.h
new file mode 100644
index 0000000..c888202
--- /dev/null
+++ b/src/input/x11FakeKeyboardHandler.h
@@ -0,0 +1,29 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # x11FakeKeyboardHandler.h:
+ # - Handle keyboard events on X11 - interface
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef X11FAKEKEYBOARDHANDLER_H_
+#define X11FAKEKEYBOARDHANDLER_H_
+
+#include "inputEventHandler.h"
+
+class X11FakeKeyboardHandler : public DefaultInputEventHandler<InputEvent::ET_KEY>
+{
+public:
+ static void handle(InputEvent const&);
+ static void initialize();
+};
+
+#endif /* X11FAKEKEYBOARDHANDLER_H_ */
diff --git a/src/input/x11FakeMouseHandler.cpp b/src/input/x11FakeMouseHandler.cpp
new file mode 100644
index 0000000..432e19f
--- /dev/null
+++ b/src/input/x11FakeMouseHandler.cpp
@@ -0,0 +1,59 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # x11FakeMouseHandler.h:
+ # - Handle mouse events on X11 - implementation
+ # --------------------------------------------------------------------------
+ */
+
+#include <src/util/consoleLogger.h>
+#include <X11/extensions/XTest.h>
+#include "x11InputUtils.h"
+#include "x11FakeMouseHandler.h"
+
+void X11FakeMouseButtonHandler::handle(InputEvent const& evt)
+{
+ quint16 pressedButton = evt.pressedButton();
+
+ Display* dpy = X11InputUtils::display();
+
+ XTestGrabControl(dpy, 1);
+ for(int i = 0; i < 16; i++) {
+ if((1<<i) == pressedButton)
+ {
+ ConsoleLog writeLine(QString("Got mouse button event: button %1 %2").arg(i + 1).arg(evt.isPress() ? "pressed" : "released"));
+ if(!XTestFakeButtonEvent(dpy, i + 1, evt.isPress(), CurrentTime))
+ {
+ ConsoleLog writeLine("[ERROR] XTestFakeButtonEvent failed");
+ }
+ }
+ }
+ XTestGrabControl(dpy, 0);
+
+ // Since there may not be a mainloop running, we need to manually flush the event queue
+ XFlush(dpy);
+}
+
+void X11FakeMouseMovementHandler::handle(InputEvent const& evt)
+{
+ ConsoleLog writeLine(QString("Received mouse motion event (%1,%2)").arg(evt.xCoord()).arg(evt.yCoord()));
+ Display* dpy = X11InputUtils::display();
+ int screen = 0 /* DefaultScreen(dpy) */;
+ XTestGrabControl(dpy, 1);
+ if(!XTestFakeMotionEvent(dpy, screen, evt.xCoord(), evt.yCoord(), CurrentTime))
+ {
+ ConsoleLog writeLine("[ERROR] XTestFakeMotionEvent failed");
+ }
+ XTestGrabControl(dpy, 0);
+
+ // Since there may not be a mainloop running, we need to manually flush the event queue
+ XFlush(dpy);
+}
diff --git a/src/input/x11FakeMouseHandler.h b/src/input/x11FakeMouseHandler.h
new file mode 100644
index 0000000..19ed29e
--- /dev/null
+++ b/src/input/x11FakeMouseHandler.h
@@ -0,0 +1,34 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # x11FakeMouseHandler.h:
+ # - Handle mouse events on X11 - interface
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef X11FAKEMOUSEHANDLER_H_
+#define X11FAKEMOUSEHANDLER_H_
+
+#include "inputEventHandler.h"
+
+class X11FakeMouseButtonHandler : public DefaultInputEventHandler<InputEvent::ET_BUTTON>
+{
+public:
+ static void handle(InputEvent const&);
+};
+
+class X11FakeMouseMovementHandler : public DefaultInputEventHandler<InputEvent::ET_POINTER>
+{
+public:
+ static void handle(InputEvent const&);
+};
+
+#endif /* X11FAKEMOUSEHANDLER_H_ */
diff --git a/src/input/x11InputUtils.cpp b/src/input/x11InputUtils.cpp
new file mode 100644
index 0000000..b589bd6
--- /dev/null
+++ b/src/input/x11InputUtils.cpp
@@ -0,0 +1,29 @@
+/*
+ # Copyright (c) 2009, 2010 - OpenSLX Project, Computer Center University of
+ # Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # ------------------------------------------------------------------------
+ # src/input/x11InputUtils.h:
+ # Utilities for input handling under X11 - implementation
+ */
+
+#include "x11InputUtils.h"
+
+static Display* _dpy = 0;
+
+void X11InputUtils::setDisplay(Display* dpy)
+{
+ _dpy = dpy;
+}
+
+Display* X11InputUtils::display()
+{
+ return _dpy;
+}
diff --git a/src/input/x11InputUtils.h b/src/input/x11InputUtils.h
new file mode 100644
index 0000000..9c85d09
--- /dev/null
+++ b/src/input/x11InputUtils.h
@@ -0,0 +1,27 @@
+/*
+ # Copyright (c) 2009, 2010 - OpenSLX Project, Computer Center University of
+ # Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # ------------------------------------------------------------------------
+ # src/input/x11InputUtils.h:
+ # Utilities for input handling under X11 - interface
+ */
+
+#ifndef X11INPUTUTILS_H_
+#define X11INPUTUTILS_H_
+
+#include <X11/Xlib.h>
+
+struct X11InputUtils {
+ static void setDisplay(Display*);
+ static Display* display();
+};
+
+#endif /* X11INPUTUTILS_H_ */
diff --git a/src/pvs.cpp b/src/pvs.cpp
index 2069e36..e44d04d 100644
--- a/src/pvs.cpp
+++ b/src/pvs.cpp
@@ -15,6 +15,9 @@
#include "src/net/pvsMsg.h"
#include "src/net/pvsServiceDiscovery.h"
#include "src/net/pvsDiscoveredServer.h"
+#include "src/input/inputEvent.h"
+#include "src/input/unprivilegedHandlerChain.h"
+#include "src/input/x11InputUtils.h"
// D-Bus
#include "pvsadaptor.h"
@@ -76,6 +79,7 @@ PVS::PVS() :
sigaction(SIGINT, &act, 0);
sigaction(SIGQUIT, &act, 0);
+ initializeInputEventHandling();
}
PVS::~PVS()
@@ -176,6 +180,12 @@ void PVS::onCommand(PVSMsg cmdMessage)
unlock();
return;
}
+ if (ident.compare("INPUTEVENT") == 0)
+ {
+ InputEvent evt;
+ eventFromString(message, evt);
+ handleInputEvent(evt);
+ }
#ifdef never
// prototype
@@ -627,3 +637,17 @@ void PVS::signalHandler(int signal)
}
+// Input handling
+
+void PVS::handleInputEvent(InputEvent const& evt)
+{
+ std::string s = evt.toString();
+ ConsoleLog writeLine(QString("Received input event: %1").arg(s.c_str()));
+ unprivileged_handler_chain::handle(evt);
+}
+
+void PVS::initializeInputEventHandling()
+{
+ X11InputUtils::setDisplay(X11Info::display());
+ unprivileged_handler_chain::initialize();
+}
diff --git a/src/pvs.h b/src/pvs.h
index 4b1e29e..8e94169 100644
--- a/src/pvs.h
+++ b/src/pvs.h
@@ -28,6 +28,7 @@
class PVSServiceDiscovery;
class PVSDiscoveredServer;
+class InputEvent;
/**
* PVSClient
@@ -142,5 +143,8 @@ private:
int _timerLockTest;
int _timerLockDelay;
+ // input event handling:
+ void handleInputEvent(InputEvent const& evt);
+ void initializeInputEventHandling();
};
#endif /* PVSCLIENT_H_ */
diff --git a/src/util/clientGUIUtils.cpp b/src/util/clientGUIUtils.cpp
index 4d4cc0d..a8a9487 100644
--- a/src/util/clientGUIUtils.cpp
+++ b/src/util/clientGUIUtils.cpp
@@ -2,7 +2,7 @@
BlankScreen::BlankScreen()
{
- dpy = XOpenDisplay(NULL);
+ dpy = X11Info::display();
scr = DefaultScreen(dpy);
assert(dpy);
blackColor = BlackPixel(dpy, DefaultScreen(dpy));
@@ -142,3 +142,14 @@ bool BlankScreen::unlock()
lockMsg.clear();
return !(locked = false);
}
+
+static Display* _dpy = 0;
+
+Display* X11Info::display()
+{
+ if(!_dpy)
+ {
+ _dpy = XOpenDisplay(0);
+ }
+ return _dpy;
+}
diff --git a/src/util/clientGUIUtils.h b/src/util/clientGUIUtils.h
index 28b05cc..4da0a99 100644
--- a/src/util/clientGUIUtils.h
+++ b/src/util/clientGUIUtils.h
@@ -36,4 +36,10 @@ private:
int offX, offY;
};
+class X11Info
+{
+public:
+ static Display* display();
+};
+
#endif