diff options
author | Sebastien Braun | 2010-10-04 00:22:14 +0200 |
---|---|---|
committer | Sebastien Braun | 2010-10-05 18:15:48 +0200 |
commit | 266eb5fb14c07e67aa211a5860e9abf3009136e3 (patch) | |
tree | 9eeb8b159edf6e83880c056f1177cebec2ad354c | |
parent | Defect #715, apply patch by Sébastien (diff) | |
download | pvs-266eb5fb14c07e67aa211a5860e9abf3009136e3.tar.gz pvs-266eb5fb14c07e67aa211a5860e9abf3009136e3.tar.xz pvs-266eb5fb14c07e67aa211a5860e9abf3009136e3.zip |
Implement first version of basic input event support
-rw-r--r-- | CMakeLists.txt | 12 | ||||
-rw-r--r-- | icons/README | 3 | ||||
-rw-r--r-- | icons/remote-control-all.png | bin | 0 -> 5365 bytes | |||
-rw-r--r-- | icons/remote-control.png | bin | 0 -> 3657 bytes | |||
-rw-r--r-- | pvsmgr.qrc | 2 | ||||
-rw-r--r-- | src/gui/frame.cpp | 246 | ||||
-rw-r--r-- | src/gui/frame.h | 27 | ||||
-rw-r--r-- | src/input/CMakeLists.txt | 19 | ||||
-rw-r--r-- | src/input/inputEvent.cpp | 98 | ||||
-rw-r--r-- | src/input/inputEvent.h | 218 | ||||
-rw-r--r-- | src/input/inputEventHandler.h | 187 | ||||
-rw-r--r-- | src/input/inputEventNonQt.cpp | 17 | ||||
-rw-r--r-- | src/input/unprivilegedHandlerChain.h | 34 | ||||
-rw-r--r-- | src/input/x11FakeKeyboardHandler.cpp | 800 | ||||
-rw-r--r-- | src/input/x11FakeKeyboardHandler.h | 29 | ||||
-rw-r--r-- | src/input/x11FakeMouseHandler.cpp | 59 | ||||
-rw-r--r-- | src/input/x11FakeMouseHandler.h | 34 | ||||
-rw-r--r-- | src/input/x11InputUtils.cpp | 29 | ||||
-rw-r--r-- | src/input/x11InputUtils.h | 27 | ||||
-rw-r--r-- | src/pvs.cpp | 24 | ||||
-rw-r--r-- | src/pvs.h | 4 | ||||
-rw-r--r-- | src/util/clientGUIUtils.cpp | 13 | ||||
-rw-r--r-- | src/util/clientGUIUtils.h | 6 |
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 Binary files differnew file mode 100644 index 0000000..bc7e2ae --- /dev/null +++ b/icons/remote-control-all.png diff --git a/icons/remote-control.png b/icons/remote-control.png Binary files differnew file mode 100644 index 0000000..ba460dd --- /dev/null +++ b/icons/remote-control.png @@ -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(); +} @@ -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 |