From e61097b8881bc7e72a5499816cb1199ea274a3ca Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Thu, 7 Oct 2010 22:54:10 +0200 Subject: Rework template meta-magic - No more implicit dependency on Boost.MPL - Better documentation for template magic - Move input handler policies to handler definitions where they belong - Separate out event descriptions from handlers --- src/gui/frame.cpp | 18 +- src/input/CMakeLists.txt | 5 +- src/input/allowLocalOrPrivileged.cpp | 21 ++ src/input/detail/Makefile.autogen | 8 + src/input/detail/gen/gen_policyChain.cpp | 68 +++++ src/input/detail/gen/gen_typeList.cpp | 115 ++++++++ src/input/detail/policyChain.h | 78 ++++++ src/input/detail/policyChain_autogen.h | 8 + src/input/detail/systemTraits.h | 94 +++++++ src/input/detail/typeList.h | 76 ++++++ src/input/detail/typeList_autogen.h | 60 ++++ src/input/inputEvent.cpp | 32 +++ src/input/inputEvent.h | 49 ++-- src/input/inputEventHandler.cpp | 21 +- src/input/inputEventHandler.h | 407 ++++++++++++++-------------- src/input/inputHandlerChain.h | 49 ---- src/input/inputHandlerChains.h | 25 ++ src/input/killX11Handler.cpp | 2 +- src/input/killX11Handler.h | 14 +- src/input/magicSysRqHandler.cpp | 2 +- src/input/magicSysRqHandler.h | 52 +--- src/input/privilegedHandlerForwarder.cpp | 4 +- src/input/privilegedHandlerForwarder.h | 6 +- src/input/privilegedInputHandlerChain.cpp | 30 ++ src/input/pvsPrivInputHandler.cpp | 3 +- src/input/pvsPrivInputHandler.h | 4 +- src/input/rebootSystemHandler.cpp | 2 +- src/input/rebootSystemHandler.h | 10 +- src/input/sayHelloHandler.cpp | 2 +- src/input/sayHelloHandler.h | 11 +- src/input/unprivilegedInputHandlerChain.cpp | 30 ++ src/input/x11FakeKeyboardHandler.cpp | 4 +- src/input/x11FakeKeyboardHandler.h | 8 +- src/input/x11FakeMouseHandler.cpp | 4 +- src/input/x11FakeMouseHandler.h | 14 +- src/pvs.cpp | 7 +- src/pvs.h | 4 +- 37 files changed, 968 insertions(+), 379 deletions(-) create mode 100644 src/input/allowLocalOrPrivileged.cpp create mode 100644 src/input/detail/Makefile.autogen create mode 100644 src/input/detail/gen/gen_policyChain.cpp create mode 100644 src/input/detail/gen/gen_typeList.cpp create mode 100644 src/input/detail/policyChain.h create mode 100644 src/input/detail/policyChain_autogen.h create mode 100644 src/input/detail/systemTraits.h create mode 100644 src/input/detail/typeList.h create mode 100644 src/input/detail/typeList_autogen.h delete mode 100644 src/input/inputHandlerChain.h create mode 100644 src/input/inputHandlerChains.h create mode 100644 src/input/privilegedInputHandlerChain.cpp create mode 100644 src/input/unprivilegedInputHandlerChain.cpp diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp index 1b80c3d..12ce6b5 100644 --- a/src/gui/frame.cpp +++ b/src/gui/frame.cpp @@ -19,7 +19,6 @@ */ #include -#include #include "frame.h" #include #include @@ -434,19 +433,18 @@ 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())); + ConsoleLog writeLine(QString("sendInputEvent(%1) to one").arg(evt.toString())); PVSConnectionManager::getManager()->getServer()->sendToAll(msg); } else { - ConsoleLog writeLine(QString("sendInputEvent(%1) to all").arg(evtStr.c_str())); + ConsoleLog writeLine(QString("sendInputEvent(%1) to all").arg(evt.toString())); _cFrame->getConnection()->sendMessage(msg); } } @@ -592,14 +590,14 @@ void Frame::showSpecialEventMenu() { qDebug("Trying to show menu..."); QMenu* menu = new QMenu(this); - QList specialEvents = privileged_handler_chain::describe(); - QList::iterator iter; + QList specialEvents = SpecialInputEventDescription::describeSpecialEvents(); + QListIterator iter(specialEvents); int i; - for(i = 0, iter = specialEvents.begin(); - iter != specialEvents.end(); - iter++, i++) + for(i = 0; + iter.hasNext(); + i++) { - QAction* act = menu->addAction((*iter).descriptionString); + QAction* act = menu->addAction(iter.next().description); act->setData(i); } QAction* selected = menu->exec(QCursor::pos()); diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 20fd531..689fd39 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -2,6 +2,8 @@ include(${QT_USE_FILE}) set(pvsinput_SRCS inputEvent.cpp + unprivilegedInputHandlerChain.cpp + inputEventHandler.cpp ) if(UNIX) @@ -23,7 +25,8 @@ if(UNIX) killX11Handler.cpp magicSysRqHandler.cpp sayHelloHandler.cpp - inputEventHandler.cpp + privilegedInputHandlerChain.cpp + allowLocalOrPrivileged.cpp ) set(pvsprivinputd_MOC_HDRS diff --git a/src/input/allowLocalOrPrivileged.cpp b/src/input/allowLocalOrPrivileged.cpp new file mode 100644 index 0000000..ba456dc --- /dev/null +++ b/src/input/allowLocalOrPrivileged.cpp @@ -0,0 +1,21 @@ +/* + * inputHandlerSecurityPolicies.cpp + * + * Created on: Oct 7, 2010 + * Author: brs + */ + +#include "inputEventHandler.h" +#include "pvsCheckPrivileges.h" + +bool input_policy::AllowLocalOrPrivileged::allow(InputEventContext const* ctx) +{ + if(ctx) + { + if(PVSCheckPrivileges::instance()->require(PVSCheckPrivileges::SESSION_LOCAL, ctx)) + return true; + if(PVSCheckPrivileges::instance()->require(PVSCheckPrivileges::USER_PRIVILEGED, ctx)) + return true; + } + return false; +} diff --git a/src/input/detail/Makefile.autogen b/src/input/detail/Makefile.autogen new file mode 100644 index 0000000..6d0bfb3 --- /dev/null +++ b/src/input/detail/Makefile.autogen @@ -0,0 +1,8 @@ +all : policyChain_autogen.h typeList_autogen.h +.PHONY : all + +policyChain_autogen.h : gen/gen_policyChain + gen/gen_policyChain > policyChain_autogen.h + +typeList_autogen.h : gen/gen_typeList + gen/gen_typeList > typeList_autogen.h diff --git a/src/input/detail/gen/gen_policyChain.cpp b/src/input/detail/gen/gen_policyChain.cpp new file mode 100644 index 0000000..3e375ec --- /dev/null +++ b/src/input/detail/gen/gen_policyChain.cpp @@ -0,0 +1,68 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # detail/gen/gen_policyChain.cpp: + # - generate the input_policy::detail::PolicyChain class + # -------------------------------------------------------------------------- + */ + +#include + +using namespace std; + +#define NUM_POLICIES 8 + +int main(int, char**) +{ + int i; + + cout << "template\nstruct PolicyChain :\npublic P0::template apply_ >\n"; + cout << "{};\n"; + + // Base case: + cout << "template\n"; + cout << "struct PolicyChain : public BaseCase {};\n"; + + // We need the following in macros: + cout << "#define _autogen_POLICY_TEMPLATE_PARAMS "; + for(i = 0; i < NUM_POLICIES; i++) + { + if(i) + cout << ", "; + cout << "typename P" << i; + } + + cout << "\n#define _autogen_POLICY_TEMPLATE_ARGS "; + for(i = 0; i < NUM_POLICIES; i++) + { + if(i) + cout << ", "; + cout << "P" << i; + } + cout << "\n"; + + return 0; +} diff --git a/src/input/detail/gen/gen_typeList.cpp b/src/input/detail/gen/gen_typeList.cpp new file mode 100644 index 0000000..e092b80 --- /dev/null +++ b/src/input/detail/gen/gen_typeList.cpp @@ -0,0 +1,115 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # detail/gen/gen_policyChain.cpp: + # - generate the input_policy::detail::TypeList class + # -------------------------------------------------------------------------- + */ + +#include + +using namespace std; + +#define NUM_MAX_ENTRIES 16 + +int main(int, char**) +{ + int i; + + cout << "template<"; + for(i = 0; i < NUM_MAX_ENTRIES; i++) + { + if(i) + cout << ", "; + cout << "typename T" << i << " = void"; + } + cout << ">\nstruct TypeList {\n"; + cout << "typedef T0 head;\n"; + cout << "typedef TypeList<"; + for(i = 1; i < NUM_MAX_ENTRIES; i++) + { + if(i > 1) + cout << ", "; + cout << "T" << i; + } + cout << ", void > tail;\n"; + cout << "};\n"; + + // Contains: + cout << "template\n" + "struct Contains { static const int index = -1; static const bool value = false; };\n"; + + for(i = 0; i < NUM_MAX_ENTRIES; i++) + { + int j; + + cout << "template\nstruct Contains >\n{ static const int index = " << i << "; static const bool value = true; };\n"; + } + + // Empty List: + cout << "typedef TypeList<"; + for(i = 0; i < NUM_MAX_ENTRIES; i++) + { + if(i) + cout << ", "; + cout << "void"; + } + cout << " > EmptyList;\n"; + + // Macros: + cout << "#define IMPLICIT_TYPE_LIST_PARAMS(prefix) "; + for(i = 0; i < NUM_MAX_ENTRIES; i++) + { + if(i) + cout << ", "; + cout << "typename prefix##" << i << " = void"; + } + cout << "\n"; + + cout << "#define IMPLICIT_TYPE_LIST_PARAMS_NODEFAULT(prefix) "; + for(i = 0; i < NUM_MAX_ENTRIES; i++) + { + if(i) + cout << ", "; + cout << "typename prefix##" << i; + } + cout << "\n"; + + cout << "#define IMPLICIT_TYPE_LIST_ARGS(prefix) "; + for(i = 0; i < NUM_MAX_ENTRIES; i++) + { + if(i) + cout << ", "; + cout << "prefix##" << i; + } + cout << "\n"; + + cout << "#define IMPLICIT_TYPE_LIST(prefix) ::input_policy::detail::TypeList\n"; + + return 0; +} diff --git a/src/input/detail/policyChain.h b/src/input/detail/policyChain.h new file mode 100644 index 0000000..ae01ff2 --- /dev/null +++ b/src/input/detail/policyChain.h @@ -0,0 +1,78 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # detail/policyChain.h: + # - Tie together the different bits of policy information a handler may + # give us + # -------------------------------------------------------------------------- + */ + +#ifndef POLICYCHAIN_H_ +#define POLICYCHAIN_H_ + +#include "typeList.h" + +namespace input_policy +{ +namespace detail +{ + +template +struct PolicyChain : public PolicyList::head::template apply_ > +{ +}; + +template +struct PolicyChain : public BaseCase +{ +private: + struct This_Should_Not_Work; +public: + static const int test_value = sizeof(This_Should_Not_Work); +}; + +} +} + +///////////////////////////////////////////////////////////////////////// +// Macros that enable specification of policies: +// A policy is declared like this: +// template< PARAM1, PARAM2, ... > +// BEGIN_POLICY_CLASS(MyPolicy) { +// static const int field1 = 2; +// ... +// } END_POLICY_CLASS(MyPolicy); +///////////////////////////////////////////////////////////////////////// +#define BEGIN_POLICY_CLASS(policyName) \ + struct policyName { \ + template \ + struct apply_ : public NextPolicy +#define END_POLICY_CLASS \ + ; }; + +///////////////////////////////////////////////////////////////////////// +// A macro that enables us to use a template parameter list +// in a class using a policy, like this: +// +// template +// struct MyPolicyBasedClass +// { +// typedef USE_POLICY(baseCase) policy_type; +// }; +// +// now, the following type is valid: +// MyPolicyBasedClass +///////////////////////////////////////////////////////////////////////// +#define POLICY_PARAMS IMPLICIT_TYPE_LIST_PARAMS(Policy) +#define POLICY_PARAMS_LIST IMPLICIT_TYPE_LIST(Policy) +#define USE_POLICY(baseCase) ::input_policy::detail::PolicyChain + +#endif /* POLICYCHAIN_H_ */ diff --git a/src/input/detail/policyChain_autogen.h b/src/input/detail/policyChain_autogen.h new file mode 100644 index 0000000..d9503b8 --- /dev/null +++ b/src/input/detail/policyChain_autogen.h @@ -0,0 +1,8 @@ +template +struct PolicyChain : +public P0::template apply_ > +{}; +template +struct PolicyChain : public BaseCase {}; +#define _autogen_POLICY_TEMPLATE_PARAMS typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7 +#define _autogen_POLICY_TEMPLATE_ARGS P0, P1, P2, P3, P4, P5, P6, P7 diff --git a/src/input/detail/systemTraits.h b/src/input/detail/systemTraits.h new file mode 100644 index 0000000..7f5582f --- /dev/null +++ b/src/input/detail/systemTraits.h @@ -0,0 +1,94 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # detail/systemTraits.h: + # - Define system traits and provide a way to match against them + # -------------------------------------------------------------------------- + */ + +#ifndef SYSTEMTRAITS_H_ +#define SYSTEMTRAITS_H_ + +#include "typeList.h" + +#define DEFINE_SYSTEM_TRAIT(name) struct name; +#define BEGIN_SYSTEM_TRAITS typedef TypeList< +#define END_SYSTEM_TRAITS > SystemTraits; + +namespace input_policy +{ + +// Trait names are externally visible. +DEFINE_SYSTEM_TRAIT(UnixLike) +DEFINE_SYSTEM_TRAIT(LinuxSystem) +DEFINE_SYSTEM_TRAIT(X11GUI) +DEFINE_SYSTEM_TRAIT(ConsoleKitSupported) + +namespace detail +{ +BEGIN_SYSTEM_TRAITS +#ifdef __linux +UnixLike, +LinuxSystem, +X11GUI, +ConsoleKitSupported +#endif +END_SYSTEM_TRAITS +} + +///////////////////////////////////////////////////////////////////////// +// Boolean logic as applied to system traits +///////////////////////////////////////////////////////////////////////// +template +struct AllOf; + +template +struct AnyOf; + +namespace detail +{ +///////////////////////////////////////////////////////////////////////// +// Does the list of system traits match what we have given? +///////////////////////////////////////////////////////////////////////// +template +struct Matches +{ + // if Needles is neither AnyOf<...> nor AllOf<...> + // then we need to know if the Haystack contains it: + static const bool value = Contains::value; +}; + +template +struct MatchesPredicate +{ + template + struct apply + { + static const bool value = Matches::value; + }; +}; + +template +struct Matches, Haystack> +{ + static const bool value = ForAnyInTypeList, IMPLICIT_TYPE_LIST(T)>::value; +}; + +template +struct Matches, Haystack> +{ + static const bool value = ForAllInTypeList, IMPLICIT_TYPE_LIST(T)>::value; +}; +} + +} + +#endif /* SYSTEMTRAITS_H_ */ diff --git a/src/input/detail/typeList.h b/src/input/detail/typeList.h new file mode 100644 index 0000000..5b915a9 --- /dev/null +++ b/src/input/detail/typeList.h @@ -0,0 +1,76 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # detail/typeList.h: + # - Compile-time metaprogramming facilities: Type Lists and Member Check + # -------------------------------------------------------------------------- + */ + +#ifndef TYPELIST_H_ +#define TYPELIST_H_ + +namespace input_policy +{ +namespace detail +{ + +///////////////////////////////////////////////////////////////////////// +// TypeList, Contains, EmptyList: +// This class is autogenerated by gen/gen_typeList.cpp +///////////////////////////////////////////////////////////////////////// +#include "typeList_autogen.h" + +///////////////////////////////////////////////////////////////////////// +// Type-level functions that do not need to be autogenerated as they +// do not depend on the maximum number of entries: +// +// ForAnyInTypeList::value == true +// if there is any entry E in List for which +// Predicate::apply::value == true +///////////////////////////////////////////////////////////////////////// +template +struct ForAnyInTypeList +{ + static const bool value = + Predicate::template apply::value || + ForAnyInTypeList::value; +}; + +template +struct ForAnyInTypeList +{ + static const bool value = false; +}; + +///////////////////////////////////////////////////////////////////////// +// ForAllInTypeList::value == true +// if there is not any entry E in List for which +// Predicate::apply::value == false +///////////////////////////////////////////////////////////////////////// +template +struct ForAllInTypeList +{ + static const bool value = + Predicate::template apply::value && + ForAllInTypeList::value; +}; + +template +struct ForAllInTypeList +{ + static const bool value = true; +}; + +} + +} + +#endif /* TYPELIST_H_ */ diff --git a/src/input/detail/typeList_autogen.h b/src/input/detail/typeList_autogen.h new file mode 100644 index 0000000..0f8fdd4 --- /dev/null +++ b/src/input/detail/typeList_autogen.h @@ -0,0 +1,60 @@ +template +struct TypeList { +typedef T0 head; +typedef TypeList tail; +}; +template +struct Contains { static const int index = -1; static const bool value = false; }; +template +struct Contains > +{ static const int index = 0; static const bool value = true; }; +template +struct Contains > +{ static const int index = 1; static const bool value = true; }; +template +struct Contains > +{ static const int index = 2; static const bool value = true; }; +template +struct Contains > +{ static const int index = 3; static const bool value = true; }; +template +struct Contains > +{ static const int index = 4; static const bool value = true; }; +template +struct Contains > +{ static const int index = 5; static const bool value = true; }; +template +struct Contains > +{ static const int index = 6; static const bool value = true; }; +template +struct Contains > +{ static const int index = 7; static const bool value = true; }; +template +struct Contains > +{ static const int index = 8; static const bool value = true; }; +template +struct Contains > +{ static const int index = 9; static const bool value = true; }; +template +struct Contains > +{ static const int index = 10; static const bool value = true; }; +template +struct Contains > +{ static const int index = 11; static const bool value = true; }; +template +struct Contains > +{ static const int index = 12; static const bool value = true; }; +template +struct Contains > +{ static const int index = 13; static const bool value = true; }; +template +struct Contains > +{ static const int index = 14; static const bool value = true; }; +template +struct Contains > +{ static const int index = 15; static const bool value = true; }; +typedef TypeList EmptyList; +#define IMPLICIT_TYPE_LIST_PARAMS(prefix) typename prefix##0 = void, typename prefix##1 = void, typename prefix##2 = void, typename prefix##3 = void, typename prefix##4 = void, typename prefix##5 = void, typename prefix##6 = void, typename prefix##7 = void, typename prefix##8 = void, typename prefix##9 = void, typename prefix##10 = void, typename prefix##11 = void, typename prefix##12 = void, typename prefix##13 = void, typename prefix##14 = void, typename prefix##15 = void +#define IMPLICIT_TYPE_LIST_PARAMS_NODEFAULT(prefix) typename prefix##0, typename prefix##1, typename prefix##2, typename prefix##3, typename prefix##4, typename prefix##5, typename prefix##6, typename prefix##7, typename prefix##8, typename prefix##9, typename prefix##10, typename prefix##11, typename prefix##12, typename prefix##13, typename prefix##14, typename prefix##15 +#define IMPLICIT_TYPE_LIST_ARGS(prefix) prefix##0, prefix##1, prefix##2, prefix##3, prefix##4, prefix##5, prefix##6, prefix##7, prefix##8, prefix##9, prefix##10, prefix##11, prefix##12, prefix##13, prefix##14, prefix##15 +#define IMPLICIT_TYPE_LIST(prefix) ::input_policy::detail::TypeList diff --git a/src/input/inputEvent.cpp b/src/input/inputEvent.cpp index 9b69a3a..f5abf43 100644 --- a/src/input/inputEvent.cpp +++ b/src/input/inputEvent.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -97,3 +98,34 @@ InputEvent InputEvent::keyboardRelease(int key, int mods) return InputEvent(ET_KEY, EC_RELEASE, value); } +#define describe(list, description, type, code, value) \ + list.append(SpecialInputEventDescription(InputEvent::type, InputEvent::code, value, QCoreApplication::translate("InputEvent", description))) + +QList SpecialInputEventDescription::describeSpecialEvents() +{ + QList list; + describe(list, "Say Hello", ET_SPECIAL, EC_SAY_HELLO, 0); + describe(list, "Reboot", ET_SPECIAL, EC_REBOOT, 0); + describe(list, "Kill X Server", ET_SPECIAL, EC_KILL_X, 0); + describe(list, "Reboot immediately", ET_SPECIAL, EC_SYSRQ, 'b'); + describe(list, "Power off immediately", ET_SPECIAL, EC_SYSRQ, 'o'); + describe(list, "Crash System", ET_SPECIAL, EC_SYSRQ, 'c'); + describe(list, "Turn off raw keyboard mode", ET_SPECIAL, EC_SYSRQ, 'r'); + describe(list, "Send SIGTERM to all", ET_SPECIAL, EC_SYSRQ, 'e'); + describe(list, "Send SIGKILL to all", ET_SPECIAL, EC_SYSRQ, 'i'); + describe(list, "Kill all on this terminal", ET_SPECIAL, EC_SYSRQ, 'k'); + describe(list, "Activate OOM killer", ET_SPECIAL, EC_SYSRQ, 'f'); + describe(list, "Make real-time tasks niceable", ET_SPECIAL, EC_SYSRQ, 'n'); + describe(list, "Force-thaw filesystems", ET_SPECIAL, EC_SYSRQ, 'j'); + describe(list, "Sync all mounted filesystems", ET_SPECIAL, EC_SYSRQ, 's'); + describe(list, "Remount all readonly", ET_SPECIAL, EC_SYSRQ, 'u'); + describe(list, "Show all held locks", ET_SPECIAL, EC_SYSRQ, 'd'); + describe(list, "Show stack traces", ET_SPECIAL, EC_SYSRQ, 'l'); + describe(list, "Dump memory info", ET_SPECIAL, EC_SYSRQ, 'm'); + describe(list, "Dump registers and flags", ET_SPECIAL, EC_SYSRQ, 'p'); + describe(list, "Dump timers and clockevents", ET_SPECIAL, EC_SYSRQ, 'q'); + describe(list, "Dump task list", ET_SPECIAL, EC_SYSRQ, 't'); + describe(list, "Dump uninterruptible tasks", ET_SPECIAL, EC_SYSRQ, 'w'); + describe(list, "Dump ftrace buffer", ET_SPECIAL, EC_SYSRQ, 'z'); + return list; +} diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h index 7a64bfc..2f557ce 100644 --- a/src/input/inputEvent.h +++ b/src/input/inputEvent.h @@ -18,9 +18,7 @@ #define INPUTEVENT_H_ #include -#include -#include -#include +#include #ifndef __linux # error "This will only run on a Linux system. Porting is required for other systems." @@ -46,8 +44,13 @@ private: // 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(uint16_t type, uint16_t code, uint32_t value = 0) : type_(type), code_(code), value_(value) + { + } + + InputEvent(InputEvent const& other) : type_(other.type_), code_(other.code_), value_(other.value_) { } @@ -158,7 +161,7 @@ public: return (value_ & 0xffff); } - static std::string typeToString(uint16_t type) + static QString typeToString(uint16_t type) { switch(type) { @@ -171,13 +174,11 @@ public: case ET_SPECIAL: return "SPECIAL"; default: - std::ostringstream s; - s << std::hex << type; - return s.str(); + return QString::number(type, 16); } } - static std::string codeToString(uint16_t code) + static QString codeToString(uint16_t code) { switch(code) { @@ -192,17 +193,13 @@ public: case EC_KILL_X: return "KILL_X"; default: - std::ostringstream s; - s << std::hex << code; - return s.str(); + return QString::number(code, 16); } } - std::string toString() const + QString toString() const { - std::ostringstream s; - s << typeToString(type_) << ':' << codeToString(code_) << ':' << std::hex << value_; - return s.str(); + return QString("%1:%2:%3").arg(typeToString(type_)).arg(codeToString(code_)).arg(value_, 16); } uint32_t qt_keysym() const @@ -216,4 +213,24 @@ public: } }; +struct SpecialInputEventDescription +{ + SpecialInputEventDescription(uint16_t type, uint16_t code, uint32_t value, QString const& description_) + : type(type), code(code), value(value), description(description_) + { + } + + uint16_t type; + uint16_t code; + uint32_t value; + QString description; + + InputEvent toEvent() const + { + return InputEvent(type, code, value); + } + + static QList describeSpecialEvents(); +}; + #endif /* INPUTEVENT_H_ */ diff --git a/src/input/inputEventHandler.cpp b/src/input/inputEventHandler.cpp index c16c358..5298aed 100644 --- a/src/input/inputEventHandler.cpp +++ b/src/input/inputEventHandler.cpp @@ -17,20 +17,17 @@ #include "inputEventHandler.h" #include "pvsCheckPrivileges.h" -bool policy::allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx) +InputEventHandlerBase::HandlerStatus InputEventHandlerBase::handle(InputEvent const& evt, InputEventContext const* ctx) { - if(ctx) - return PVSCheckPrivileges::instance()->require(PVSCheckPrivileges::SESSION_UNKNOWN, PVSCheckPrivileges::USER_PRIVILEGED, - ctx); - else - return false; + if(!isApplicable(evt, ctx)) + return HANDLER_NOT_APPLICABLE; + if(!allow(evt, ctx)) + return HANDLER_NOT_ALLOWED; + doHandle(evt, ctx); + return HANDLER_MATCHED; } -bool policy::allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx) +bool input_policy::AllowEverybody::allow(InputEventContext const*) { - if(ctx) - return PVSCheckPrivileges::instance()->require(PVSCheckPrivileges::SESSION_LOCAL, PVSCheckPrivileges::USER_UNKNOWN, - ctx); - else - return false; + return true; } diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 52e3338..5b03a90 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -22,274 +22,283 @@ #include #include #include -#include -#include -#include #include +#include "detail/policyChain.h" +#include "detail/systemTraits.h" -#define HANDLER_TYPE_DONT_CARE 0xffff -#define HANDLER_CODE_DONT_CARE 0xffff -#define HANDLER_VALUE_DONT_CARE 0xffffffff - -class InputEventContext -{ -public: - virtual pid_t getSenderPid() const = 0; - virtual uid_t getSenderUid() const = 0; - virtual gid_t getSenderGid() const = 0; -}; - -struct SpecialInputEventDescription +struct InputEventContext { - SpecialInputEventDescription(QString const& d, quint16 t, quint16 c, quint32 v = 0) - : descriptionString(d), evtType(t), evtCode(c), evtValue(v) + InputEventContext() { + hasBeenDenied = false; } - QString descriptionString; - quint16 evtType; - quint16 evtCode; - quint32 evtValue; + virtual pid_t getSenderPid() const = 0; + virtual uid_t getSenderUid() const = 0; + virtual gid_t getSenderGid() const = 0; - InputEvent toEvent() const - { - return InputEvent(evtType, evtCode, evtValue); - } + mutable bool hasBeenDenied; }; -template -class DefaultInputEventHandler { -protected: - static QString tr(char const* string) - { - return QCoreApplication::translate("InputEventHandler", string); - } - -public: - virtual bool matches(InputEvent const& evt, InputEventContext const*) { - if(Type != HANDLER_TYPE_DONT_CARE) { - if(evt.type() != Type) - return false; - } - if(Code != HANDLER_CODE_DONT_CARE) { - if(evt.code() != Code) - return false; - } - if(Value != HANDLER_VALUE_DONT_CARE) { - if(evt.value() != Value) - return false; - } - return true; - } +namespace input_policy +{ - virtual void initialize() +///////////////////////////////////////////////////////////////////////// +// Policy: +// Modifies the behaviour of an input handler class. +// +// There are several kinds of policy: +// - Security Policy (When to allow a certain action) +// - System Requirements (When to enable a certain handler) +// - Applicability (When to consider a certain handler) +// +// Policies are tied together using the detail::PolicyChain class. +///////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////// +// Security Policy: +// At the moment there are two security policies: +// 1. If the user is on a local seat, allow. If the user is privileged, +// allow. Else deny. +// 2. Allow everybody. +// Additional security policies can be added by following the example +// set by AllowLocalOrPrivileged +///////////////////////////////////////////////////////////////////////// +template +BEGIN_POLICY_CLASS(Security) +{ + bool allow(InputEventContext const* context) { + return PolicyImpl::allow(context); } +} +END_POLICY_CLASS - virtual void handle(InputEvent const& evt, InputEventContext const*) = 0; - - static void describeInto(QList& description) - { - } +struct AllowLocalOrPrivileged +{ + static bool allow(InputEventContext const*); }; -namespace policy { - -enum SecurityFlags { - SEC_FREE_FOR_ALL, - SEC_PHYSICAL_OR_PRIVILEGED +struct AllowEverybody +{ + static bool allow(InputEventContext const*); }; -bool allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx); -bool allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx); +typedef Security Unprivileged; -struct SecurityAllowAny +///////////////////////////////////////////////////////////////////////// +// System Requirements: +// At the moment, this is trivial, as PVS only runs on Linux. But, +// as porting efforts are already underway, we include the necessary +// machinery anyway. +///////////////////////////////////////////////////////////////////////// +template +BEGIN_POLICY_CLASS(Require) { - bool allow(InputEvent const& evt, InputEventContext const* ctx) - { - return true; - } + static const bool areSystemRequirementsFulfilled = + NextPolicy::areSystemRequirementsFulfilled && + detail::Matches::value; +} +END_POLICY_CLASS + +///////////////////////////////////////////////////////////////////////// +// System Requirements: +// At the moment, this is trivial, as PVS only runs on Linux. But, +// as porting efforts are already underway, we include the necessary +// machinery anyway. +///////////////////////////////////////////////////////////////////////// +enum { + HANDLER_CODE_DONT_CARE = 0xffff, + HANDLER_VALUE_DONT_CARE = 0xffffffff }; -struct SecurityAllowPhysicalOrPrivileged +struct T; + +template +BEGIN_POLICY_CLASS(Match) { - bool allow(InputEvent const& evt, InputEventContext const* ctx) + bool isApplicable(InputEvent const& evt) { - if(allowPhysicalSeat(evt, ctx)) - return true; - else if(allowPrivilegedUser(evt, ctx)) - return true; - return false; + if(evt.type() != EventType) + return NextPolicy::isApplicable(evt); + if(EventCode != HANDLER_CODE_DONT_CARE && evt.code() != EventCode) + return NextPolicy::isApplicable(evt); + if(EventValue != HANDLER_VALUE_DONT_CARE && evt.value() != EventValue) + return NextPolicy::isApplicable(evt); + return true; } }; +END_POLICY_CLASS -struct UnixLike; -struct Linux; -struct Windows; - -#if defined(__linux) -typedef boost::mpl::vector2::type Systems; -#elif defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) -typedef boost::mpl::vector1::type Systems; -#else -# error "Porting is needed!" -#endif - -struct SystemEnabled; -struct SystemDisabled; - -template -struct RequireSystem -{ - typedef typename boost::mpl::contains::type enabled_type; - static const bool enabled = enabled_type::value; -}; - -struct RequireNoSystem +namespace detail { - typedef boost::mpl::bool_::type enabled_type; - static const bool enabled = enabled_type::value; -}; -} - -template -class HandlerHelper +///////////////////////////////////////////////////////////////////////// +// Base case: If no policies are given: +///////////////////////////////////////////////////////////////////////// +struct InputEventHandlerPolicyBase { -public: - bool handle(InputEvent const& evt, InputEventContext const* context = 0) { - if(!securityPolicy.allow(evt, context)) - { - std::string evtStr = evt.toString(); - qWarning("Input Event %s has been denied by security policy", evtStr.c_str()); - return true; - } - if(delegate.matches(evt, context)) { - delegate.handle(evt, context); - return true; - } else { - return false; - } - } + // The default security policy applies + typedef AllowLocalOrPrivileged DefaultSecurityPolicyImpl; - void initialize() + bool allow(InputEventContext const* context) { - delegate.initialize(); + return DefaultSecurityPolicyImpl::allow(context); } - static void describeInto(QList& list) - { - Delegate::describeInto(list); - } + // A handler that does not specify requirements works + // everywhere + static const bool areSystemRequirementsFulfilled = true; -private: - Delegate delegate; - SecurityPolicy securityPolicy; -}; - -template -class HandlerHelper -{ -public: - bool handle(InputEvent const& evt, InputEventContext const* context = 0) { + // Generate an error when no match policy is given. + bool isApplicable(InputEvent const&) + { return false; } + // If any policy implementation needs an initialization hook: + // Don't forget to call NextPolicy::initialize() in your + // implementation! void initialize() { } - - static void describeInto(QList&) - { - } }; -template -struct Handler : public HandlerHelper -{ -}; +} +} -template -struct ApplyDefaultSecurityPolicy +///////////////////////////////////////////////////////////////////////// +// We want a nice non-generic base so we can make a list of polymorphic +// handlers. +// +// The actual handler class need to provide doHandle and can override +// allow and isApplicable. +///////////////////////////////////////////////////////////////////////// +/* interface */ class InputEventHandlerBase { - typedef HandlerType type; -}; +public: + enum HandlerStatus + { + HANDLER_MATCHED, + HANDLER_NOT_ALLOWED, + HANDLER_NOT_APPLICABLE + }; -template -struct ApplyDefaultSecurityPolicy > -{ - typedef Handler type; + virtual void initialize() = 0; + HandlerStatus handle(InputEvent const& evt, InputEventContext const* context = 0); + +protected: + virtual bool allow(InputEvent const& event, InputEventContext const* context = 0) = 0; + virtual bool isApplicable(InputEvent const& event, InputEventContext const* context = 0) = 0; + virtual void doHandle(InputEvent const& event, InputEventContext const* context = 0) = 0; }; -template -struct InputEventHandlerChainHelper +///////////////////////////////////////////////////////////////////////// +// Now that the machinery is in place, we can finally define what it +// is like to be an input event handler: +///////////////////////////////////////////////////////////////////////// +template +class InputEventHandler : public InputEventHandlerBase { -private: - typedef typename boost::mpl::next::type next_iterator_type; - typedef InputEventHandlerChainHelper next_in_chain; - - typedef typename boost::mpl::deref::type handler_entry_type; - typedef typename ApplyDefaultSecurityPolicy::type handler_type; - - handler_type _handler; - next_in_chain _next; +protected: + typedef USE_POLICY(input_policy::detail::InputEventHandlerPolicyBase) policy_type; + policy_type policy; public: - void handle(InputEvent const& evt, InputEventContext const* context = 0) { - if(!_handler.handle(evt, context)) { - _next.handle(evt, context); - } + void initialize() + { + policy.initialize(); } - void initialize() { - _handler.initialize(); - _next.initialize(); - } + // Export this so the handler chain can decide whether to include this handler + static const bool areSystemRequirementsFulfilled = policy_type::areSystemRequirementsFulfilled; + +protected: + + typedef InputEventHandler super; - static void describeInto(QList& list) + // allow and isApplicable are actually provided by Policy. If the + // handler class wishes to override any of them, the policy implementation + // can be called by means of super. + bool allow(InputEvent const&, InputEventContext const* context = 0) { - handler_type::describeInto(list); - next_in_chain::describeInto(list); + return policy.allow(context); } - static QList describe() + bool isApplicable(InputEvent const& event, InputEventContext const* = 0) { - QList list; - describeInto(list); - return list; + return policy.isApplicable(event); } }; -template -struct InputEventHandlerChainHelper +///////////////////////////////////////////////////////////////////////// +// And we can chain input handlers together: +///////////////////////////////////////////////////////////////////////// +class InputEventHandlerChain { - void handle(InputEvent const&, InputEventContext const* context = 0) { - // do nothing - } +private: + QList handlers; + + ///////////////////////////////////////////////////////////////////////// + // We need to statically dispatch on a static member of HandlerType. + // Unfortunately, we cannot specialize member functions of a template. + // So, we need to make this a class with a static non-template member. + ///////////////////////////////////////////////////////////////////////// + template + struct ConditionallyAppend + { + static void doIt(InputEventHandlerChain* chain) + { + chain->handlers.append(new HandlerType); + } + }; - void initialize() { - // do nothing - } + template + struct ConditionallyAppend + { + static void doIt(InputEventHandlerChain*) + { + } + }; - static void describeInto(QList&) +public: + // Add an event handler to the chain. The argument is only for + // compilers which cannot handle template member functions + // correctly. + template + InputEventHandlerChain& add(HandlerType const* = 0) { - // do nothing + ConditionallyAppend::doIt(this); + return *this; } - static QList describe() + void initialize() { - return QList(); + QListIterator i(handlers); + while(i.hasNext()) + { + i.next()->initialize(); + } } -}; -template -struct InputEventHandlerChain : - public InputEventHandlerChainHelper::type, - typename boost::mpl::end::type> -{ + void handle(InputEvent const& event, InputEventContext const* context = 0) + { + QListIterator i(handlers); + while(i.hasNext()) + { + switch(i.next()->handle(event, context)) + { + case InputEventHandlerBase::HANDLER_MATCHED: + break; + case InputEventHandlerBase::HANDLER_NOT_ALLOWED: + context->hasBeenDenied = true; + case InputEventHandlerBase::HANDLER_NOT_APPLICABLE: + continue; + } + } + } }; #endif /* INPUTEVENTHANDLER_H_ */ diff --git a/src/input/inputHandlerChain.h b/src/input/inputHandlerChain.h deleted file mode 100644 index 3c9446c..0000000 --- a/src/input/inputHandlerChain.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - # 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 -#include "inputEventHandler.h" - -#include "x11FakeKeyboardHandler.h" -#include "x11FakeMouseHandler.h" -#include "privilegedHandlerForwarder.h" -#include "rebootSystemHandler.h" -#include "sayHelloHandler.h" -#include "killX11Handler.h" -#include "magicSysRqHandler.h" - -typedef boost::mpl::list< - Handler >, - Handler >, - Handler >, - Handler ->::type unprivileged_handler_list; - -typedef InputEventHandlerChain unprivileged_handler_chain; - -typedef boost::mpl::list< - Handler, - Handler >, - Handler >, - Handler > ->::type privileged_handler_list; - -typedef InputEventHandlerChain privileged_handler_chain; - -#endif /* INPUTHANDLERCHAIN_H_ */ diff --git a/src/input/inputHandlerChains.h b/src/input/inputHandlerChains.h new file mode 100644 index 0000000..a91e605 --- /dev/null +++ b/src/input/inputHandlerChains.h @@ -0,0 +1,25 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # inputHandlerChains.h: + # - Definition of the input handler chains - interface + # -------------------------------------------------------------------------- + */ + +#ifndef INPUTHANDLERCHAIN_H_ +#define INPUTHANDLERCHAIN_H_ + +#include "inputEventHandler.h" + +InputEventHandlerChain makeUnprivilegedInputEventHandlerChain(); +InputEventHandlerChain makePrivilegedInputEventHandlerChain(); + +#endif /* INPUTHANDLERCHAIN_H_ */ diff --git a/src/input/killX11Handler.cpp b/src/input/killX11Handler.cpp index 7ac75a1..572656e 100644 --- a/src/input/killX11Handler.cpp +++ b/src/input/killX11Handler.cpp @@ -25,7 +25,7 @@ using namespace std; -void KillX11Handler::handle(InputEvent const&, InputEventContext const* ctx) +void KillX11Handler::doHandle(InputEvent const&, InputEventContext const* ctx) { // Find out which display device is used: QString displayDevice = PVSCheckPrivileges::instance()->getX11DisplayDevice(ctx); diff --git a/src/input/killX11Handler.h b/src/input/killX11Handler.h index 2f3ef44..8c0d655 100644 --- a/src/input/killX11Handler.h +++ b/src/input/killX11Handler.h @@ -20,15 +20,15 @@ #include #include "inputEventHandler.h" -class KillX11Handler : public DefaultInputEventHandler +class KillX11Handler : public InputEventHandler< + input_policy::Match, + input_policy::Require > > { public: - void handle(InputEvent const&, InputEventContext const*); - - static void describeInto(QList& list) - { - list << SpecialInputEventDescription(tr(QT_TRANSLATE_NOOP("InputEventHandler", "Kill X Server")), InputEvent::ET_SPECIAL, InputEvent::EC_KILL_X); - } + void doHandle(InputEvent const&, InputEventContext const*); }; #endif /* KILLX11HANDLER_H_ */ diff --git a/src/input/magicSysRqHandler.cpp b/src/input/magicSysRqHandler.cpp index 108bfca..7c38216 100644 --- a/src/input/magicSysRqHandler.cpp +++ b/src/input/magicSysRqHandler.cpp @@ -17,7 +17,7 @@ #include #include "magicSysRqHandler.h" -void MagicSysRqHandler::handle(InputEvent const& evt, InputEventContext const*) +void MagicSysRqHandler::doHandle(InputEvent const& evt, InputEventContext const*) { QFile trigger("/proc/sysrq-trigger"); trigger.open(QIODevice::WriteOnly); diff --git a/src/input/magicSysRqHandler.h b/src/input/magicSysRqHandler.h index 563d091..ba02997 100644 --- a/src/input/magicSysRqHandler.h +++ b/src/input/magicSysRqHandler.h @@ -19,54 +19,16 @@ #include "inputEventHandler.h" -class MagicSysRqHandler : public DefaultInputEventHandler +class MagicSysRqHandler : public InputEventHandler< + input_policy::Match, + input_policy::Require > { public: - void handle(InputEvent const& evt, InputEventContext const* ctx); + void doHandle(InputEvent const& evt, InputEventContext const* ctx); - static void describeInto(QList& list) - { - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Reboot immediately"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'b'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Crash system"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'c'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Show all held logs"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'd'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Send SIGTERM to all"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'e'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Activate OOM killer"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'f'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Send SIGKILL to all"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'i'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Force thaw filesystems"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'j'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Kill all on terminal"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'k'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Show stack traces"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'l'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Dump memory info"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'm'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Make real-time tasks niceable"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'n'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Power off immediately"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'o'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Dump registers and flags"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'p'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Dump timers and clockevents"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'q'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Turn off raw keyboard mode"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'r'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Sync all mounted filesystems"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 's'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Dump task list"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 't'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Remount all read-only"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'u'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Dump uninterruptible tasks"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'w'); - list << SpecialInputEventDescription(QCoreApplication::translate("InputEventHandler", "Dump ftrace buffer"), - InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ, 'z'); - } +// static void describeInto(QList& list) +// { +// } }; #endif /* MAGICSYSRQHANDLER_H_ */ diff --git a/src/input/privilegedHandlerForwarder.cpp b/src/input/privilegedHandlerForwarder.cpp index 3c0b3bd..17c4ab1 100644 --- a/src/input/privilegedHandlerForwarder.cpp +++ b/src/input/privilegedHandlerForwarder.cpp @@ -45,9 +45,9 @@ void PrivilegedHandlerForwarder::initialize() } } -void PrivilegedHandlerForwarder::handle(InputEvent const& evt, InputEventContext const*) +void PrivilegedHandlerForwarder::doHandle(InputEvent const& evt, InputEventContext const*) { - qDebug("Trying to handle %s in PrivilegedHandlerForwarder", evt.toString().c_str()); + qDebug("Trying to handle %s in PrivilegedHandlerForwarder", evt.toString().toLocal8Bit().constData()); if(_socket < 0) { initialize(); diff --git a/src/input/privilegedHandlerForwarder.h b/src/input/privilegedHandlerForwarder.h index 37e8f24..f5a6cc3 100644 --- a/src/input/privilegedHandlerForwarder.h +++ b/src/input/privilegedHandlerForwarder.h @@ -19,10 +19,12 @@ #include "inputEventHandler.h" -class PrivilegedHandlerForwarder : public DefaultInputEventHandler +class PrivilegedHandlerForwarder : public InputEventHandler< + input_policy::Require, + input_policy::Unprivileged> { public: - void handle(InputEvent const& evt, InputEventContext const* = 0); + void doHandle(InputEvent const& evt, InputEventContext const* = 0); void initialize(); private: diff --git a/src/input/privilegedInputHandlerChain.cpp b/src/input/privilegedInputHandlerChain.cpp new file mode 100644 index 0000000..5764728 --- /dev/null +++ b/src/input/privilegedInputHandlerChain.cpp @@ -0,0 +1,30 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # privilegedInputHandlerChain.cpp + # - Definition of the input handler chains - implementation for privileged + # chain + # -------------------------------------------------------------------------- + */ + +#include "rebootSystemHandler.h" +#include "sayHelloHandler.h" +#include "killX11Handler.h" +#include "magicSysRqHandler.h" +#include "inputHandlerChains.h" + +InputEventHandlerChain makePrivilegedInputEventHandlerChain() +{ + return InputEventHandlerChain().add() + .add() + .add() + .add(); +} diff --git a/src/input/pvsPrivInputHandler.cpp b/src/input/pvsPrivInputHandler.cpp index 70ed1bc..bfa60ce 100644 --- a/src/input/pvsPrivInputHandler.cpp +++ b/src/input/pvsPrivInputHandler.cpp @@ -21,7 +21,7 @@ #include #include #include "inputEvent.h" -#include "inputEventHandler.h" +#include "inputHandlerChains.h" #include "pvsPrivInputSocket.h" #include "pvsPrivInputHandler.h" @@ -63,6 +63,7 @@ PVSPrivInputHandler::PVSPrivInputHandler(int fd, QObject* parent) : _notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); _notifier->setEnabled(true); connect(_notifier, SIGNAL(activated(int)), this, SLOT(canRead())); + _handlerChain = makePrivilegedInputEventHandlerChain(); } PVSPrivInputHandler::~PVSPrivInputHandler() diff --git a/src/input/pvsPrivInputHandler.h b/src/input/pvsPrivInputHandler.h index 9980cdf..e82787b 100644 --- a/src/input/pvsPrivInputHandler.h +++ b/src/input/pvsPrivInputHandler.h @@ -20,7 +20,7 @@ #include #include #include -#include "inputHandlerChain.h" +#include "inputEventHandler.h" class QSocketNotifier; @@ -39,7 +39,7 @@ private: QByteArray _messageAssembly; int _bytes; int _fd; - privileged_handler_chain _handlerChain; + InputEventHandlerChain _handlerChain; }; #endif /* PVSPRIVINPUTHANDLER_H_ */ diff --git a/src/input/rebootSystemHandler.cpp b/src/input/rebootSystemHandler.cpp index b5b8f8a..6c5c63a 100644 --- a/src/input/rebootSystemHandler.cpp +++ b/src/input/rebootSystemHandler.cpp @@ -22,7 +22,7 @@ using namespace std; -void RebootLinuxSystemHandler::handle(InputEvent const& evt, InputEventContext const* ctx) +void RebootLinuxSystemHandler::doHandle(InputEvent const& evt, InputEventContext const* ctx) { // Rebooting a linux system is particulary easy: if(kill(1, SIGINT) < 0) diff --git a/src/input/rebootSystemHandler.h b/src/input/rebootSystemHandler.h index 34fa8ae..4920452 100644 --- a/src/input/rebootSystemHandler.h +++ b/src/input/rebootSystemHandler.h @@ -20,15 +20,11 @@ #include #include "inputEventHandler.h" -class RebootLinuxSystemHandler : public DefaultInputEventHandler +class RebootLinuxSystemHandler : public InputEventHandler< + input_policy::Require > { public: - void handle(InputEvent const&, InputEventContext const*); - - static void describeInto(QList& list) - { - list << SpecialInputEventDescription(tr(QT_TRANSLATE_NOOP("InputEventHandler", "Reboot")), InputEvent::ET_SPECIAL, InputEvent::EC_REBOOT); - } + void doHandle(InputEvent const&, InputEventContext const*); }; #endif /* REBOOTSYSTEMHANDLER_H_ */ diff --git a/src/input/sayHelloHandler.cpp b/src/input/sayHelloHandler.cpp index fc6f668..712963d 100644 --- a/src/input/sayHelloHandler.cpp +++ b/src/input/sayHelloHandler.cpp @@ -19,7 +19,7 @@ using namespace std; -void SayHelloHandler::handle(InputEvent const&, InputEventContext const* ctx) +void SayHelloHandler::doHandle(InputEvent const&, InputEventContext const* ctx) { cerr << "I'm right here! You sent this message from pid " << ctx->getSenderPid() << " as user " << ctx->getSenderUid() << " with gid " << ctx->getSenderGid() << endl; } diff --git a/src/input/sayHelloHandler.h b/src/input/sayHelloHandler.h index b0d4c7e..00463ca 100644 --- a/src/input/sayHelloHandler.h +++ b/src/input/sayHelloHandler.h @@ -20,15 +20,12 @@ #include #include "inputEventHandler.h" -class SayHelloHandler : public DefaultInputEventHandler +class SayHelloHandler : public InputEventHandler< + input_policy::Match, + input_policy::Security > { public: - void handle(InputEvent const&, InputEventContext const*); - - static void describeInto(QList& list) - { - list << SpecialInputEventDescription(tr(QT_TRANSLATE_NOOP("InputEventHandler", "Say Hello")), InputEvent::ET_SPECIAL, InputEvent::EC_SAY_HELLO); - } + void doHandle(InputEvent const&, InputEventContext const*); }; #endif /* SAYHELLOHANDLER_CPP_ */ diff --git a/src/input/unprivilegedInputHandlerChain.cpp b/src/input/unprivilegedInputHandlerChain.cpp new file mode 100644 index 0000000..fbbc770 --- /dev/null +++ b/src/input/unprivilegedInputHandlerChain.cpp @@ -0,0 +1,30 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # privilegedInputHandlerChain.cpp + # - Definition of the input handler chains - implementation for + # unprivileged chain + # -------------------------------------------------------------------------- + */ + +#include "x11FakeKeyboardHandler.h" +#include "x11FakeMouseHandler.h" +#include "privilegedHandlerForwarder.h" +#include "inputHandlerChains.h" + +InputEventHandlerChain makeUnprivilegedInputEventHandlerChain() +{ + return InputEventHandlerChain().add() + .add() + .add() + .add(); +} + diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index 0c32b66..eab4498 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -807,7 +807,7 @@ void X11FakeKeyboardHandler::initialize() current_modifiers = 0; } -void X11FakeKeyboardHandler::handle(InputEvent const& evt, InputEventContext const*) +void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext const*) { Display* dpy = X11InputUtils::display(); @@ -818,7 +818,7 @@ void X11FakeKeyboardHandler::handle(InputEvent const& evt, InputEventContext con switch(evt.qt_keysym()) { case Qt::Key_Backtab: - handle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab)); + doHandle(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)); diff --git a/src/input/x11FakeKeyboardHandler.h b/src/input/x11FakeKeyboardHandler.h index 3dde7cc..6c18dce 100644 --- a/src/input/x11FakeKeyboardHandler.h +++ b/src/input/x11FakeKeyboardHandler.h @@ -19,10 +19,14 @@ #include "inputEventHandler.h" -class X11FakeKeyboardHandler : public DefaultInputEventHandler +class X11FakeKeyboardHandler : public InputEventHandler< + input_policy::Match, + input_policy::Match, + input_policy::Require, + input_policy::Unprivileged> { public: - void handle(InputEvent const&, InputEventContext const* = 0); + void doHandle(InputEvent const&, InputEventContext const* = 0); void initialize(); }; diff --git a/src/input/x11FakeMouseHandler.cpp b/src/input/x11FakeMouseHandler.cpp index 58415d5..605fe2c 100644 --- a/src/input/x11FakeMouseHandler.cpp +++ b/src/input/x11FakeMouseHandler.cpp @@ -19,7 +19,7 @@ #include #include "x11InputUtils.h" -void X11FakeMouseButtonHandler::handle(InputEvent const& evt, InputEventContext const*) +void X11FakeMouseButtonHandler::doHandle(InputEvent const& evt, InputEventContext const*) { quint16 pressedButton = evt.pressedButton(); @@ -42,7 +42,7 @@ void X11FakeMouseButtonHandler::handle(InputEvent const& evt, InputEventContext XFlush(dpy); } -void X11FakeMouseMovementHandler::handle(InputEvent const& evt, InputEventContext const*) +void X11FakeMouseMovementHandler::doHandle(InputEvent const& evt, InputEventContext const*) { ConsoleLog writeLine(QString("Received mouse motion event (%1,%2)").arg(evt.xCoord()).arg(evt.yCoord())); Display* dpy = X11InputUtils::display(); diff --git a/src/input/x11FakeMouseHandler.h b/src/input/x11FakeMouseHandler.h index 0e32256..8ff8df4 100644 --- a/src/input/x11FakeMouseHandler.h +++ b/src/input/x11FakeMouseHandler.h @@ -19,16 +19,22 @@ #include "inputEventHandler.h" -class X11FakeMouseButtonHandler : public DefaultInputEventHandler +class X11FakeMouseButtonHandler : public InputEventHandler< + input_policy::Match, + input_policy::Require, + input_policy::Unprivileged> { public: - void handle(InputEvent const&, InputEventContext const* = 0); + void doHandle(InputEvent const&, InputEventContext const* = 0); }; -class X11FakeMouseMovementHandler : public DefaultInputEventHandler +class X11FakeMouseMovementHandler : public InputEventHandler< + input_policy::Match, + input_policy::Require, + input_policy::Unprivileged> { public: - void handle(InputEvent const&, InputEventContext const* = 0); + void doHandle(InputEvent const&, InputEventContext const* = 0); }; #endif /* X11FAKEMOUSEHANDLER_H_ */ diff --git a/src/pvs.cpp b/src/pvs.cpp index eda63f5..96a92ea 100755 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -20,7 +20,7 @@ #include "src/net/pvsServiceDiscovery.h" #include "src/net/pvsDiscoveredServer.h" #include "src/input/inputEvent.h" -#include "src/input/inputHandlerChain.h" +#include "src/input/inputHandlerChains.h" #include "src/input/x11InputUtils.h" #include "src/net/mcast/McastConfiguration.h" #include "src/net/pvsOutgoingMulticastTransfer.h" @@ -751,14 +751,15 @@ bool PVS::createMulticastTransfer(QString const& objectPath, quint64& transferID void PVS::handleInputEvent(InputEvent const& evt) { - std::string s = evt.toString(); - ConsoleLog writeLine(QString("Received input event: %1").arg(s.c_str())); + QString s = evt.toString(); + ConsoleLog writeLine(QString("Received input event: %1").arg(s.toLocal8Bit().constData())); _inputEventHandlers.handle(evt); } void PVS::initializeInputEventHandling() { X11InputUtils::setDisplay(X11Info::display()); + _inputEventHandlers = makeUnprivilegedInputEventHandlerChain(); _inputEventHandlers.initialize(); } diff --git a/src/pvs.h b/src/pvs.h index c18e9a3..902fbe7 100755 --- a/src/pvs.h +++ b/src/pvs.h @@ -26,7 +26,7 @@ #include "src/version.h" #include "src/util/consoleLogger.h" #include "src/util/clientGUIUtils.h" -#include "src/input/inputHandlerChain.h" +#include "src/input/inputEventHandler.h" class PVSServiceDiscovery; class PVSDiscoveredServer; @@ -168,7 +168,7 @@ private: int _timerLockDelay; // input event handling: - unprivileged_handler_chain _inputEventHandlers; + InputEventHandlerChain _inputEventHandlers; void handleInputEvent(InputEvent const& evt); void initializeInputEventHandling(); -- cgit v1.2.3-55-g7522 From 66f6a2f189a707e285a1cf24ef57c0587e3ecd51 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:44:13 +0200 Subject: It is not necessary to auto-generate policyChain_autogen.h anymore All it did is handled by implicit TypeList parameters. --- src/input/detail/Makefile.autogen | 5 +-- src/input/detail/gen/gen_policyChain.cpp | 68 -------------------------------- src/input/detail/policyChain_autogen.h | 8 ---- 3 files changed, 1 insertion(+), 80 deletions(-) delete mode 100644 src/input/detail/gen/gen_policyChain.cpp delete mode 100644 src/input/detail/policyChain_autogen.h diff --git a/src/input/detail/Makefile.autogen b/src/input/detail/Makefile.autogen index 6d0bfb3..cbd52be 100644 --- a/src/input/detail/Makefile.autogen +++ b/src/input/detail/Makefile.autogen @@ -1,8 +1,5 @@ -all : policyChain_autogen.h typeList_autogen.h +all : typeList_autogen.h .PHONY : all -policyChain_autogen.h : gen/gen_policyChain - gen/gen_policyChain > policyChain_autogen.h - typeList_autogen.h : gen/gen_typeList gen/gen_typeList > typeList_autogen.h diff --git a/src/input/detail/gen/gen_policyChain.cpp b/src/input/detail/gen/gen_policyChain.cpp deleted file mode 100644 index 3e375ec..0000000 --- a/src/input/detail/gen/gen_policyChain.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - # 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/ - # -------------------------------------------------------------------------- - # detail/gen/gen_policyChain.cpp: - # - generate the input_policy::detail::PolicyChain class - # -------------------------------------------------------------------------- - */ - -#include - -using namespace std; - -#define NUM_POLICIES 8 - -int main(int, char**) -{ - int i; - - cout << "template\nstruct PolicyChain :\npublic P0::template apply_ >\n"; - cout << "{};\n"; - - // Base case: - cout << "template\n"; - cout << "struct PolicyChain : public BaseCase {};\n"; - - // We need the following in macros: - cout << "#define _autogen_POLICY_TEMPLATE_PARAMS "; - for(i = 0; i < NUM_POLICIES; i++) - { - if(i) - cout << ", "; - cout << "typename P" << i; - } - - cout << "\n#define _autogen_POLICY_TEMPLATE_ARGS "; - for(i = 0; i < NUM_POLICIES; i++) - { - if(i) - cout << ", "; - cout << "P" << i; - } - cout << "\n"; - - return 0; -} diff --git a/src/input/detail/policyChain_autogen.h b/src/input/detail/policyChain_autogen.h deleted file mode 100644 index d9503b8..0000000 --- a/src/input/detail/policyChain_autogen.h +++ /dev/null @@ -1,8 +0,0 @@ -template -struct PolicyChain : -public P0::template apply_ > -{}; -template -struct PolicyChain : public BaseCase {}; -#define _autogen_POLICY_TEMPLATE_PARAMS typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7 -#define _autogen_POLICY_TEMPLATE_ARGS P0, P1, P2, P3, P4, P5, P6, P7 -- cgit v1.2.3-55-g7522 From 8ed8f90effab0876a8d8374d787d8c3b6214c531 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Fri, 8 Oct 2010 22:01:39 +0200 Subject: Move the translations for pvsinput into the library where they belong. --- i18n/pvsmgr_ar_JO.ts | 118 ---------------------------- i18n/pvsmgr_de_DE.ts | 118 ---------------------------- i18n/pvsmgr_es_MX.ts | 118 ---------------------------- i18n/pvsmgr_fr_FR.ts | 118 ---------------------------- i18n/pvsmgr_pl_PL.ts | 118 ---------------------------- src/input/CMakeLists.txt | 27 +++++++ src/input/i18n.h | 33 ++++++++ src/input/i18n/pvsinput_ar_JO.ts | 147 ++++++++++++++++++++++++++++++++++ src/input/i18n/pvsinput_de_DE.ts | 165 +++++++++++++++++++++++++++++++++++++++ src/input/i18n/pvsinput_es_MX.ts | 147 ++++++++++++++++++++++++++++++++++ src/input/i18n/pvsinput_fr_FR.ts | 147 ++++++++++++++++++++++++++++++++++ src/input/i18n/pvsinput_pl_PL.ts | 147 ++++++++++++++++++++++++++++++++++ src/input/inputEvent.cpp | 48 ++++++------ src/input/inputEvent.h | 7 ++ src/pvsmgr.cpp | 3 + src/pvsmgrtouch.cpp | 3 + 16 files changed, 850 insertions(+), 614 deletions(-) create mode 100644 src/input/i18n.h create mode 100644 src/input/i18n/pvsinput_ar_JO.ts create mode 100644 src/input/i18n/pvsinput_de_DE.ts create mode 100644 src/input/i18n/pvsinput_es_MX.ts create mode 100644 src/input/i18n/pvsinput_fr_FR.ts create mode 100644 src/input/i18n/pvsinput_pl_PL.ts diff --git a/i18n/pvsmgr_ar_JO.ts b/i18n/pvsmgr_ar_JO.ts index e4ee3cb..d434341 100644 --- a/i18n/pvsmgr_ar_JO.ts +++ b/i18n/pvsmgr_ar_JO.ts @@ -333,124 +333,6 @@ Perform an unprojection or remove remote help to get a target. - - InputEventHandler - - - Kill X Server - - - - - Reboot immediately - - - - - Crash system - - - - - Show all held logs - - - - - Send SIGTERM to all - - - - - Activate OOM killer - - - - - Send SIGKILL to all - - - - - Force thaw filesystems - - - - - Kill all on terminal - - - - - Show stack traces - - - - - Dump memory info - - - - - Make real-time tasks niceable - - - - - Power off immediately - - - - - Dump registers and flags - - - - - Dump timers and clockevents - - - - - Turn off raw keyboard mode - - - - - Sync all mounted filesystems - - - - - Dump task list - - - - - Remount all read-only - - - - - Dump uninterruptible tasks - - - - - Dump ftrace buffer - - - - - Reboot - - - - - Say Hello - - - MainWindow diff --git a/i18n/pvsmgr_de_DE.ts b/i18n/pvsmgr_de_DE.ts index 39e79cd..921b5ba 100644 --- a/i18n/pvsmgr_de_DE.ts +++ b/i18n/pvsmgr_de_DE.ts @@ -333,124 +333,6 @@ Perform an unprojection or remove remote help to get a target. - - InputEventHandler - - - Kill X Server - - - - - Reboot immediately - - - - - Crash system - - - - - Show all held logs - - - - - Send SIGTERM to all - - - - - Activate OOM killer - - - - - Send SIGKILL to all - - - - - Force thaw filesystems - - - - - Kill all on terminal - - - - - Show stack traces - - - - - Dump memory info - - - - - Make real-time tasks niceable - - - - - Power off immediately - - - - - Dump registers and flags - - - - - Dump timers and clockevents - - - - - Turn off raw keyboard mode - - - - - Sync all mounted filesystems - - - - - Dump task list - - - - - Remount all read-only - - - - - Dump uninterruptible tasks - - - - - Dump ftrace buffer - - - - - Reboot - - - - - Say Hello - - - MainWindow diff --git a/i18n/pvsmgr_es_MX.ts b/i18n/pvsmgr_es_MX.ts index 1470448..86a21b8 100644 --- a/i18n/pvsmgr_es_MX.ts +++ b/i18n/pvsmgr_es_MX.ts @@ -333,124 +333,6 @@ Perform an unprojection or remove remote help to get a target. - - InputEventHandler - - - Kill X Server - - - - - Reboot immediately - - - - - Crash system - - - - - Show all held logs - - - - - Send SIGTERM to all - - - - - Activate OOM killer - - - - - Send SIGKILL to all - - - - - Force thaw filesystems - - - - - Kill all on terminal - - - - - Show stack traces - - - - - Dump memory info - - - - - Make real-time tasks niceable - - - - - Power off immediately - - - - - Dump registers and flags - - - - - Dump timers and clockevents - - - - - Turn off raw keyboard mode - - - - - Sync all mounted filesystems - - - - - Dump task list - - - - - Remount all read-only - - - - - Dump uninterruptible tasks - - - - - Dump ftrace buffer - - - - - Reboot - - - - - Say Hello - - - MainWindow diff --git a/i18n/pvsmgr_fr_FR.ts b/i18n/pvsmgr_fr_FR.ts index e4ee3cb..d434341 100644 --- a/i18n/pvsmgr_fr_FR.ts +++ b/i18n/pvsmgr_fr_FR.ts @@ -333,124 +333,6 @@ Perform an unprojection or remove remote help to get a target. - - InputEventHandler - - - Kill X Server - - - - - Reboot immediately - - - - - Crash system - - - - - Show all held logs - - - - - Send SIGTERM to all - - - - - Activate OOM killer - - - - - Send SIGKILL to all - - - - - Force thaw filesystems - - - - - Kill all on terminal - - - - - Show stack traces - - - - - Dump memory info - - - - - Make real-time tasks niceable - - - - - Power off immediately - - - - - Dump registers and flags - - - - - Dump timers and clockevents - - - - - Turn off raw keyboard mode - - - - - Sync all mounted filesystems - - - - - Dump task list - - - - - Remount all read-only - - - - - Dump uninterruptible tasks - - - - - Dump ftrace buffer - - - - - Reboot - - - - - Say Hello - - - MainWindow diff --git a/i18n/pvsmgr_pl_PL.ts b/i18n/pvsmgr_pl_PL.ts index e4ee3cb..d434341 100644 --- a/i18n/pvsmgr_pl_PL.ts +++ b/i18n/pvsmgr_pl_PL.ts @@ -333,124 +333,6 @@ Perform an unprojection or remove remote help to get a target. - - InputEventHandler - - - Kill X Server - - - - - Reboot immediately - - - - - Crash system - - - - - Show all held logs - - - - - Send SIGTERM to all - - - - - Activate OOM killer - - - - - Send SIGKILL to all - - - - - Force thaw filesystems - - - - - Kill all on terminal - - - - - Show stack traces - - - - - Dump memory info - - - - - Make real-time tasks niceable - - - - - Power off immediately - - - - - Dump registers and flags - - - - - Dump timers and clockevents - - - - - Turn off raw keyboard mode - - - - - Sync all mounted filesystems - - - - - Dump task list - - - - - Remount all read-only - - - - - Dump uninterruptible tasks - - - - - Dump ftrace buffer - - - - - Reboot - - - - - Say Hello - - - MainWindow diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 689fd39..e14cdb4 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -110,8 +110,35 @@ if(UNIX) PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) endif() +set(pvsinput_TSS + i18n/pvsinput_de_DE.ts + i18n/pvsinput_fr_FR.ts + i18n/pvsinput_es_MX.ts + i18n/pvsinput_ar_JO.ts + i18n/pvsinput_pl_PL.ts) + +QT4_CREATE_TRANSLATION(pvsinput_QMS + ${pvsinput_SRCS} + ${pvsprivinputd_SRCS} + ${pvsinput_TSS}) + +# Generate an RCC file for our translations: +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/pvsinput.qrc" + "") +foreach(qm ${pvsinput_QMS}) + file(RELATIVE_PATH qm_rel ${CMAKE_CURRENT_BINARY_DIR} ${qm}) + get_filename_component(qm_basename ${qm} NAME) + file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pvsinput.qrc" + "${qm_rel}") +endforeach() +file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pvsinput.qrc" "") + +qt4_add_resources(pvsinput_RCS + "${CMAKE_CURRENT_BINARY_DIR}/pvsinput.qrc") + add_library( pvsinput STATIC ${pvsinput_SRCS} + ${pvsinput_RCS} ) diff --git a/src/input/i18n.h b/src/input/i18n.h new file mode 100644 index 0000000..d64c7cf --- /dev/null +++ b/src/input/i18n.h @@ -0,0 +1,33 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # i18n.h: + # - For library users: Make sure the translations are linked and registered + # -------------------------------------------------------------------------- + */ + +#ifndef I18N_H_ +#define I18N_H_ + +#include +#include +#include + +#define USE_PVSINPUT_TRANSLATIONS \ + do { \ + Q_INIT_RESOURCE(pvsinput); \ + QTranslator* translator = new QTranslator(QCoreApplication::instance()); \ + translator->load("pvsinput_" + QLocale::system().name(), ":/i18n/pvsinput"); \ + QCoreApplication::instance()->installTranslator(translator); \ + } while(false) + + +#endif /* I18N_H_ */ diff --git a/src/input/i18n/pvsinput_ar_JO.ts b/src/input/i18n/pvsinput_ar_JO.ts new file mode 100644 index 0000000..1040142 --- /dev/null +++ b/src/input/i18n/pvsinput_ar_JO.ts @@ -0,0 +1,147 @@ + + + + + InputEvent + + + Say Hello + + + + + Reboot + + + + + Kill X Server + + + + + Reboot immediately + + + + + Power off immediately + + + + + Crash System + + + + + Turn off raw keyboard mode + + + + + Send SIGTERM to all + + + + + Send SIGKILL to all + + + + + Kill all on this terminal + + + + + Activate OOM killer + + + + + Make real-time tasks niceable + + + + + Force-thaw filesystems + + + + + Sync all mounted filesystems + + + + + Remount all readonly + + + + + Show all held locks + + + + + Show stack traces + + + + + Dump memory info + + + + + Dump registers and flags + + + + + Dump timers and clockevents + + + + + Dump task list + + + + + Dump uninterruptible tasks + + + + + Dump ftrace buffer + + + + + QObject + + + Usage: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>] + +Options: + --help, -h Show this message + --daemon, -d Run in background + --log=<Logger>, + -l<Logger> Redirect all output to <Logger> + valid values are: + - any file name + - `syslog' to redirect output to the system log + - `null' to discard output (default) + (without quotes) + +Signals: + SIGINT, SIGTERM (or press Ctrl+C when run in foreground) + Quit + SIGHUP Reload configuration and cached user data + + + + + diff --git a/src/input/i18n/pvsinput_de_DE.ts b/src/input/i18n/pvsinput_de_DE.ts new file mode 100644 index 0000000..56ebf26 --- /dev/null +++ b/src/input/i18n/pvsinput_de_DE.ts @@ -0,0 +1,165 @@ + + + + + InputEvent + + + Say Hello + Hallo sagen + + + + Reboot + Neustart + + + + Kill X Server + X-Server töten + + + + Reboot immediately + Sofort neu starten + + + + Power off immediately + Sofort abschalten + + + + Crash System + Systemabsturz + + + + Turn off raw keyboard mode + RAW-Tastatur-Modus abschalten + + + + Send SIGTERM to all + SIGTERM an alle Prozesse senden + + + + Send SIGKILL to all + SIGKILL an alle Prozesse senden + + + + Kill all on this terminal + Alle Prozesse an diesem Terminal töten + + + + Activate OOM killer + OOM-Killer aktivieren + + + + Make real-time tasks niceable + Nice für Echtzeitprozesse ermöglichen + + + + Force-thaw filesystems + + + + + Sync all mounted filesystems + Alle eingebundenen Dateisysteme sync(2)en + + + + Remount all readonly + Alle Dateisysteme nur-lesbar mounten + + + + Show all held locks + Alle gehaltenen Sperren zeigen + + + + Show stack traces + Stacktraces anzigen + + + + Dump memory info + Speicherinfo anzeigen + + + + Dump registers and flags + Register und Flags anzeigen + + + + Dump timers and clockevents + Timer und Clockevents anzeigen + + + + Dump task list + Taskliste anzeigen + + + + Dump uninterruptible tasks + Ununterbrechbare Tasks anzeigen + + + + Dump ftrace buffer + ftrace-Puffer anzeigen + + + + QObject + + + Usage: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>] + +Options: + --help, -h Show this message + --daemon, -d Run in background + --log=<Logger>, + -l<Logger> Redirect all output to <Logger> + valid values are: + - any file name + - `syslog' to redirect output to the system log + - `null' to discard output (default) + (without quotes) + +Signals: + SIGINT, SIGTERM (or press Ctrl+C when run in foreground) + Quit + SIGHUP Reload configuration and cached user data + + Verwendung: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>] + +Optionen: + --help, -h Diese Nachricht anzeigen + --daemon, -d Im Hintergrund laufen + --log=<Logger>, + -l<Logger> Alle Ausgaben an <Logger> weiterleiten + Mögliche Werte für <Logger>: + - Ein Dateiname + - `syslog', um Ausgaben an das Systemlog zu leiten + - `null', um Ausgaben zu verwerfen + Standardwert: null + Werte ohne Anführungszeichen eingeben + +Signale: + SIGINT, SIGTERM (oder Strg+C wenn nicht im Hintergrund) + Beenden + SIGHUP Konfiguration und Benutzerdatenbank neu laden + + + + diff --git a/src/input/i18n/pvsinput_es_MX.ts b/src/input/i18n/pvsinput_es_MX.ts new file mode 100644 index 0000000..047c59c --- /dev/null +++ b/src/input/i18n/pvsinput_es_MX.ts @@ -0,0 +1,147 @@ + + + + + InputEvent + + + Say Hello + + + + + Reboot + + + + + Kill X Server + + + + + Reboot immediately + + + + + Power off immediately + + + + + Crash System + + + + + Turn off raw keyboard mode + + + + + Send SIGTERM to all + + + + + Send SIGKILL to all + + + + + Kill all on this terminal + + + + + Activate OOM killer + + + + + Make real-time tasks niceable + + + + + Force-thaw filesystems + + + + + Sync all mounted filesystems + + + + + Remount all readonly + + + + + Show all held locks + + + + + Show stack traces + + + + + Dump memory info + + + + + Dump registers and flags + + + + + Dump timers and clockevents + + + + + Dump task list + + + + + Dump uninterruptible tasks + + + + + Dump ftrace buffer + + + + + QObject + + + Usage: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>] + +Options: + --help, -h Show this message + --daemon, -d Run in background + --log=<Logger>, + -l<Logger> Redirect all output to <Logger> + valid values are: + - any file name + - `syslog' to redirect output to the system log + - `null' to discard output (default) + (without quotes) + +Signals: + SIGINT, SIGTERM (or press Ctrl+C when run in foreground) + Quit + SIGHUP Reload configuration and cached user data + + + + + diff --git a/src/input/i18n/pvsinput_fr_FR.ts b/src/input/i18n/pvsinput_fr_FR.ts new file mode 100644 index 0000000..8e3e417 --- /dev/null +++ b/src/input/i18n/pvsinput_fr_FR.ts @@ -0,0 +1,147 @@ + + + + + InputEvent + + + Say Hello + + + + + Reboot + + + + + Kill X Server + + + + + Reboot immediately + + + + + Power off immediately + + + + + Crash System + + + + + Turn off raw keyboard mode + + + + + Send SIGTERM to all + + + + + Send SIGKILL to all + + + + + Kill all on this terminal + + + + + Activate OOM killer + + + + + Make real-time tasks niceable + + + + + Force-thaw filesystems + + + + + Sync all mounted filesystems + + + + + Remount all readonly + + + + + Show all held locks + + + + + Show stack traces + + + + + Dump memory info + + + + + Dump registers and flags + + + + + Dump timers and clockevents + + + + + Dump task list + + + + + Dump uninterruptible tasks + + + + + Dump ftrace buffer + + + + + QObject + + + Usage: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>] + +Options: + --help, -h Show this message + --daemon, -d Run in background + --log=<Logger>, + -l<Logger> Redirect all output to <Logger> + valid values are: + - any file name + - `syslog' to redirect output to the system log + - `null' to discard output (default) + (without quotes) + +Signals: + SIGINT, SIGTERM (or press Ctrl+C when run in foreground) + Quit + SIGHUP Reload configuration and cached user data + + + + + diff --git a/src/input/i18n/pvsinput_pl_PL.ts b/src/input/i18n/pvsinput_pl_PL.ts new file mode 100644 index 0000000..87527d5 --- /dev/null +++ b/src/input/i18n/pvsinput_pl_PL.ts @@ -0,0 +1,147 @@ + + + + + InputEvent + + + Say Hello + + + + + Reboot + + + + + Kill X Server + + + + + Reboot immediately + + + + + Power off immediately + + + + + Crash System + + + + + Turn off raw keyboard mode + + + + + Send SIGTERM to all + + + + + Send SIGKILL to all + + + + + Kill all on this terminal + + + + + Activate OOM killer + + + + + Make real-time tasks niceable + + + + + Force-thaw filesystems + + + + + Sync all mounted filesystems + + + + + Remount all readonly + + + + + Show all held locks + + + + + Show stack traces + + + + + Dump memory info + + + + + Dump registers and flags + + + + + Dump timers and clockevents + + + + + Dump task list + + + + + Dump uninterruptible tasks + + + + + Dump ftrace buffer + + + + + QObject + + + Usage: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>] + +Options: + --help, -h Show this message + --daemon, -d Run in background + --log=<Logger>, + -l<Logger> Redirect all output to <Logger> + valid values are: + - any file name + - `syslog' to redirect output to the system log + - `null' to discard output (default) + (without quotes) + +Signals: + SIGINT, SIGTERM (or press Ctrl+C when run in foreground) + Quit + SIGHUP Reload configuration and cached user data + + + + + diff --git a/src/input/inputEvent.cpp b/src/input/inputEvent.cpp index f5abf43..fa623e1 100644 --- a/src/input/inputEvent.cpp +++ b/src/input/inputEvent.cpp @@ -99,33 +99,33 @@ InputEvent InputEvent::keyboardRelease(int key, int mods) } #define describe(list, description, type, code, value) \ - list.append(SpecialInputEventDescription(InputEvent::type, InputEvent::code, value, QCoreApplication::translate("InputEvent", description))) + list.append(SpecialInputEventDescription(InputEvent::type, InputEvent::code, value, description)) QList SpecialInputEventDescription::describeSpecialEvents() { QList list; - describe(list, "Say Hello", ET_SPECIAL, EC_SAY_HELLO, 0); - describe(list, "Reboot", ET_SPECIAL, EC_REBOOT, 0); - describe(list, "Kill X Server", ET_SPECIAL, EC_KILL_X, 0); - describe(list, "Reboot immediately", ET_SPECIAL, EC_SYSRQ, 'b'); - describe(list, "Power off immediately", ET_SPECIAL, EC_SYSRQ, 'o'); - describe(list, "Crash System", ET_SPECIAL, EC_SYSRQ, 'c'); - describe(list, "Turn off raw keyboard mode", ET_SPECIAL, EC_SYSRQ, 'r'); - describe(list, "Send SIGTERM to all", ET_SPECIAL, EC_SYSRQ, 'e'); - describe(list, "Send SIGKILL to all", ET_SPECIAL, EC_SYSRQ, 'i'); - describe(list, "Kill all on this terminal", ET_SPECIAL, EC_SYSRQ, 'k'); - describe(list, "Activate OOM killer", ET_SPECIAL, EC_SYSRQ, 'f'); - describe(list, "Make real-time tasks niceable", ET_SPECIAL, EC_SYSRQ, 'n'); - describe(list, "Force-thaw filesystems", ET_SPECIAL, EC_SYSRQ, 'j'); - describe(list, "Sync all mounted filesystems", ET_SPECIAL, EC_SYSRQ, 's'); - describe(list, "Remount all readonly", ET_SPECIAL, EC_SYSRQ, 'u'); - describe(list, "Show all held locks", ET_SPECIAL, EC_SYSRQ, 'd'); - describe(list, "Show stack traces", ET_SPECIAL, EC_SYSRQ, 'l'); - describe(list, "Dump memory info", ET_SPECIAL, EC_SYSRQ, 'm'); - describe(list, "Dump registers and flags", ET_SPECIAL, EC_SYSRQ, 'p'); - describe(list, "Dump timers and clockevents", ET_SPECIAL, EC_SYSRQ, 'q'); - describe(list, "Dump task list", ET_SPECIAL, EC_SYSRQ, 't'); - describe(list, "Dump uninterruptible tasks", ET_SPECIAL, EC_SYSRQ, 'w'); - describe(list, "Dump ftrace buffer", ET_SPECIAL, EC_SYSRQ, 'z'); + describe(list, InputEvent::tr("Say Hello"), ET_SPECIAL, EC_SAY_HELLO, 0); + describe(list, InputEvent::tr("Reboot"), ET_SPECIAL, EC_REBOOT, 0); + describe(list, InputEvent::tr("Kill X Server"), ET_SPECIAL, EC_KILL_X, 0); + describe(list, InputEvent::tr("Reboot immediately"), ET_SPECIAL, EC_SYSRQ, 'b'); + describe(list, InputEvent::tr("Power off immediately"), ET_SPECIAL, EC_SYSRQ, 'o'); + describe(list, InputEvent::tr("Crash System"), ET_SPECIAL, EC_SYSRQ, 'c'); + describe(list, InputEvent::tr("Turn off raw keyboard mode"), ET_SPECIAL, EC_SYSRQ, 'r'); + describe(list, InputEvent::tr("Send SIGTERM to all"), ET_SPECIAL, EC_SYSRQ, 'e'); + describe(list, InputEvent::tr("Send SIGKILL to all"), ET_SPECIAL, EC_SYSRQ, 'i'); + describe(list, InputEvent::tr("Kill all on this terminal"), ET_SPECIAL, EC_SYSRQ, 'k'); + describe(list, InputEvent::tr("Activate OOM killer"), ET_SPECIAL, EC_SYSRQ, 'f'); + describe(list, InputEvent::tr("Make real-time tasks niceable"), ET_SPECIAL, EC_SYSRQ, 'n'); + describe(list, InputEvent::tr("Force-thaw filesystems"), ET_SPECIAL, EC_SYSRQ, 'j'); + describe(list, InputEvent::tr("Sync all mounted filesystems"), ET_SPECIAL, EC_SYSRQ, 's'); + describe(list, InputEvent::tr("Remount all readonly"), ET_SPECIAL, EC_SYSRQ, 'u'); + describe(list, InputEvent::tr("Show all held locks"), ET_SPECIAL, EC_SYSRQ, 'd'); + describe(list, InputEvent::tr("Show stack traces"), ET_SPECIAL, EC_SYSRQ, 'l'); + describe(list, InputEvent::tr("Dump memory info"), ET_SPECIAL, EC_SYSRQ, 'm'); + describe(list, InputEvent::tr("Dump registers and flags"), ET_SPECIAL, EC_SYSRQ, 'p'); + describe(list, InputEvent::tr("Dump timers and clockevents"), ET_SPECIAL, EC_SYSRQ, 'q'); + describe(list, InputEvent::tr("Dump task list"), ET_SPECIAL, EC_SYSRQ, 't'); + describe(list, InputEvent::tr("Dump uninterruptible tasks"), ET_SPECIAL, EC_SYSRQ, 'w'); + describe(list, InputEvent::tr("Dump ftrace buffer"), ET_SPECIAL, EC_SYSRQ, 'z'); return list; } diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h index 2f557ce..82b059c 100644 --- a/src/input/inputEvent.h +++ b/src/input/inputEvent.h @@ -18,6 +18,7 @@ #define INPUTEVENT_H_ #include +#include // for translation #include #ifndef __linux @@ -211,6 +212,12 @@ public: { return value_ & MODIFIER_MASK; } + + // We want to enable InputEvent as a translation context, so we fake the tr method: + static QString tr(const char* string) + { + return QCoreApplication::translate("InputEvent", string); + } }; struct SpecialInputEventDescription diff --git a/src/pvsmgr.cpp b/src/pvsmgr.cpp index dd00c0e..f543c6d 100644 --- a/src/pvsmgr.cpp +++ b/src/pvsmgr.cpp @@ -19,6 +19,7 @@ #include "gui/mainWindow.h" #include "util/consoleLogger.h" #include "util/CertManager.h" +#include "src/input/i18n.h" QApplication *qtApp; @@ -35,6 +36,8 @@ int main(int argc, char** argv) translator.load(":pvsmgr"); qtApp->installTranslator(&translator); + USE_PVSINPUT_TRANSLATIONS; + ConsoleLog setLogName(QString("log.server")); ConsoleLog writeLine(QString("PVS-Server started.")); diff --git a/src/pvsmgrtouch.cpp b/src/pvsmgrtouch.cpp index d14ea56..4a1a97d 100644 --- a/src/pvsmgrtouch.cpp +++ b/src/pvsmgrtouch.cpp @@ -18,6 +18,7 @@ #include #include "util/consoleLogger.h" #include "util/CertManager.h" +#include "src/input/i18n.h" QApplication *qtApp; @@ -34,6 +35,8 @@ int main(int argc, char** argv) translator.load(":pvsmgr"); qtApp->installTranslator(&translator);*/ + USE_PVSINPUT_TRANSLATIONS; + ConsoleLog setLogName(QString("log.server")); ConsoleLog writeLine(QString("PVS-Server started.")); -- cgit v1.2.3-55-g7522 From a3885fdab7f8fd91b27237cb882f623dc046cbb9 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Fri, 8 Oct 2010 22:01:51 +0200 Subject: Actually install pvsprivinputd --- src/input/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index e14cdb4..b7a6511 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -108,6 +108,10 @@ if(UNIX) install(FILES pvsprivinputd.conf DESTINATION /etc PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + + # Install the daemon + install(TARGETS pvsprivinputd + DESTINATION sbin) endif() set(pvsinput_TSS -- cgit v1.2.3-55-g7522 From 1233d9c40fdf20b2c5157eee89d995817b0c1c3b Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:33:59 +0200 Subject: Code cleanup for X11FakeKeyboardHandler.cpp - CamelCase names - Add more comments - Remove unused stuff --- src/input/x11FakeKeyboardHandler.cpp | 409 ++++++++++++++++------------------- 1 file changed, 184 insertions(+), 225 deletions(-) diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index eab4498..a136e45 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -9,7 +9,7 @@ # # General information about OpenSLX can be found at http://openslx.org/ # -------------------------------------------------------------------------- - # x11FakeKeyboardHandler.h: + # x11FakeKeyboardHandler.cpp: # - Handle keyboard events on X11 - interface # -------------------------------------------------------------------------- */ @@ -36,10 +36,10 @@ #include #include "x11InputUtils.h" -//////////////////////// INPUT EVENT TRANSLATION ///////////////////////////////// - -typedef unsigned char xmodifier_type; +// X11 supports 8 modifiers, so a bitmask of modifiers fits into a byte: +typedef unsigned char XModifiers; +// For debugging output, these are the names of modifier keys: char modifiernames[][8] = { "SHIFT", "LOCK", @@ -51,7 +51,7 @@ char modifiernames[][8] = { "MOD5" }; -QString modifiers_to_string(xmodifier_type mods) +QString modifiersToString(XModifiers mods) { QString s; for(int i = 0; i < 8; i++) @@ -66,15 +66,22 @@ QString modifiers_to_string(xmodifier_type mods) return s; } +///////////////////////////////////////////////////////////////////////// +// Input event translation code +///////////////////////////////////////////////////////////////////////// + +// We need to translate between Qt's keycodes and X11's keycodes. +// Unfortunately, there does not seem to be a direct correspondence +// between them, so we are stuck with storing a lookup table: +typedef std::map KeycodeLookupTable; +KeycodeLookupTable keysyms; -typedef std::map 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() { +// The following code has been partially autogenerated by +// an insane sed(1) script and then hand-edited to make +// the errors go away. +void initializeKeycodeLookupTable() { 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; @@ -140,8 +147,6 @@ void initialize_keysyms() { 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; @@ -314,10 +319,8 @@ void initialize_keysyms() { 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; @@ -332,9 +335,6 @@ void initialize_keysyms() { 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; @@ -343,16 +343,11 @@ void initialize_keysyms() { 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; @@ -372,94 +367,33 @@ void initialize_keysyms() { 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]; +// every keysym with a value under 256 corresponds +// directly to an ISO-Latin1 Character. We need +// to store how to generate those characters: +int basicKeycodes[0x100]; // What key do we need to press? +int basicModifiers[0x100]; // What modifiers are required? -int xmodifier_from_qtmodifier(Qt::KeyboardModifier m) { - for(int i = 0; i < 8; i++) { - if(m == modifier_meaning[i]) - return i; - } - return -1; -} +// What keys do we need to press to generate the +// modifiers? +int modifierKeycodes[8]; +// How do the X11 modifiers relate to Qt's KeyboardModifiers? +Qt::KeyboardModifier modifierMeaning[8]; -typedef std::map qt_to_xmodifier_type; -typedef std::map x_to_qtmodifier_type; -qt_to_xmodifier_type qt_to_xmodifier; -x_to_qtmodifier_type x_to_qtmodifier; +// How do the X11 modifiers correspond to Qt's KeyboardModifiers? +typedef std::map XToQtModifierMap; +XToQtModifierMap XToQtModifier; -typedef std::multimap modifier_to_keycode_map; -modifier_to_keycode_map modifier_to_keycode; -typedef std::map keycode_to_modifier_map; -keycode_to_modifier_map keycode_to_modifier; +// And how do the modifiers relate to Keycodes? +typedef std::multimap ModifierToKeycodeMap; +ModifierToKeycodeMap ModifierToKeycode; +typedef std::map KeycodeToModifierMap; +KeycodeToModifierMap KeycodeToModifier; // We need to query the input devices, preferrable through XInput2, but // if that is not available we will contend ourselves with XInput1: @@ -491,56 +425,72 @@ keycode_to_modifier_map keycode_to_modifier; } #endif - -void initialize_basic_keycodes() +// Initialize the above data structures: +void initializeBasicKeycodes() { + // Mark everything as unknown initially for(int i = 0; i < 8; i++) { - modifier_keycodes[i] = -1; + modifierKeycodes[i] = -1; } for(int i = 0; i < 0x100; i++) { - basic_keycodes[i] = -1; + basicKeycodes[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); + + // Find out the valid range of keycodes + int minKeycode, maxKeycode; + XDisplayKeycodes(dpy, &minKeycode, &maxKeycode); + + // Initialize the XKB client-side code, and find out whether + // the XKB extension is present in the server. + int xkbOpcode, xkbEvent, xkbError, xkbMajor, xkbMinor; + bool xkbPresent = XkbQueryExtension(dpy, &xkbOpcode, &xkbEvent, &xkbError, &xkbMajor, &xkbMinor); + + if(!xkbPresent) { + // No XKB. This is probably not a very recent + // system, but we will do the best we can. + // Retrieve the keyboard mapping + int keysymsPerCode; + const int count = maxKeycode - minKeycode + 1; + KeySym* mapping = XGetKeyboardMapping(dpy, minKeycode, count, &keysymsPerCode); + + // and traverse every entry for(int i = 0; i < count; i++) { - for(int j = 0; j < keysyms_per_code; j++) + for(int j = 0; j < keysymsPerCode; j++) { - const int idx = i * keysyms_per_code + j; + const int idx = i * keysymsPerCode + j; const KeySym ks = mapping[idx]; - const int keycode = min_keycode + i; + const int keycode = minKeycode + i; + // to find out if there is a Latin1 character there, 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) + // that we have not yet found, + if(basicKeycodes[ks] != -1) continue; // already found - basic_keycodes[ks] = keycode; - basic_modifiers[ks] = j; + // and record its keycode and needed modifiers. + basicKeycodes[ks] = keycode; + basicModifiers[ks] = j; } } } + + // We are finished, free the mapping structure. XFree(mapping); } else { - // Try to find out what device XTest will send events on: + // XKB is present. + + // As different input devices can have different keymaps, + // we need to find out what device XTest will send events on: unsigned int xkbDeviceId = XkbUseCoreKbd; Atom xtestDeviceProp = XInternAtom(dpy, "XTEST Device", false); + + // Find the list of input devices: int ndevinfos; XIDeviceInfo* devinfos = XIQueryDevice(dpy, XIAllDevices, &ndevinfos); if(devinfos) @@ -578,6 +528,9 @@ void initialize_basic_keycodes() # undef deviceid #endif } + // at this point, xkbDeviceId contains the identifier + // of the XTEST Device, or xkbUseCoreKbd if none was + // found. // Okay, we know which device to query. Now get its keymap: XkbDescPtr keybDesc = XkbGetKeyboard(dpy, XkbAllComponentsMask, xkbDeviceId); @@ -586,7 +539,9 @@ void initialize_basic_keycodes() qWarning("Unable to retrieve keyboard description for device %d. Falling back to unreliable global mapping", xkbDeviceId); } - for(int i = min_keycode; i <= max_keycode; i++) + // This is basically the same loop as above, it just queries XKB + // instead of the old core Xlib routines. + for(int i = minKeycode; i <= maxKeycode; i++) { for(int j = 0; j <= 0xff; j++) { @@ -605,17 +560,11 @@ void initialize_basic_keycodes() 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) + if(basicKeycodes[ks] != -1) continue; - basic_keycodes[ks] = i; - basic_modifiers[ks] = unconsumed & j; + basicKeycodes[ks] = i; + basicModifiers[ks] = unconsumed & j; } } } @@ -631,56 +580,57 @@ void initialize_basic_keycodes() 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); + const int shiftCode = XKeysymToKeycode(dpy, XK_Shift_L); + const int controlCode = XKeysymToKeycode(dpy, XK_Control_L); + const int altCode = XKeysymToKeycode(dpy, XK_Alt_L); + const int metaCode = XKeysymToKeycode(dpy, XK_Meta_L); + const int switchCode = XKeysymToKeycode(dpy, XK_Mode_switch); + // and use this information to find out which + // X11 modifiers correspond to Qt's modifiers: 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< int_set_type; -int_set_type pressed_modifier_keys; -xmodifier_type current_modifiers; +// We need to keep track of which modifiers +// are currently active +typedef std::set IntSet; +IntSet pressedModifierKeys; +XModifiers currentModifiers; void trackModifiers(int keycode, bool down) { // is this a modifier key? - const bool is_modifier = keycode_to_modifier.find(keycode) != keycode_to_modifier.end(); + const bool isModifier = KeycodeToModifier.find(keycode) != KeycodeToModifier.end(); - if(!is_modifier) + if(!isModifier) { return; } if(down) { - pressed_modifier_keys.insert(keycode); + pressedModifierKeys.insert(keycode); } else { - pressed_modifier_keys.erase(keycode); + pressedModifierKeys.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++) + IntSet::iterator i, end = pressedModifierKeys.end(); + XModifiers modifs = 0; + for(i = pressedModifierKeys.begin(); i != end; i++) { - keycode_to_modifier_map::iterator found_kc = keycode_to_modifier.find(*i); - if(found_kc != keycode_to_modifier.end()) + KeycodeToModifierMap::iterator foundCode = KeycodeToModifier.find(*i); + if(foundCode != KeycodeToModifier.end()) { - modifs |= (*found_kc).second; + modifs |= (*foundCode).second; } } - current_modifiers = modifs; + currentModifiers = modifs; - ConsoleLog writeLine(QString("[trackModifiers] current modifiers: %1").arg(modifiers_to_string(modifs))); + ConsoleLog writeLine(QString("[trackModifiers] current modifiers: %1").arg(modifiersToString(modifs))); } -typedef std::pair modifier_tweak_type; -typedef std::vector tweak_sequence_type; +// And, if we need to tweak the modifiers to generate +// a particular keysym, we need to keep track of which +// ones we pressed or released. +typedef std::pair ModifierTweak; +typedef std::vector TweakSequence; -void tweakModifiers(Display* dpy, xmodifier_type neededState, xmodifier_type actualState, tweak_sequence_type& tracker) +// Tweak the modifiers to reach the neededState, from actualState +// and record tweaks in the tracker. +void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState, TweakSequence& tracker) { - ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiers_to_string(neededState)).arg(modifiers_to_string(actualState))); + ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiersToString(neededState)).arg(modifiersToString(actualState))); for(int j = 0; j < 8; j++) { - xmodifier_type i = 1<second == i) { + KeycodeToModifierMap::iterator modmapIter = KeycodeToModifier.find(*iter); + if(modmapIter != KeycodeToModifier.end()) { + if(modmapIter->second == i) { kc = *iter; // release this key: @@ -790,29 +746,33 @@ void tweakModifiers(Display* dpy, xmodifier_type neededState, xmodifier_type act } } -void untweakModifiers(Display* dpy, tweak_sequence_type& tracker) +// Undo a recorded sequence of modifier tweaks +void untweakModifiers(Display* dpy, TweakSequence& tracker) { - tweak_sequence_type::iterator i, end = tracker.end(); + TweakSequence::iterator i, end = tracker.end(); for(i = tracker.begin(); i != end; i++) { - modifier_tweak_type& t = *i; + ModifierTweak& t = *i; XTestFakeKeyEvent(dpy, t.first, !t.second, CurrentTime); } } +// initialize the handler void X11FakeKeyboardHandler::initialize() { - initialize_keysyms(); - initialize_basic_keycodes(); - pressed_modifier_keys.clear(); - current_modifiers = 0; + initializeKeycodeLookupTable(); + initializeBasicKeycodes(); + pressedModifierKeys.clear(); + currentModifiers = 0; } +// actually try our best to generate the correct input sequence +// for the event void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext const*) { Display* dpy = X11InputUtils::display(); // find out which keysym caused this event: - lookup_table_const_iterator i = keysyms.find(evt.qt_keysym()); + KeycodeLookupTable::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()) @@ -829,44 +789,43 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c // is it a "normal" key? if(ks >= ' ' && ks < 0x100) { - if(basic_keycodes[ks] != -1) + if(basicKeycodes[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))); + KeySym unmodSym = XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers); + ConsoleLog writeLine(QString("Pressing the key for %1 would yield %2 right now.").arg(XKeysymToString(ks)).arg(XKeysymToString(unmodSym))); - if(ks == XKeycodeToKeysym(dpy, basic_keycodes[ks], current_modifiers)) + if(ks == XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers)) { - XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime); + XTestFakeKeyEvent(dpy, basicKeycodes[ks], 1, CurrentTime); } else { // what modifier keys do we need to press? - xmodifier_type mods = translate_modifiers(evt.qt_modifiers()); + XModifiers mods = translateModifiers(evt.qt_modifiers()); // we may need to press additional modifiers to generate this keysym: if(QChar(ks, 0).isLetter()) { - // 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<>(QDataStream& istrm, InputEvent& evt) { - istrm >> evt.type_ >> evt.code_ >> evt.value_; + istrm >> evt._type >> evt._code >> evt._value; return istrm; } diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h index 82b059c..73b7129 100644 --- a/src/input/inputEvent.h +++ b/src/input/inputEvent.h @@ -39,19 +39,19 @@ private: 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_; + quint16 _type; + quint16 _code; + quint32 _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 = 0) : type_(type), code_(code), value_(value) + InputEvent(quint16 type, quint16 code, quint32 value = 0) : _type(type), _code(code), _value(value) { } - InputEvent(InputEvent const& other) : type_(other.type_), code_(other.code_), value_(other.value_) + InputEvent(InputEvent const& other) : _type(other._type), _code(other._code), _value(other._value) { } @@ -59,110 +59,110 @@ public: { } - static InputEvent mouseMotion(uint16_t x, uint16_t y) + static InputEvent mouseMotion(quint16 x, quint16 y) { - return InputEvent(ET_POINTER, 0, ((uint32_t)x << 16) | y); + return InputEvent(ET_POINTER, 0, ((quint32)x << 16) | y); } - static uint16_t mouseButtonsFromQt(int b); + static quint16 mouseButtonsFromQt(int b); static InputEvent mousePressRelease(int button, int buttons); static InputEvent keyboardPress(int key, int mods); static InputEvent keyboardRelease(int key, int mods); - 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 quint16 ET_KEY = 0; + static const quint16 ET_BUTTON = 1; + static const quint16 ET_POINTER = 2; + static const quint16 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; - static const uint16_t EC_SAY_HELLO = 5; //< for debugging purposes + static const quint16 EC_PRESS = 0; + static const quint16 EC_RELEASE = 1; + static const quint16 EC_REBOOT = 2; + static const quint16 EC_SYSRQ = 3; + static const quint16 EC_KILL_X = 4; + static const quint16 EC_SAY_HELLO = 5; //< for debugging purposes - typedef uint32_t event_key; + typedef quint32 event_key; - typedef uint32_t event_key_modifiers; + typedef quint32 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 quint16 EB_LEFT = 1; + static const quint16 EB_MIDDLE = 2; + static const quint16 EB_RIGHT = 4; - static const uint32_t MODIFIER_MASK = + static const quint32 MODIFIER_MASK = 0x7e000000; - uint16_t type() const + quint16 type() const { - return type_; + return _type; } - uint16_t code() const + quint16 code() const { - return code_; + return _code; } - uint32_t value() const + quint32 value() const { - return value_; + return _value; } bool isKeyboard() const { - return type_ == ET_KEY; + return _type == ET_KEY; } bool isButton() const { - return type_ == ET_BUTTON; + return _type == ET_BUTTON; } bool isPointer() const { - return type_ == ET_POINTER; + return _type == ET_POINTER; } bool isSpecial() const { - return type_ == ET_SPECIAL; + return _type == ET_SPECIAL; } bool isPress() const { - return code_ == EC_PRESS; + return _code == EC_PRESS; } bool isRelease() const { - return code_ == EC_RELEASE; + return _code == EC_RELEASE; } - uint16_t pressedButton() const + quint16 pressedButton() const { - assert(type_ == ET_BUTTON); - return (value_ >> 16); + assert(_type == ET_BUTTON); + return (_value >> 16); } - uint16_t heldButtons() const + quint16 heldButtons() const { - assert(type_ == ET_BUTTON); - return (value_ & 0xffff); + assert(_type == ET_BUTTON); + return (_value & 0xffff); } - uint16_t xCoord() const + quint16 xCoord() const { - assert(type_ == ET_POINTER); - return (value_ >> 16); + assert(_type == ET_POINTER); + return (_value >> 16); } - uint16_t yCoord() const + quint16 yCoord() const { - assert(type_ == ET_POINTER); - return (value_ & 0xffff); + assert(_type == ET_POINTER); + return (_value & 0xffff); } - static QString typeToString(uint16_t type) + static QString typeToString(quint16 type) { switch(type) { @@ -179,7 +179,7 @@ public: } } - static QString codeToString(uint16_t code) + static QString codeToString(quint16 code) { switch(code) { @@ -200,17 +200,17 @@ public: QString toString() const { - return QString("%1:%2:%3").arg(typeToString(type_)).arg(codeToString(code_)).arg(value_, 16); + return QString("%1:%2:%3").arg(typeToString(_type)).arg(codeToString(_code)).arg(_value, 16); } - uint32_t qt_keysym() const + quint32 qtKeysym() const { - return value_ & ~MODIFIER_MASK; + return _value & ~MODIFIER_MASK; } - uint32_t qt_modifiers() const + quint32 qtModifiers() const { - return value_ & MODIFIER_MASK; + return _value & MODIFIER_MASK; } // We want to enable InputEvent as a translation context, so we fake the tr method: @@ -222,14 +222,14 @@ public: struct SpecialInputEventDescription { - SpecialInputEventDescription(uint16_t type, uint16_t code, uint32_t value, QString const& description_) + SpecialInputEventDescription(quint16 type, quint16 code, quint32 value, QString const& description_) : type(type), code(code), value(value), description(description_) { } - uint16_t type; - uint16_t code; - uint32_t value; + quint16 type; + quint16 code; + quint32 value; QString description; InputEvent toEvent() const diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 5b03a90..71a530b 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -176,7 +176,7 @@ struct InputEventHandlerPolicyBase // The actual handler class need to provide doHandle and can override // allow and isApplicable. ///////////////////////////////////////////////////////////////////////// -/* interface */ class InputEventHandlerBase +class InputEventHandlerBase { public: enum HandlerStatus @@ -246,9 +246,15 @@ private: // Unfortunately, we cannot specialize member functions of a template. // So, we need to make this a class with a static non-template member. ///////////////////////////////////////////////////////////////////////// - template + template struct ConditionallyAppend { + ///////////////////////////////////////////////////////////////////////// + // This method will never be instantiated for handlers that are + // not Compatible, thus generating no reference to HandlerType + // and permitting compilation to proceed without + // tedious nested preprocessor conditionals. + ///////////////////////////////////////////////////////////////////////// static void doIt(InputEventHandlerChain* chain) { chain->handlers.append(new HandlerType); diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index a136e45..4e3449a 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -772,16 +772,16 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c Display* dpy = X11InputUtils::display(); // find out which keysym caused this event: - KeycodeLookupTable::const_iterator i = keysyms.find(evt.qt_keysym()); + KeycodeLookupTable::const_iterator i = keysyms.find(evt.qtKeysym()); 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()) + switch(evt.qtKeysym()) { case Qt::Key_Backtab: - doHandle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab)); + doHandle(InputEvent(evt.type(), evt.code(), evt.qtModifiers() | Qt::ShiftModifier | Qt::Key_Tab)); break; default: - ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qt_keysym(), 8, 16)); + ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qtKeysym(), 8, 16)); } } else { KeySym ks = (*i).second; @@ -805,7 +805,7 @@ void X11FakeKeyboardHandler::doHandle(InputEvent const& evt, InputEventContext c else { // what modifier keys do we need to press? - XModifiers mods = translateModifiers(evt.qt_modifiers()); + XModifiers mods = translateModifiers(evt.qtModifiers()); // we may need to press additional modifiers to generate this keysym: if(QChar(ks, 0).isLetter()) -- cgit v1.2.3-55-g7522 From 18f16ac568d0c699fe24271c5b77f573b749092e Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:40:33 +0200 Subject: Lose the `get' method prefix on InputEventContext since it does not fit in --- src/input/inputEventHandler.h | 6 +++--- src/input/killX11Handler.cpp | 2 +- src/input/pvsCheckPrivileges.h | 6 +++--- src/input/pvsPrivInputHandler.cpp | 6 +++--- src/input/sayHelloHandler.cpp | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 71a530b..735b75c 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -33,9 +33,9 @@ struct InputEventContext hasBeenDenied = false; } - virtual pid_t getSenderPid() const = 0; - virtual uid_t getSenderUid() const = 0; - virtual gid_t getSenderGid() const = 0; + virtual pid_t senderPid() const = 0; + virtual uid_t senderUid() const = 0; + virtual gid_t senderGid() const = 0; mutable bool hasBeenDenied; }; diff --git a/src/input/killX11Handler.cpp b/src/input/killX11Handler.cpp index 572656e..32e5873 100644 --- a/src/input/killX11Handler.cpp +++ b/src/input/killX11Handler.cpp @@ -33,7 +33,7 @@ void KillX11Handler::doHandle(InputEvent const&, InputEventContext const* ctx) if(displayDevice.isNull()) { - qWarning("Can not kill X server for %d,%d,%d: No Display Device", ctx->getSenderPid(), ctx->getSenderUid(), ctx->getSenderGid()); + qWarning("Can not kill X server for %d,%d,%d: No Display Device", ctx->senderPid(), ctx->senderUid(), ctx->senderGid()); return; } diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h index 62b463c..92c68fe 100644 --- a/src/input/pvsCheckPrivileges.h +++ b/src/input/pvsCheckPrivileges.h @@ -32,9 +32,9 @@ struct CachedInputContext { if(source) { - pid = source->getSenderPid(); - uid = source->getSenderUid(); - gid = source->getSenderGid(); + pid = source->senderPid(); + uid = source->senderUid(); + gid = source->senderGid(); } else { diff --git a/src/input/pvsPrivInputHandler.cpp b/src/input/pvsPrivInputHandler.cpp index bfa60ce..84ccbae 100644 --- a/src/input/pvsPrivInputHandler.cpp +++ b/src/input/pvsPrivInputHandler.cpp @@ -35,17 +35,17 @@ public: { } - pid_t getSenderPid() const + pid_t senderPid() const { return _pid; } - uid_t getSenderUid() const + uid_t senderUid() const { return _uid; } - gid_t getSenderGid() const + gid_t senderGid() const { return _gid; } diff --git a/src/input/sayHelloHandler.cpp b/src/input/sayHelloHandler.cpp index 712963d..301709f 100644 --- a/src/input/sayHelloHandler.cpp +++ b/src/input/sayHelloHandler.cpp @@ -21,5 +21,5 @@ using namespace std; void SayHelloHandler::doHandle(InputEvent const&, InputEventContext const* ctx) { - cerr << "I'm right here! You sent this message from pid " << ctx->getSenderPid() << " as user " << ctx->getSenderUid() << " with gid " << ctx->getSenderGid() << endl; + cerr << "I'm right here! You sent this message from pid " << ctx->senderPid() << " as user " << ctx->senderUid() << " with gid " << ctx->senderGid() << endl; } -- cgit v1.2.3-55-g7522 From bdec8a3b34650603b111261cfed0364acf6656b7 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:41:25 +0200 Subject: Fix wrong policy: KillX11Handler only works on Linux, due to dependency on the /proc file system's layout. --- src/input/killX11Handler.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/input/killX11Handler.h b/src/input/killX11Handler.h index 8c0d655..77d9fdb 100644 --- a/src/input/killX11Handler.h +++ b/src/input/killX11Handler.h @@ -22,10 +22,7 @@ class KillX11Handler : public InputEventHandler< input_policy::Match, - input_policy::Require > > + input_policy::Require > { public: void doHandle(InputEvent const&, InputEventContext const*); -- cgit v1.2.3-55-g7522 From 2d31480bf052e3176edfbdc914ff5a29d54dc46c Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:41:48 +0200 Subject: Introduce an implicit logical AND into Require policy --- src/input/inputEventHandler.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 735b75c..46e688c 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -92,12 +92,12 @@ typedef Security Unprivileged; // as porting efforts are already underway, we include the necessary // machinery anyway. ///////////////////////////////////////////////////////////////////////// -template +template BEGIN_POLICY_CLASS(Require) { static const bool areSystemRequirementsFulfilled = - NextPolicy::areSystemRequirementsFulfilled && - detail::Matches::value; + NextPolicy::areSystemRequirementsFulfilled || + detail::Matches, detail::SystemTraits>::value; } END_POLICY_CLASS -- cgit v1.2.3-55-g7522 From e659552d9b4c3889522d018e76c00adbe507d045 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:42:18 +0200 Subject: Add some comments to inputEventHandler.h --- src/input/inputEventHandler.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 46e688c..3879b80 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -26,6 +26,11 @@ #include "detail/policyChain.h" #include "detail/systemTraits.h" +///////////////////////////////////////////////////////////////////////// +// InputEventContext: +// For handling access control, this specifies who sent the input event. +// This only makes sense in the privileged input handler chain. +///////////////////////////////////////////////////////////////////////// struct InputEventContext { InputEventContext() @@ -37,6 +42,7 @@ struct InputEventContext virtual uid_t senderUid() const = 0; virtual gid_t senderGid() const = 0; + // Support the generation of meaningful log messages: mutable bool hasBeenDenied; }; @@ -203,6 +209,7 @@ template class InputEventHandler : public InputEventHandlerBase { protected: + // instantiate our policy: typedef USE_POLICY(input_policy::detail::InputEventHandlerPolicyBase) policy_type; policy_type policy; -- cgit v1.2.3-55-g7522 From b4a5c00cd583458a83577e3f0148d33ccaae2794 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 01:42:51 +0200 Subject: Remove input headers from PVSMGR_SRCS in CMakeLists.txt as they do not contribute translatable strings anymore --- CMakeLists.txt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc695ce..4214fd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,13 +103,6 @@ SET( PVSMGR_SRCS src/util/serviceDiscoveryUtil.cpp src/gui/aboutDialog.cpp src/gui/multicastConfigDialog.cpp - - # We need the following headers for translations. - # They will not be compiled. - src/input/killX11Handler.h - src/input/rebootSystemHandler.h - src/input/sayHelloHandler.h - src/input/magicSysRqHandler.h ) # pvs -- cgit v1.2.3-55-g7522 From f6d1c5346fc3b950fe31f7f6f920699e9835cb62 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 14:31:25 +0200 Subject: Fix bug in logical OR when chaining Require<...> Policy. --- src/input/inputEventHandler.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 3879b80..11e2f4e 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -102,8 +102,10 @@ template BEGIN_POLICY_CLASS(Require) { static const bool areSystemRequirementsFulfilled = - NextPolicy::areSystemRequirementsFulfilled || - detail::Matches, detail::SystemTraits>::value; + (NextPolicy::areSystemRequirementsFulfilled + && !NextPolicy::areSystemRequirementsVacuouslyFulfilled) + || detail::Matches, detail::SystemTraits>::value; + static const bool areSystemRequirementsVacuouslyFulfilled = false; } END_POLICY_CLASS @@ -158,6 +160,9 @@ struct InputEventHandlerPolicyBase // everywhere static const bool areSystemRequirementsFulfilled = true; + // We need this to implement proper logical OR + static const bool areSystemRequirementsVacuouslyFulfilled = true; + // Generate an error when no match policy is given. bool isApplicable(InputEvent const&) { -- cgit v1.2.3-55-g7522 From c8978b46070959273d8ee8d760b2594c18a237a9 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 14:31:49 +0200 Subject: Add an InputEventHandler that is not compatible anywhere. --- src/input/incompatibleHandler.h | 37 +++++++++++++++++++++++++++++ src/input/unprivilegedInputHandlerChain.cpp | 4 +++- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/input/incompatibleHandler.h diff --git a/src/input/incompatibleHandler.h b/src/input/incompatibleHandler.h new file mode 100644 index 0000000..5a92806 --- /dev/null +++ b/src/input/incompatibleHandler.h @@ -0,0 +1,37 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # incompatibleHandler.h: + # - A handler that is not compatible with any system. + # The presence of this file does no harm whatsoever, + # since there will never be any references generated to the class + # it defines, and allows us to test the claim that + # the Require<...> policy does a better job than the preprocessor. + # -------------------------------------------------------------------------- + */ + +#ifndef INCOMPATIBLEHANDLERTYPE_H_ +#define INCOMPATIBLEHANDLERTYPE_H_ + +#include "inputEventHandler.h" + +namespace incompatible { + struct Incompatible; +} + +class IncompatibleHandler : public InputEventHandler< + input_policy::Require > +{ + void doHandle(InputEvent const&, InputEventContext const*); +}; + + +#endif /* INCOMPATIBLEHANDLERTYPE_H_ */ diff --git a/src/input/unprivilegedInputHandlerChain.cpp b/src/input/unprivilegedInputHandlerChain.cpp index fbbc770..9353321 100644 --- a/src/input/unprivilegedInputHandlerChain.cpp +++ b/src/input/unprivilegedInputHandlerChain.cpp @@ -18,6 +18,7 @@ #include "x11FakeKeyboardHandler.h" #include "x11FakeMouseHandler.h" #include "privilegedHandlerForwarder.h" +#include "incompatibleHandler.h" #include "inputHandlerChains.h" InputEventHandlerChain makeUnprivilegedInputEventHandlerChain() @@ -25,6 +26,7 @@ InputEventHandlerChain makeUnprivilegedInputEventHandlerChain() return InputEventHandlerChain().add() .add() .add() - .add(); + .add() + .add(); // See comments in incompatibleHandler.h } -- cgit v1.2.3-55-g7522 From d76a4ddc26ab17277ae4b5018dfc2aa05b623c73 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 14:32:46 +0200 Subject: Remove leftover code that serves no purpose --- src/input/detail/policyChain.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/input/detail/policyChain.h b/src/input/detail/policyChain.h index ae01ff2..efaf371 100644 --- a/src/input/detail/policyChain.h +++ b/src/input/detail/policyChain.h @@ -33,10 +33,6 @@ struct PolicyChain : public PolicyList::head::template apply_ struct PolicyChain : public BaseCase { -private: - struct This_Should_Not_Work; -public: - static const int test_value = sizeof(This_Should_Not_Work); }; } -- cgit v1.2.3-55-g7522 From 2e072d898609ef8dfb5270a07e3212498648d048 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 17:08:49 +0200 Subject: Code cleanup and simplification for X11FakeKeyboardHandler --- src/input/CMakeLists.txt | 32 +- src/input/x11FakeKeyboardHandler.cpp | 655 ++++++++++++++++++----------------- 2 files changed, 358 insertions(+), 329 deletions(-) diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index b7a6511..d950c67 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -5,16 +5,28 @@ set(pvsinput_SRCS unprivilegedInputHandlerChain.cpp inputEventHandler.cpp ) + +set(feature_DEFS) if(UNIX) find_file(XINPUT2_HDR X11/extensions/XInput2.h) if(XINPUT2_HDR) - set_property(SOURCE x11FakeKeyboardHandler.cpp - APPEND - PROPERTY COMPILE_DEFINITIONS HAVE_XINPUT2_H - ) + list(APPEND feature_DEFS + HAVE_XINPUT2_H) endif() - + + find_file(XINPUT_HDR X11/extensions/XInput.h) + if(XINPUT_HDR) + list(APPEND feature_DEFS + HAVE_XINPUT_H) + endif() + + find_file(XKBLIB_HDR X11/XKBlib.h) + if(XKBLIB_HDR) + list(APPEND feature_DEFS + HAVE_XKBLIB_H) + endif() + set(pvsprivinputd_SRCS pvsprivinputd.cpp pvsPrivInputHandler.cpp @@ -114,6 +126,11 @@ if(UNIX) DESTINATION sbin) endif() +set_property(SOURCE ${pvsinput_SRCS} ${pvsprivinputd_SRCS} + APPEND + PROPERTY COMPILE_DEFINITIONS ${feature_DEFS} +) + set(pvsinput_TSS i18n/pvsinput_de_DE.ts i18n/pvsinput_fr_FR.ts @@ -146,3 +163,8 @@ add_library( ${pvsinput_SRCS} ${pvsinput_RCS} ) + +add_library( + pvsinputtests + STATIC + templateMagicTests.cpp) diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index 4e3449a..fed087e 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -51,6 +51,44 @@ char modifiernames[][8] = { "MOD5" }; +// We generally want to find a key sequence with as few modifiers as +// possible. These are all modifier combinations sorted by number of +// bits set: +char modifierpriority[256] = { + 0, 1, 2, 4, 8, 16, 32, 64, 128, + 3, 5, 6, 9, 10, 12, 17, 18, + 20, 24, 33, 34, 36, 40, 48, 65, + 66, 68, 72, 80, 96, 129, 130, 132, + 136, 144, 160, 192, 7, 11, 13, 14, + 19, 21, 22, 25, 26, 28, 35, 37, + 38, 41, 42, 44, 49, 50, 52, 56, + 67, 69, 70, 73, 74, 76, 81, 82, + 84, 88, 97, 98, 100, 104, 112, 131, + 133, 134, 137, 138, 140, 145, 146, 148, + 152, 161, 162, 164, 168, 176, 193, 194, + 196, 200, 208, 224, 15, 23, 27, 29, + 30, 39, 43, 45, 46, 51, 53, 54, + 57, 58, 60, 71, 75, 77, 78, 83, + 85, 86, 89, 90, 92, 99, 101, 102, + 105, 106, 108, 113, 114, 116, 120, 135, + 139, 141, 142, 147, 149, 150, 153, 154, + 156, 163, 165, 166, 169, 170, 172, 177, + 178, 180, 184, 195, 197, 198, 201, 202, + 204, 209, 210, 212, 216, 225, 226, 228, + 232, 240, 31, 47, 55, 59, 61, 62, + 79, 87, 91, 93, 94, 103, 107, 109, + 110, 115, 117, 118, 121, 122, 124, 143, + 151, 155, 157, 158, 167, 171, 173, 174, + 179, 181, 182, 185, 186, 188, 199, 203, + 205, 206, 211, 213, 214, 217, 218, 220, + 227, 229, 230, 233, 234, 236, 241, 242, + 244, 248, 63, 95, 111, 119, 123, 125, + 126, 159, 175, 183, 187, 189, 190, 207, + 215, 219, 221, 222, 231, 235, 237, 238, + 243, 245, 246, 249, 250, 252, 127, 191, + 223, 239, 247, 251, 253, 254, 255 +}; + QString modifiersToString(XModifiers mods) { QString s; @@ -82,6 +120,7 @@ KeycodeLookupTable keysyms; void initializeKeycodeLookupTable() { keysyms[Qt::Key_Escape] = XK_Escape; keysyms[Qt::Key_Tab] = XK_Tab; + keysyms[Qt::Key_Backtab] = XK_ISO_Left_Tab; keysyms[Qt::Key_Backspace] = XK_BackSpace; keysyms[Qt::Key_Return] = XK_Return; keysyms[Qt::Key_Enter] = XK_KP_Enter; @@ -147,171 +186,13 @@ void initializeKeycodeLookupTable() { 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_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; + // Latin1 symbols do directly map to + // Keycodes both in Qt and in X11: + for(int i = 0x20; i < 0x100; i++) + { + keysyms[i] = i; + } + keysyms[Qt::Key_AltGr] = XK_ISO_Level3_Shift; keysyms[Qt::Key_Multi_key] = XK_Multi_key; keysyms[Qt::Key_Codeinput] = XK_Codeinput; @@ -373,11 +254,15 @@ void initializeKeycodeLookupTable() { keysyms[Qt::Key_unknown] = XK_VoidSymbol; } -// every keysym with a value under 256 corresponds -// directly to an ISO-Latin1 Character. We need -// to store how to generate those characters: -int basicKeycodes[0x100]; // What key do we need to press? -int basicModifiers[0x100]; // What modifiers are required? +// We need to store how to generate KeySyms: +struct KeySymInfo +{ + KeyCode keycode; + XModifiers neededModifiers; + XModifiers modifierMask; +}; +typedef std::map KeySymToInfoMap; +KeySymToInfoMap keysymInfos; // What keys do we need to press to generate the // modifiers? @@ -388,6 +273,9 @@ Qt::KeyboardModifier modifierMeaning[8]; // How do the X11 modifiers correspond to Qt's KeyboardModifiers? typedef std::map XToQtModifierMap; XToQtModifierMap XToQtModifier; +typedef std::map QtToXModifierMap; +QtToXModifierMap QtToXModifier; + // And how do the modifiers relate to Keycodes? typedef std::multimap ModifierToKeycodeMap; @@ -395,6 +283,36 @@ ModifierToKeycodeMap ModifierToKeycode; typedef std::map KeycodeToModifierMap; KeycodeToModifierMap KeycodeToModifier; +#ifdef HAVE_XKBLIB_H +void recordModifierMapping(XkbDescPtr keybDesc, int keycode, Qt::KeyboardModifier qtMod) +{ + XModifiers rmod = 0; + if(QtToXModifier.find(qtMod) == QtToXModifier.end()) + { + for(int i = 1; i < 0x100; i <<= 1) + { + if(keybDesc->map->modmap[keycode] == i) + { + rmod = i; + XToQtModifier[rmod] = qtMod; + QtToXModifier[qtMod] = rmod; + } + } + } + else + { + rmod = QtToXModifier[qtMod]; + } + + if(rmod) + { + ModifierToKeycode.insert(std::make_pair(rmod, keycode)); + KeycodeToModifier[keycode] = rmod; + ConsoleLog writeLine(QString("%1 %2 %3 ... generates modifier %4").arg(keycode, 3).arg("", 40).arg("", 40).arg(rmod, 2, 16)); + } +} +#endif + // We need to query the input devices, preferrable through XInput2, but // if that is not available we will contend ourselves with XInput1: #ifndef HAVE_XINPUT2_H @@ -428,13 +346,22 @@ KeycodeToModifierMap KeycodeToModifier; // Initialize the above data structures: void initializeBasicKeycodes() { + // We temporarily need a list of all known KeySyms: + typedef std::set KeySymSet; + KeySymSet knownKeySyms; + + for(KeycodeLookupTable::const_iterator kcIter = keysyms.begin(); + kcIter != keysyms.end(); + kcIter++) + { + knownKeySyms.insert((*kcIter).second); + } + // Mark everything as unknown initially for(int i = 0; i < 8; i++) { modifierKeycodes[i] = -1; } - for(int i = 0; i < 0x100; i++) { - basicKeycodes[i] = -1; - } + keysymInfos.clear(); Display* dpy = X11InputUtils::display(); @@ -445,7 +372,11 @@ void initializeBasicKeycodes() // Initialize the XKB client-side code, and find out whether // the XKB extension is present in the server. int xkbOpcode, xkbEvent, xkbError, xkbMajor, xkbMinor; +#ifdef HAVE_XKBLIB_H bool xkbPresent = XkbQueryExtension(dpy, &xkbOpcode, &xkbEvent, &xkbError, &xkbMajor, &xkbMinor); +#else + bool xkbPresent = false; +#endif if(!xkbPresent) { // No XKB. This is probably not a very recent @@ -458,29 +389,81 @@ void initializeBasicKeycodes() // and traverse every entry for(int i = 0; i < count; i++) { - for(int j = 0; j < keysymsPerCode; j++) + for(int j = 0; j < 0x100; j++) { - const int idx = i * keysymsPerCode + j; + const XModifiers mods = modifierpriority[j]; + if(mods >= keysymsPerCode) + continue; + + const int idx = i * keysymsPerCode + mods; const KeySym ks = mapping[idx]; const int keycode = minKeycode + i; - // to find out if there is a Latin1 character there, - if(ks >= ' ' && ks < 0x100) + // to find out if there is a KeySym there that we know about + if(knownKeySyms.find(ks) != knownKeySyms.end()) { // that we have not yet found, - if(basicKeycodes[ks] != -1) + if(keysymInfos.find(ks) != keysymInfos.end()) continue; // already found // and record its keycode and needed modifiers. - basicKeycodes[ks] = keycode; - basicModifiers[ks] = j; + KeySymInfo info; + info.keycode = keycode; + info.neededModifiers = mods; + info.modifierMask = mods; + keysymInfos[ks] = info; } } } // We are finished, free the mapping structure. XFree(mapping); + + // find out which keycodes cause the modifier state bits: + XModifierKeymap* modkm; + modkm = XGetModifierMapping(dpy); + + const int shiftCode = XKeysymToKeycode(dpy, XK_Shift_L); + const int controlCode = XKeysymToKeycode(dpy, XK_Control_L); + const int altCode = XKeysymToKeycode(dpy, XK_Alt_L); + const int metaCode = XKeysymToKeycode(dpy, XK_Meta_L); + const int switchCode = XKeysymToKeycode(dpy, XK_Mode_switch); + + // and use this information to find out which + // X11 modifiers correspond to Qt's modifiers: + 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]; + + ModifierToKeycode.insert(std::make_pair((1<deviceid, devinfo->use, devinfo->name); + for(int i = 0; i < ndevinfos && xkbDeviceId == XkbUseCoreKbd; i++) + { + XIDeviceInfo* devinfo = devinfos + i; + qDebug("Found device %lu of type %d with name %s", (unsigned long)devinfo->deviceid, devinfo->use, devinfo->name); - // We want it to be a keyboard. - if(devinfo->use != XIMasterKeyboard && devinfo->use != XISlaveKeyboard) - continue; + // We want it to be a keyboard. + if(devinfo->use != XIMasterKeyboard && devinfo->use != XISlaveKeyboard) + continue; - int nprops; - Atom* props = getDeviceProperties(dpy, devinfo, &nprops); - if(props) - { - for(int j = 0; j < nprops && xkbDeviceId == XkbUseCoreKbd; j++) + int nprops; + Atom* props = getDeviceProperties(dpy, devinfo, &nprops); + if(props) { - Atom prop = props[j]; - if(prop == xtestDeviceProp) + for(int j = 0; j < nprops && xkbDeviceId == XkbUseCoreKbd; j++) { - // The device is the XTest Keyboard: - xkbDeviceId = devinfo->deviceid; + Atom prop = props[j]; + if(prop == xtestDeviceProp) + { + // The device is the XTest Keyboard: + xkbDeviceId = devinfo->deviceid; + } } + XFree(props); } - XFree(props); } - } - XIFreeDeviceInfo(devinfos); + XIFreeDeviceInfo(devinfos); #ifdef deviceid /* XInput1 */ # undef deviceid #endif + } } +#endif /* HAVE_XINPUT_H || HAVE_XINPUT2_H */ + // at this point, xkbDeviceId contains the identifier // of the XTEST Device, or xkbUseCoreKbd if none was // found. @@ -545,26 +541,64 @@ void initializeBasicKeycodes() { for(int j = 0; j <= 0xff; j++) { + XModifiers mods = modifierpriority[j]; KeySym ks = 0; unsigned int unconsumed; if(keybDesc) { - if(!XkbTranslateKeyCode(keybDesc, i, j, &unconsumed, &ks) || ks == NoSymbol) + if(!XkbTranslateKeyCode(keybDesc, i, mods, &unconsumed, &ks) || ks == NoSymbol) continue; } else { - if(!XkbLookupKeySym(dpy, i, j, &unconsumed, &ks) || ks == NoSymbol) + if(!XkbLookupKeySym(dpy, i, mods, &unconsumed, &ks) || ks == NoSymbol) continue; } - if(ks && (ks < 0x100)) + if(knownKeySyms.find(ks) != knownKeySyms.end()) { - if(basicKeycodes[ks] != -1) + if(j & ~unconsumed) + { + // we would be recording extraneous modifiers + continue; + } + + if(keysymInfos.find(ks) != keysymInfos.end()) continue; - basicKeycodes[ks] = i; - basicModifiers[ks] = unconsumed & j; + KeySymInfo info; + info.keycode = i; + info.neededModifiers = mods & unconsumed; + info.modifierMask = unconsumed; + keysymInfos[ks] = info; + + ConsoleLog writeLine(QString("%1 %2 %3 %4").arg(i, 3).arg(modifiersToString(info.neededModifiers), 40).arg(modifiersToString(info.modifierMask), 40).arg(XKeysymToString(ks))); + } + + if(j == 0) + { + switch(ks) + { + case XK_Shift_L: + case XK_Shift_R: + recordModifierMapping(keybDesc, i, Qt::ShiftModifier); + break; + case XK_Control_L: + case XK_Control_R: + recordModifierMapping(keybDesc, i, Qt::ControlModifier); + break; + case XK_Meta_L: + case XK_Meta_R: + recordModifierMapping(keybDesc, i, Qt::MetaModifier); + break; + case XK_Alt_L: + case XK_Alt_R: + recordModifierMapping(keybDesc, i, Qt::AltModifier); + break; + case XK_ISO_Level3_Shift: + recordModifierMapping(keybDesc, i, Qt::GroupSwitchModifier); + break; + } } } } @@ -575,50 +609,15 @@ void initializeBasicKeycodes() XkbFreeKeyboard(keybDesc, XkbAllComponentsMask, true); } } +#endif /* HAVE_XKBLIB_H */ - // find out which keycodes cause the modifier state bits: - XModifierKeymap* modkm; - modkm = XGetModifierMapping(dpy); - - const int shiftCode = XKeysymToKeycode(dpy, XK_Shift_L); - const int controlCode = XKeysymToKeycode(dpy, XK_Control_L); - const int altCode = XKeysymToKeycode(dpy, XK_Alt_L); - const int metaCode = XKeysymToKeycode(dpy, XK_Meta_L); - const int switchCode = XKeysymToKeycode(dpy, XK_Mode_switch); - - // and use this information to find out which - // X11 modifiers correspond to Qt's modifiers: - 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]; - - ModifierToKeycode.insert(std::make_pair((1<first, 2, 16).arg(i->second, 8, 16)); } - - XFreeModifiermap(modkm); } // Translate a Qt KeyboardModifiers flag to @@ -627,7 +626,7 @@ XModifiers translateModifiers(quint32 mods) { XModifiers ret = 0; - for(int j = 1; j < 8; j++) { + for(int j = 0; j < 8; j++) { XModifiers i = 1< IntSet; IntSet pressedModifierKeys; -XModifiers currentModifiers; +XModifiers currentModifiers = 0; void trackModifiers(int keycode, bool down) { @@ -686,13 +685,15 @@ typedef std::vector TweakSequence; // and record tweaks in the tracker. void tweakModifiers(Display* dpy, XModifiers neededState, XModifiers actualState, TweakSequence& tracker) { + if(neededState == actualState) + // nothing to do. + return; + ConsoleLog writeLine(QString("tweakModifiers: Trying to get to `%1' from `%2'").arg(modifiersToString(neededState)).arg(modifiersToString(actualState))); for(int j = 0; j < 8; j++) { XModifiers i = 1<= ' ' && ks < 0x100) + KeySymToInfoMap::const_iterator infoIter = keysymInfos.find(ks); + if(infoIter != keysymInfos.end()) { - if(basicKeycodes[ks] != -1) + KeySymInfo info = infoIter->second; + + if(evt.isPress()) { - if(evt.isPress()) + QString format = "Trying to press the key for %1 with modifiers %2 (X: %3, Qt: %4), while current modifiers are %5 and needed are %6 with mask %7"; + if(ks >= ' ' && ks < 0x100) + { + ConsoleLog writeLine(format + .arg((char)ks) + .arg(modifiersToString(translateModifiers(evt.qtModifiers()))) + .arg(translateModifiers(evt.qtModifiers()), 2, 16) + .arg(evt.qtModifiers(), 8, 16) + .arg(modifiersToString(currentModifiers)) + .arg(modifiersToString(info.neededModifiers)) + .arg(modifiersToString(info.modifierMask))); + } + else { - // Try the simple way first: - // Does the keycode with current modifiers yield the requested symbol? - KeySym unmodSym = XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers); - ConsoleLog writeLine(QString("Pressing the key for %1 would yield %2 right now.").arg(XKeysymToString(ks)).arg(XKeysymToString(unmodSym))); + ConsoleLog writeLine(format + .arg(XKeysymToString(ks)) + .arg(modifiersToString(translateModifiers(evt.qtModifiers()))) + .arg(translateModifiers(evt.qtModifiers()), 2, 16) + .arg(evt.qtModifiers(), 8, 16) + .arg(modifiersToString(currentModifiers)) + .arg(modifiersToString(info.neededModifiers)) + .arg(modifiersToString(info.modifierMask))); + } - if(ks == XKeycodeToKeysym(dpy, basicKeycodes[ks], currentModifiers)) - { - XTestFakeKeyEvent(dpy, basicKeycodes[ks], 1, CurrentTime); - } - else - { - // what modifier keys do we need to press? - XModifiers mods = translateModifiers(evt.qtModifiers()); + // what modifier keys do we need to press? + XModifiers mods = translateModifiers(evt.qtModifiers()); + XModifiers needed = info.neededModifiers; + XModifiers mask = info.modifierMask; + + // This is quite ad-hoc, but we do NOT want to + // mask Alt. + // On some configurations, the F-Keys consume Alt, + // and when we AND it out, we disable Alt+Fn + // combinations. That's just wrong. + // FIXME: Are there situations + // where we actually need to keep Alt masked? + // Hint: I found none. + // If so, how do we determine that? + QtToXModifierMap::const_iterator altIter = QtToXModifier.find(Qt::AltModifier); + if(altIter != QtToXModifier.end()) + { + mask &= ~(altIter->second); + } - // we may need to press additional modifiers to generate this keysym: - if(QChar(ks, 0).isLetter()) - { - // but, since Qt does not differentiate upper and lower case, - // we need to preserve Shift and Lock in their current state. - mods |= basicModifiers[ks] & ~(1<() .add() - .add() + .add() .add() .add(); // See comments in incompatibleHandler.h } diff --git a/src/input/x11FakeMouseHandler.h b/src/input/x11FakeMouseHandler.h index 8ff8df4..9d41c31 100644 --- a/src/input/x11FakeMouseHandler.h +++ b/src/input/x11FakeMouseHandler.h @@ -20,7 +20,7 @@ #include "inputEventHandler.h" class X11FakeMouseButtonHandler : public InputEventHandler< - input_policy::Match, + input_policy::Match, input_policy::Require, input_policy::Unprivileged> { -- cgit v1.2.3-55-g7522 From c53d10b0fdf137ad8157db2f8150c30ca4e814a8 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 21:35:43 +0200 Subject: Fix broken formatting of InputEvent::toString() --- src/input/inputEvent.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h index 73b7129..f9d3225 100644 --- a/src/input/inputEvent.h +++ b/src/input/inputEvent.h @@ -200,7 +200,7 @@ public: QString toString() const { - return QString("%1:%2:%3").arg(typeToString(_type)).arg(codeToString(_code)).arg(_value, 16); + return QString("%1:%2:%3").arg(typeToString(_type)).arg(codeToString(_code)).arg(_value, 8, 16, QLatin1Char('0')); } quint32 qtKeysym() const -- cgit v1.2.3-55-g7522 From d75d1a3e507e6a4cc01367df4d7a77012819b95b Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sun, 10 Oct 2010 22:09:29 +0200 Subject: Fix bug where pressing the closeUp-button sometimes results in no action. --- src/gui/frame.cpp | 29 +++++++++++- src/gui/frame.h | 3 ++ src/gui/mainWindow.cpp | 119 +++++++++++++++++++++++++++++-------------------- src/gui/mainWindow.h | 2 + 4 files changed, 102 insertions(+), 51 deletions(-) diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp index 12ce6b5..b9899d8 100644 --- a/src/gui/frame.cpp +++ b/src/gui/frame.cpp @@ -47,10 +47,12 @@ Frame::Frame(const QString & text, QWidget * parent) : _isLocked = false; _dozent = false; _uy = _ux = 0; + _isCloseUp = false; //QIcon icon; //icon.addFile(QString::fromUtf8(), QSize(), QIcon::Normal, QIcon::Off); button_closeUp = createToolButton(tr("View"), QIcon(":/restore"),SLOT(closeUp())); + button_closeUp->setCheckable(true); button_foto = createToolButton(tr("Foto"), QIcon(":/photos"),SLOT(foto())); button_lock = createToolButton(tr("Lock this client"), QIcon(":/lock"),SLOT(setLock())); //button_unlock = createToolButton(tr("Unlock this client"), QIcon(":/lock"),SLOT(setLock())); @@ -333,7 +335,11 @@ QImage Frame::getImageForFoto() void Frame::closeUp() { emit clicked(); - MainWindow::getWindow()->closeUp(); + + if(_isCloseUp) + MainWindow::getWindow()->unCloseUp(getConFrame()); + else + MainWindow::getWindow()->closeUp(getConFrame()); } void Frame::foto() @@ -377,6 +383,12 @@ void Frame::setDozent() } } +void Frame::setCloseUp(bool value) +{ + _isCloseUp = value; + button_closeUp->setChecked(value); +} + void Frame::remoteControlClicked() { if(_remoteControlEnabled) @@ -517,7 +529,20 @@ void Frame::keyPressEvent(QKeyEvent* event) { // The action of the keyboard may depend on the position of the pointer sendMouseMotionEvent(); - sendInputEvent(InputEvent::keyboardPress(event->key(), event->modifiers())); + + int key = event->key(); + + if(key >= ' ' && key < 0x100) + { + // the key is a Latin1 key. We need to find out the correct code to send. + QString text = event->text(); + if(text.length() == 1 && text.at(0).row() == 0) + { + // We found a Latin1 char and pray it is the correct case. + key = text.at(0).cell(); + } + } + sendInputEvent(InputEvent::keyboardPress(key, event->modifiers())); } } else diff --git a/src/gui/frame.h b/src/gui/frame.h index 8271670..4a3dd11 100644 --- a/src/gui/frame.h +++ b/src/gui/frame.h @@ -74,6 +74,8 @@ public Q_SLOTS: void setLock(); //void unlock(); void setDozent(); + void setCloseUp(bool value); + private Q_SLOTS: void remoteControlClicked(); void remoteControlAllClicked(); @@ -102,6 +104,7 @@ private: bool _isLocked; bool _dozent; int _ux, _uy; + bool _isCloseUp; // for remote control: QPoint _lastRecordedMousePosition; diff --git a/src/gui/mainWindow.cpp b/src/gui/mainWindow.cpp index 0f2fd0e..19b1021 100644 --- a/src/gui/mainWindow.cpp +++ b/src/gui/mainWindow.cpp @@ -98,7 +98,7 @@ MainWindow::MainWindow(QWidget *parent) : #ifdef MAINWINDOW_USE_TOUCHGUI //only used for the touchgui // define the slots we want to use - connect(ui->comboBox_touch1, SIGNAL(currentIndexChanged(int)), this, SLOT(combobox1(int))); // Combobox 1 verknüpfen mit IndexChangend Signal + connect(ui->comboBox_touch1, SIGNAL(currentIndexChanged(int)), this, SLOT(combobox1(int))); // Combobox 1 verkn��pfen mit IndexChangend Signal connect(ui->comboBox_touch1, SIGNAL(currentIndexChanged(int)), this, SLOT(setindexback())); connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(createProfile())); // profile button @@ -711,61 +711,82 @@ void MainWindow::closeUp() { std::list* selectedClients = MainWindow::getConnectionList()->getSelectedClients(); - if (!is_closeup) + + if(selectedClients->size() != 1) + // Cannot closeUp zero or more than one frames. + return; + + PVSClient* pvsClient = PVSConnectionManager::getManager()->getClientFromIp(selectedClients->front()); + + closeUp(pvsClient->getConnectionFrame(), pvsClient); +} + +void MainWindow::closeUp(ConnectionFrame* connFrame, PVSClient* pvsClient) +{ + std::list* selectedClients = + MainWindow::getConnectionList()->getSelectedClients(); + + if(selectedClients->size() != 1) + // Cannot closeUp zero or more than one frames. + return; + + if(!pvsClient) + pvsClient = connFrame->getConnection(); + + // Do we already have a closeUp Frame? + ConnectionFrame* closeupFrame = conWin->getCloseupFrame(); + + if(closeupFrame) { - if (selectedClients->size() == 1) - { - PVSClient * pvsClient = - PVSConnectionManager::getManager()->getClientFromIp( - selectedClients->front().toStdString().c_str()); - _framePosOnCloseUp = pvsClient->getConnectionFrame()->pos();//get the actualy position before run closeup - if (pvsClient->getVNCConnection()) - { - conWin->setCloseupFrame(pvsClient->getConnectionFrame()); - _updatefreq - = pvsClient->getConnectionFrame()->getFrame()->getVNCClientThread()->getUpdatefreq(); - pvsClient->getConnectionFrame()->getFrame()->getVNCClientThread()->setUpdatefreq( - 50); - pvsClient->getConnectionFrame()->move(5, 5); - pvsClient->getConnectionFrame()->setWindowFlags( - Qt::WindowStaysOnTopHint); - pvsClient->getConnectionFrame()->raise(); - pvsClient->getConnectionFrame()->paintCloseUp( - ui->widget->width(), ui->widget->height()); - - is_closeup = true; - conWin->setCloseupFrame(pvsClient->getConnectionFrame()); - } - } + // Is it the same as the sender one? + if(connFrame == closeupFrame) + // Then it already is close up. + return; else - { - QString - message = - QString( - tr( - "This operation can only be performed for one selected Client!")); - QMessageBox::information(this, "PVS", message); - } + // We need to un-closeUp the currently selected closeUp-Frame. + unCloseUp(closeupFrame); } - else if (conWin->getCloseupFrame()) + + _framePosOnCloseUp = connFrame->pos();//get the actualy position before run closeup + if (pvsClient->getVNCConnection()) { - /*PVSClient* pvsClient = - PVSConnectionManager::getManager()->getClientFromIp( - selectedClients->front().toStdString().c_str());*/ - conWin->getCloseupFrame()->setWindowFlags(Qt::Widget); - conWin->getCloseupFrame()->paintCloseUp( - conWin->getCloseupFrame()->getPrevWidth(), - conWin->getCloseupFrame()->getPrevHeight()); - conWin->getCloseupFrame()->move(_framePosOnCloseUp);//back to the position before the closeup - if (conWin->getCloseupFrame()->getConnection()->getVNCConnection()) - conWin->getCloseupFrame()->getFrame()->getVNCClientThread()->setUpdatefreq( - _updatefreq); - - is_closeup = false; - conWin->setCloseupFrame(NULL); + conWin->setCloseupFrame(connFrame); + _updatefreq = connFrame->getFrame()->getVNCClientThread()->getUpdatefreq(); + connFrame->getFrame()->getVNCClientThread()->setUpdatefreq( + 50); + connFrame->move(5, 5); + connFrame->setWindowFlags(Qt::WindowStaysOnTopHint); + connFrame->raise(); + connFrame->paintCloseUp(ui->widget->width(), ui->widget->height()); + + conWin->setCloseupFrame(connFrame); + + Frame* frame = connFrame->getFrame(); + if(frame) + frame->setCloseUp(true); } } +void MainWindow::unCloseUp(ConnectionFrame* connFrame) +{ + if(!connFrame) + return; + + connFrame->setWindowFlags(Qt::Widget); + connFrame->paintCloseUp( + connFrame->getPrevWidth(), + connFrame->getPrevHeight()); + connFrame->move(_framePosOnCloseUp);//back to the position before the closeup + if (connFrame->getConnection()->getVNCConnection()) + connFrame->getFrame()->getVNCClientThread()->setUpdatefreq(_updatefreq); + + Frame* frame = connFrame->getFrame(); + if(frame) + frame->setCloseUp(false); + + conWin->setCloseupFrame(NULL); +} + /* Perform some action if actionShowProcesses button was pressed * */ diff --git a/src/gui/mainWindow.h b/src/gui/mainWindow.h index 88756fd..c1f100e 100644 --- a/src/gui/mainWindow.h +++ b/src/gui/mainWindow.h @@ -172,6 +172,8 @@ public slots: void clientlisthide(); void projecttoolbar(); void unprojecttoolbar(); + void closeUp(ConnectionFrame* connFrame, PVSClient* client = 0); + void unCloseUp(ConnectionFrame* connFrame); void closeUp(); void foto(); void backgroundpicture(); -- cgit v1.2.3-55-g7522 From d626b99839eb2cf915d96b4048d31e6622ad00ca Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Mon, 11 Oct 2010 00:52:21 +0200 Subject: Add access control check to input event handling in PVS daemon --- src/pvs.cpp | 13 +++++++++++-- src/pvs.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pvs.cpp b/src/pvs.cpp index 96a92ea..e0605c2 100755 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -199,8 +199,11 @@ void PVS::onCommand(PVSMsg cmdMessage) if (ident.compare("INPUTEVENT") == 0) { InputEvent evt; - eventFromString(message, evt); - handleInputEvent(evt); + if(inputEventsAllowed()) + { + eventFromString(message, evt); + handleInputEvent(evt); + } } if (ident.compare("MCASTFTRETRY") == 0) { @@ -749,6 +752,12 @@ bool PVS::createMulticastTransfer(QString const& objectPath, quint64& transferID // Input handling +bool PVS::inputEventsAllowed() +{ + QString lecturer = getConfigValue("Permissions/vnc_lecturer"); + return r == "rw"; +} + void PVS::handleInputEvent(InputEvent const& evt) { QString s = evt.toString(); diff --git a/src/pvs.h b/src/pvs.h index 902fbe7..27ea2fc 100755 --- a/src/pvs.h +++ b/src/pvs.h @@ -169,6 +169,7 @@ private: // input event handling: InputEventHandlerChain _inputEventHandlers; + bool inputEventsAllowed(); void handleInputEvent(InputEvent const& evt); void initializeInputEventHandling(); -- cgit v1.2.3-55-g7522 From 732b9cfec697e893fcf5b65e1e7c9e5921ea5951 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Mon, 11 Oct 2010 09:02:38 +0200 Subject: Introduce LogNonMatchingHandler --- src/input/CMakeLists.txt | 1 + src/input/logNonMatchingHandler.cpp | 27 +++++++++++++++++++++++ src/input/logNonMatchingHandler.h | 33 +++++++++++++++++++++++++++++ src/input/unprivilegedInputHandlerChain.cpp | 4 +++- 4 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/input/logNonMatchingHandler.cpp create mode 100644 src/input/logNonMatchingHandler.h diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index d950c67..b4dfa4d 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -4,6 +4,7 @@ set(pvsinput_SRCS inputEvent.cpp unprivilegedInputHandlerChain.cpp inputEventHandler.cpp + logNonMatchingHandler.cpp ) set(feature_DEFS) diff --git a/src/input/logNonMatchingHandler.cpp b/src/input/logNonMatchingHandler.cpp new file mode 100644 index 0000000..dd694fc --- /dev/null +++ b/src/input/logNonMatchingHandler.cpp @@ -0,0 +1,27 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/input/nonMatchingHandler.cpp: +# - Log events that were not matched by another handler - implementation +# ----------------------------------------------------------------------------- +*/ + +#include "logNonMatchingHandler.h" +#include + +void LogNonMatchingHandler::doHandle(InputEvent const& event, InputEventContext const* context) +{ + // It's not really nonmatched if it has already been denied + if(!context->hasBeenDenied) + { + qWarning("No matching handler found for event %s", event.toString().toLocal8Bit().constData()); + } +} diff --git a/src/input/logNonMatchingHandler.h b/src/input/logNonMatchingHandler.h new file mode 100644 index 0000000..3403640 --- /dev/null +++ b/src/input/logNonMatchingHandler.h @@ -0,0 +1,33 @@ +/* +# 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/ +# ----------------------------------------------------------------------------- +# src/input/nonMatchingHandler.h: +# - Log events that were not matched by another handler - interface +# ----------------------------------------------------------------------------- +*/ + +#ifndef LOGNONMATCHINGHANDLER_H_ +#define LOGNONMATCHINGHANDLER_H_ + +#include "inputEventHandler.h" + +class LogNonMatchingHandler : public InputEventHandler +{ +public: + bool isApplicable(InputEvent const&, InputEventContext const*) + { + return true; + } + + void doHandle(InputEvent const&, InputEventContext const*); +}; + +#endif /* LOGNONMATCHINGHANDLER_H_ */ diff --git a/src/input/unprivilegedInputHandlerChain.cpp b/src/input/unprivilegedInputHandlerChain.cpp index 2df2d77..3f47631 100644 --- a/src/input/unprivilegedInputHandlerChain.cpp +++ b/src/input/unprivilegedInputHandlerChain.cpp @@ -20,6 +20,7 @@ #include "privilegedHandlerForwarder.h" #include "incompatibleHandler.h" #include "inputHandlerChains.h" +#include "logNonMatchingHandler.h" InputEventHandlerChain makeUnprivilegedInputEventHandlerChain() { @@ -27,6 +28,7 @@ InputEventHandlerChain makeUnprivilegedInputEventHandlerChain() .add() .add() .add() - .add(); // See comments in incompatibleHandler.h + .add() // See comments in incompatibleHandler.h + .add(); } -- cgit v1.2.3-55-g7522 From ee5f13df4fa951259f5f4c62274483ee4a5e34a7 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Mon, 11 Oct 2010 09:02:49 +0200 Subject: Fix stupid Typo bug. --- src/pvs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pvs.cpp b/src/pvs.cpp index e0605c2..f582caa 100755 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -755,7 +755,7 @@ bool PVS::createMulticastTransfer(QString const& objectPath, quint64& transferID bool PVS::inputEventsAllowed() { QString lecturer = getConfigValue("Permissions/vnc_lecturer"); - return r == "rw"; + return lecturer == "rw"; } void PVS::handleInputEvent(InputEvent const& evt) -- cgit v1.2.3-55-g7522 From 5ba61818d5bdd1b96996eb0fe1a5b3befc16b1a0 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Mon, 11 Oct 2010 09:04:19 +0200 Subject: Log unmatched events in pvsprivinputd, too. --- src/input/privilegedInputHandlerChain.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/input/privilegedInputHandlerChain.cpp b/src/input/privilegedInputHandlerChain.cpp index 5764728..c1e8629 100644 --- a/src/input/privilegedInputHandlerChain.cpp +++ b/src/input/privilegedInputHandlerChain.cpp @@ -20,11 +20,13 @@ #include "killX11Handler.h" #include "magicSysRqHandler.h" #include "inputHandlerChains.h" +#include "logNonMatchingHandler.h" InputEventHandlerChain makePrivilegedInputEventHandlerChain() { return InputEventHandlerChain().add() .add() .add() - .add(); + .add() + .add(); } -- cgit v1.2.3-55-g7522 From bcaa6e3580f5b227ab48693192c459cc72c30224 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Mon, 11 Oct 2010 12:27:27 +0200 Subject: Better error handling for PVSPrivInputHandler --- src/input/pvsPrivInputHandler.cpp | 21 ++++++++++++++++++--- src/input/pvsprivinputd.cpp | 4 +++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/input/pvsPrivInputHandler.cpp b/src/input/pvsPrivInputHandler.cpp index 84ccbae..d33697a 100644 --- a/src/input/pvsPrivInputHandler.cpp +++ b/src/input/pvsPrivInputHandler.cpp @@ -86,9 +86,24 @@ void PVSPrivInputHandler::canRead() if(!pvsPrivInputRecvMessage(_fd, _messageAssembly.data(), siz, pid, uid, gid, &err)) { - close(_fd); - deleteLater(); - return; + switch(err) + { + case EAGAIN: +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif + // That's okay. Nothing to do. + break; + case 0: + // We'll survive. There was no actual error, just the library routine + // that decided it did not really want to receive that packet. + break; + default: + qWarning("Something bad just happened, and cannot handle it. Panicking."); + close(_fd); + deleteLater(); + return; + } } else { diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp index e6ae155..df3acfc 100644 --- a/src/input/pvsprivinputd.cpp +++ b/src/input/pvsprivinputd.cpp @@ -182,7 +182,9 @@ int main(int argc, char** argv) } // Install our main object - PVSPrivInputHandler handler(sock); + PVSPrivInputHandler* handler = new PVSPrivInputHandler(sock, &app); + // When the handler gets deleted, we want to quit the application + QObject::connect(handler, SIGNAL(destroyed(QObject*)), &app, SLOT(quit())); // set up signal handling: if(socketpair(AF_UNIX, SOCK_DGRAM, 0, signalFds) < 0) -- cgit v1.2.3-55-g7522 From 6fcd6c00510d4da9c72d1d44c769bb0d546ca9ef Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 12 Oct 2010 05:16:37 +0200 Subject: Fix InputEventHandler logic bug Entered break instead of return. --- src/input/inputEventHandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 11e2f4e..a2e943e 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -309,7 +309,7 @@ public: switch(i.next()->handle(event, context)) { case InputEventHandlerBase::HANDLER_MATCHED: - break; + return; case InputEventHandlerBase::HANDLER_NOT_ALLOWED: context->hasBeenDenied = true; case InputEventHandlerBase::HANDLER_NOT_APPLICABLE: -- cgit v1.2.3-55-g7522 From f74fc506229abb42e0ecd67a4bd0fa3ac68f8149 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 12 Oct 2010 05:17:05 +0200 Subject: Fix segmentation fault in LogNonMatchingHandler Would SIGSEGV if an unmatched event arrived with no context. --- src/input/logNonMatchingHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/logNonMatchingHandler.cpp b/src/input/logNonMatchingHandler.cpp index dd694fc..b0aa93a 100644 --- a/src/input/logNonMatchingHandler.cpp +++ b/src/input/logNonMatchingHandler.cpp @@ -20,7 +20,7 @@ void LogNonMatchingHandler::doHandle(InputEvent const& event, InputEventContext const* context) { // It's not really nonmatched if it has already been denied - if(!context->hasBeenDenied) + if(!context || !context->hasBeenDenied) { qWarning("No matching handler found for event %s", event.toString().toLocal8Bit().constData()); } -- cgit v1.2.3-55-g7522 From c26b6dc30178bd153598d7d4b6a2ce64251596d3 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 12 Oct 2010 05:17:27 +0200 Subject: Fix default PolicyKit policy Admin password is required if user is not local and unprivileged. --- src/input/org.openslx.pvs.input.policy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/input/org.openslx.pvs.input.policy b/src/input/org.openslx.pvs.input.policy index f0de9f2..f4a73e6 100644 --- a/src/input/org.openslx.pvs.input.policy +++ b/src/input/org.openslx.pvs.input.policy @@ -10,8 +10,8 @@ Use privileged input actions in PVS Authentication is required to let PVS use privileged input actions - auth_self_keep - auth_self_keep + auth_admin_keep + auth_admin_keep auth_admin_keep -- cgit v1.2.3-55-g7522 From 09e7427b3715ae8cfeb81bb3489b70a823662d19 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 12 Oct 2010 05:19:30 +0200 Subject: Fix build error. --- src/input/CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index b4dfa4d..4f9eb4d 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -164,8 +164,3 @@ add_library( ${pvsinput_SRCS} ${pvsinput_RCS} ) - -add_library( - pvsinputtests - STATIC - templateMagicTests.cpp) -- cgit v1.2.3-55-g7522 From d81fa20f32d6285731248405d47fc34b8e612073 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 12 Oct 2010 06:12:20 +0200 Subject: Fix control character handling bug. The code to deal with lowercase and uppercase versions of Latin1 characters was overly broad and sent ASCII Control Characters if Ctrl was pressed. --- src/gui/frame.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp index b9899d8..12d49bc 100644 --- a/src/gui/frame.cpp +++ b/src/gui/frame.cpp @@ -538,8 +538,18 @@ void Frame::keyPressEvent(QKeyEvent* event) QString text = event->text(); if(text.length() == 1 && text.at(0).row() == 0) { - // We found a Latin1 char and pray it is the correct case. - key = text.at(0).cell(); + QChar c = text.at(0); + + // The next problem is that it may be a control character. + // This happens when Ctrl is pressed, so we only + // modify keys if they are lowercase or uppercase + // versions of the keycode. + + if(c.toLower().toLatin1() == key || c.toUpper().toLatin1() == key) + { + // We found a Latin1 char and pray it is the correct case. + key = c.cell(); + } } } sendInputEvent(InputEvent::keyboardPress(key, event->modifiers())); -- cgit v1.2.3-55-g7522 From 6f9be93b8e47a5a65a3c56fab0de7e78d150d790 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 12 Oct 2010 09:44:11 +0200 Subject: Document changed requirements --- INSTALL | 2 ++ 1 file changed, 2 insertions(+) diff --git a/INSTALL b/INSTALL index cfb079b..6a7d736 100644 --- a/INSTALL +++ b/INSTALL @@ -6,6 +6,8 @@ The following packages are required: libvncserver-dev libx11-dev + libxi-dev + libxtst-dev libqt4-dev >= 4.5.3 qt4-dev-tools >= 4.5.3 cmake >= 2.4.0 -- cgit v1.2.3-55-g7522 From 2561bfbe4f72bfb2093da2d93b1298caaa4f4497 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 13 Oct 2010 03:28:43 +0200 Subject: Fix key case comparison bug --- src/gui/frame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp index 12d49bc..561f3ce 100644 --- a/src/gui/frame.cpp +++ b/src/gui/frame.cpp @@ -545,7 +545,7 @@ void Frame::keyPressEvent(QKeyEvent* event) // modify keys if they are lowercase or uppercase // versions of the keycode. - if(c.toLower().toLatin1() == key || c.toUpper().toLatin1() == key) + if(c.toLower().toLatin1() == (char)key || c.toUpper().toLatin1() == (char)key) { // We found a Latin1 char and pray it is the correct case. key = c.cell(); -- cgit v1.2.3-55-g7522 From 45ffedadfb42973e244debdb63300e9aefda5414 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 13 Oct 2010 03:34:39 +0200 Subject: Introduce init-scripts for pvsprivinputd --- src/input/CMakeLists.txt | 9 ++ src/input/pvsprivinputd.gentooinit.in | 37 +++++++++ src/input/pvsprivinputd.lsbinit.in | 152 ++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 src/input/pvsprivinputd.gentooinit.in create mode 100644 src/input/pvsprivinputd.lsbinit.in diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 4f9eb4d..26eeb64 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -164,3 +164,12 @@ add_library( ${pvsinput_SRCS} ${pvsinput_RCS} ) + +if(EXISTS /etc/gentoo-release) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pvsprivinputd.gentooinit.in ${CMAKE_CURRENT_BINARY_DIR}/pvsprivinputd.init @ONLY@) +else() + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pvsprivinputd.lsbinit.in ${CMAKE_CURRENT_BINARY_DIR}/pvsprivinputd.init @ONLY@) +endif() +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/pvsprivinputd.init + DESTINATION /etc/init.d + RENAME pvsprivinputd) diff --git a/src/input/pvsprivinputd.gentooinit.in b/src/input/pvsprivinputd.gentooinit.in new file mode 100644 index 0000000..03ade0f --- /dev/null +++ b/src/input/pvsprivinputd.gentooinit.in @@ -0,0 +1,37 @@ +#!/sbin/runscript +# Copyright (C) 2010 OpenSKX Project, Computer Center of the University of Freiburg, Germany +# This program is free software distributed under the GPL version 2. +# See http://openslx.org/COPYING + +opts="${opts} reload" + +PVSPRIVINPUTD_BINARY="@CMAKE_INSTALL_PREFIX@/sbin/pvsprivinputd" +PVSPRIVINPUTD_PIDFILE="/var/run/pvsprivinputd.pid" + +depend() { + use net + use logger + before dbus +} + +start() { + ebegin "Starting pvsprivinputd" + start-stop-daemon --start --pidfile "${PVSPRIVINPUTD_PIDFILE}" \ + --exec "${PVSPRIVINPUTD_BINARY}" -- \ + -d -lsyslog + eend $? +} + +stop() { + ebegin "Stopping pvsprivinputd" + start-stop-daemon --stop --signal SIGINT --pidfile "${PVSPRIVINPUTD_PIDFILE}" \ + --exec "${PVSPRIVINPUTD_BINARY}" + eend $? +} + +reload() { + ebegin "Realoding pvsprivinputd's configuration" + start-stop-daemon --stop --signal SIGHUP --pidfile "${PVSPRIVINPUTD_PIDFILE}" \ + --oknodo --exec "${PVSPRIVINPUTD_BINARY}" + eend $? +} diff --git a/src/input/pvsprivinputd.lsbinit.in b/src/input/pvsprivinputd.lsbinit.in new file mode 100644 index 0000000..9b4293e --- /dev/null +++ b/src/input/pvsprivinputd.lsbinit.in @@ -0,0 +1,152 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: pvsprivinputd +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: PVS Privileged Input Daemon +# Description: Support system service for PVS. +### END INIT INFO + +# Author: Sebastien Braun +# +# Please remove the "Author" lines above and replace them +# with your own name if you copy and modify this script. + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin +DESC="Support system service for PVS" +NAME=pvsprivinputd +DAEMON=@CMAKE_INSTALL_PREFIX@/sbin/pvsprivinputd +DAEMON_ARGS="-d -lsyslog" +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.0-6) to ensure that this file is present. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + restart) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + exit 3 + ;; +esac + +: -- cgit v1.2.3-55-g7522 From a27b41dfcbf1c73a2eab60e5e32016eee014f816 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 13 Oct 2010 03:34:59 +0200 Subject: Uncomment killing of X-Server --- src/input/killX11Handler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/killX11Handler.cpp b/src/input/killX11Handler.cpp index 32e5873..8fa8c24 100644 --- a/src/input/killX11Handler.cpp +++ b/src/input/killX11Handler.cpp @@ -85,5 +85,5 @@ void KillX11Handler::doHandle(InputEvent const&, InputEventContext const* ctx) QString exe = QFileInfo(QString("/proc/%1/exe").arg(pids[0])).readLink(); qDebug("Killing X server, PID %d, exe name %s with SIGTERM", pids[0], exe.toLocal8Bit().constData()); -// kill(pids[0], SIGTERM); + kill(pids[0], SIGTERM); } -- cgit v1.2.3-55-g7522 From a576f62d0e3003824832e4730dd42aa16dc1f178 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 13 Oct 2010 05:07:44 +0200 Subject: Formatting fixes for X11FakeKeyboardHandler --- src/input/x11FakeKeyboardHandler.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index fed087e..333baab 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -186,6 +186,7 @@ void initializeKeycodeLookupTable() { keysyms[Qt::Key_Hyper_L] = XK_Hyper_L; keysyms[Qt::Key_Hyper_R] = XK_Hyper_R; keysyms[Qt::Key_Help] = XK_Help; + // Latin1 symbols do directly map to // Keycodes both in Qt and in X11: for(int i = 0x20; i < 0x100; i++) @@ -572,7 +573,11 @@ void initializeBasicKeycodes() info.modifierMask = unconsumed; keysymInfos[ks] = info; - ConsoleLog writeLine(QString("%1 %2 %3 %4").arg(i, 3).arg(modifiersToString(info.neededModifiers), 40).arg(modifiersToString(info.modifierMask), 40).arg(XKeysymToString(ks))); + ConsoleLog writeLine(QString("%1 %2 %3 %4") + .arg(i, 3) + .arg(modifiersToString(info.neededModifiers), 40) + .arg(modifiersToString(info.modifierMask), 40) + .arg(XKeysymToString(ks))); } if(j == 0) -- cgit v1.2.3-55-g7522 From 3db2c6c566b57fb02bd5529274ab690e7e0b1ffc Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 13 Oct 2010 05:09:02 +0200 Subject: Fix forgotten change of j to mods in X11FakeKeyboardHandler. --- src/input/x11FakeKeyboardHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index 333baab..f27ea1e 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -558,7 +558,7 @@ void initializeBasicKeycodes() if(knownKeySyms.find(ks) != knownKeySyms.end()) { - if(j & ~unconsumed) + if(mods & ~unconsumed) { // we would be recording extraneous modifiers continue; -- cgit v1.2.3-55-g7522 From 7e3b963e3a0cbbf9391243e72ceb015e9015d630 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Sat, 23 Oct 2010 17:49:12 +0200 Subject: Documentation fixes and code cleanup --- doc/doxconf | 10 +- src/input/detail/gen/gen_typeList.cpp | 3 + src/input/detail/typeList_autogen.h | 2 + src/input/i18n/pvsinput_ar_JO.ts | 46 +++---- src/input/i18n/pvsinput_de_DE.ts | 46 +++---- src/input/i18n/pvsinput_es_MX.ts | 46 +++---- src/input/i18n/pvsinput_fr_FR.ts | 46 +++---- src/input/i18n/pvsinput_pl_PL.ts | 46 +++---- src/input/inputEvent.cpp | 32 ++++- src/input/inputEvent.h | 245 +++++++++++++++++++++++++++------ src/input/inputEventHandler.h | 198 ++++++++++++++++++-------- src/input/inputHandlerChains.h | 15 ++ src/input/killX11Handler.h | 11 ++ src/input/logNonMatchingHandler.h | 3 + src/input/magicSysRqHandler.h | 12 +- src/input/privilegedHandlerForwarder.h | 13 ++ src/input/pvsCheckPrivileges.h | 65 +++++++-- src/input/pvsPrivInputHandler.h | 9 ++ src/input/pvsPrivInputSignalHandler.h | 17 +++ src/input/pvsPrivInputSocket.h | 38 +++++ src/input/pvsSyslog.h | 9 ++ src/input/rebootSystemHandler.h | 6 + src/input/sayHelloHandler.h | 4 + src/input/x11FakeKeyboardHandler.h | 7 + src/input/x11FakeMouseHandler.h | 6 + src/input/x11InputUtils.h | 3 + 26 files changed, 695 insertions(+), 243 deletions(-) diff --git a/doc/doxconf b/doc/doxconf index 50334c7..e3e32a6 100644 --- a/doc/doxconf +++ b/doc/doxconf @@ -564,7 +564,7 @@ WARN_LOGFILE = ./doxwarnlog # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ./pvsClient.h ./pvsClient.cpp ./pvs.h ./pvs.cpp ./pvsDaemon.h ./pvsDaemon.cpp ./src +INPUT = ../pvsClient.h ../pvsClient.cpp ../pvs.h ../pvs.cpp ../pvsDaemon.h ../pvsDaemon.cpp ../src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -1210,13 +1210,13 @@ ENABLE_PREPROCESSING = YES # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. -EXPAND_ONLY_PREDEF = NO +EXPAND_ONLY_PREDEF = YES # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. @@ -1244,7 +1244,9 @@ INCLUDE_FILE_PATTERNS = # undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = "DOXYGEN_RUNNING" \ + "BEGIN_POLICY_CLASS(name)=class name" \ + "END_POLICY_CLASS=;" # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. diff --git a/src/input/detail/gen/gen_typeList.cpp b/src/input/detail/gen/gen_typeList.cpp index e092b80..21056f9 100644 --- a/src/input/detail/gen/gen_typeList.cpp +++ b/src/input/detail/gen/gen_typeList.cpp @@ -47,6 +47,8 @@ int main(int, char**) cout << "template\n" "struct Contains { static const int index = -1; static const bool value = false; };\n"; + // specializations: + cout << "#ifndef DOXYGEN_RUNNING\n"; for(i = 0; i < NUM_MAX_ENTRIES; i++) { int j; @@ -70,6 +72,7 @@ int main(int, char**) } cout << "> >\n{ static const int index = " << i << "; static const bool value = true; };\n"; } + cout << "#endif\n"; // Empty List: cout << "typedef TypeList<"; diff --git a/src/input/detail/typeList_autogen.h b/src/input/detail/typeList_autogen.h index 0f8fdd4..79f1335 100644 --- a/src/input/detail/typeList_autogen.h +++ b/src/input/detail/typeList_autogen.h @@ -5,6 +5,7 @@ typedef TypeList struct Contains { static const int index = -1; static const bool value = false; }; +#ifndef DOXYGEN_RUNNING template struct Contains > { static const int index = 0; static const bool value = true; }; @@ -53,6 +54,7 @@ struct Contains struct Contains > { static const int index = 15; static const bool value = true; }; +#endif typedef TypeList EmptyList; #define IMPLICIT_TYPE_LIST_PARAMS(prefix) typename prefix##0 = void, typename prefix##1 = void, typename prefix##2 = void, typename prefix##3 = void, typename prefix##4 = void, typename prefix##5 = void, typename prefix##6 = void, typename prefix##7 = void, typename prefix##8 = void, typename prefix##9 = void, typename prefix##10 = void, typename prefix##11 = void, typename prefix##12 = void, typename prefix##13 = void, typename prefix##14 = void, typename prefix##15 = void #define IMPLICIT_TYPE_LIST_PARAMS_NODEFAULT(prefix) typename prefix##0, typename prefix##1, typename prefix##2, typename prefix##3, typename prefix##4, typename prefix##5, typename prefix##6, typename prefix##7, typename prefix##8, typename prefix##9, typename prefix##10, typename prefix##11, typename prefix##12, typename prefix##13, typename prefix##14, typename prefix##15 diff --git a/src/input/i18n/pvsinput_ar_JO.ts b/src/input/i18n/pvsinput_ar_JO.ts index 1040142..bf25eda 100644 --- a/src/input/i18n/pvsinput_ar_JO.ts +++ b/src/input/i18n/pvsinput_ar_JO.ts @@ -4,117 +4,117 @@ InputEvent - + Say Hello - + Reboot - + Kill X Server - + Reboot immediately - + Power off immediately - + Crash System - + Turn off raw keyboard mode - + Send SIGTERM to all - + Send SIGKILL to all - + Kill all on this terminal - + Activate OOM killer - + Make real-time tasks niceable - + Force-thaw filesystems - + Sync all mounted filesystems - + Remount all readonly - + Show all held locks - + Show stack traces - + Dump memory info - + Dump registers and flags - + Dump timers and clockevents - + Dump task list - + Dump uninterruptible tasks - + Dump ftrace buffer diff --git a/src/input/i18n/pvsinput_de_DE.ts b/src/input/i18n/pvsinput_de_DE.ts index 56ebf26..002016a 100644 --- a/src/input/i18n/pvsinput_de_DE.ts +++ b/src/input/i18n/pvsinput_de_DE.ts @@ -4,117 +4,117 @@ InputEvent - + Say Hello Hallo sagen - + Reboot Neustart - + Kill X Server X-Server töten - + Reboot immediately Sofort neu starten - + Power off immediately Sofort abschalten - + Crash System Systemabsturz - + Turn off raw keyboard mode RAW-Tastatur-Modus abschalten - + Send SIGTERM to all SIGTERM an alle Prozesse senden - + Send SIGKILL to all SIGKILL an alle Prozesse senden - + Kill all on this terminal Alle Prozesse an diesem Terminal töten - + Activate OOM killer OOM-Killer aktivieren - + Make real-time tasks niceable Nice für Echtzeitprozesse ermöglichen - + Force-thaw filesystems - + Sync all mounted filesystems Alle eingebundenen Dateisysteme sync(2)en - + Remount all readonly Alle Dateisysteme nur-lesbar mounten - + Show all held locks Alle gehaltenen Sperren zeigen - + Show stack traces Stacktraces anzigen - + Dump memory info Speicherinfo anzeigen - + Dump registers and flags Register und Flags anzeigen - + Dump timers and clockevents Timer und Clockevents anzeigen - + Dump task list Taskliste anzeigen - + Dump uninterruptible tasks Ununterbrechbare Tasks anzeigen - + Dump ftrace buffer ftrace-Puffer anzeigen diff --git a/src/input/i18n/pvsinput_es_MX.ts b/src/input/i18n/pvsinput_es_MX.ts index 047c59c..d805d0e 100644 --- a/src/input/i18n/pvsinput_es_MX.ts +++ b/src/input/i18n/pvsinput_es_MX.ts @@ -4,117 +4,117 @@ InputEvent - + Say Hello - + Reboot - + Kill X Server - + Reboot immediately - + Power off immediately - + Crash System - + Turn off raw keyboard mode - + Send SIGTERM to all - + Send SIGKILL to all - + Kill all on this terminal - + Activate OOM killer - + Make real-time tasks niceable - + Force-thaw filesystems - + Sync all mounted filesystems - + Remount all readonly - + Show all held locks - + Show stack traces - + Dump memory info - + Dump registers and flags - + Dump timers and clockevents - + Dump task list - + Dump uninterruptible tasks - + Dump ftrace buffer diff --git a/src/input/i18n/pvsinput_fr_FR.ts b/src/input/i18n/pvsinput_fr_FR.ts index 8e3e417..af231ea 100644 --- a/src/input/i18n/pvsinput_fr_FR.ts +++ b/src/input/i18n/pvsinput_fr_FR.ts @@ -4,117 +4,117 @@ InputEvent - + Say Hello - + Reboot - + Kill X Server - + Reboot immediately - + Power off immediately - + Crash System - + Turn off raw keyboard mode - + Send SIGTERM to all - + Send SIGKILL to all - + Kill all on this terminal - + Activate OOM killer - + Make real-time tasks niceable - + Force-thaw filesystems - + Sync all mounted filesystems - + Remount all readonly - + Show all held locks - + Show stack traces - + Dump memory info - + Dump registers and flags - + Dump timers and clockevents - + Dump task list - + Dump uninterruptible tasks - + Dump ftrace buffer diff --git a/src/input/i18n/pvsinput_pl_PL.ts b/src/input/i18n/pvsinput_pl_PL.ts index 87527d5..11365c0 100644 --- a/src/input/i18n/pvsinput_pl_PL.ts +++ b/src/input/i18n/pvsinput_pl_PL.ts @@ -4,117 +4,117 @@ InputEvent - + Say Hello - + Reboot - + Kill X Server - + Reboot immediately - + Power off immediately - + Crash System - + Turn off raw keyboard mode - + Send SIGTERM to all - + Send SIGKILL to all - + Kill all on this terminal - + Activate OOM killer - + Make real-time tasks niceable - + Force-thaw filesystems - + Sync all mounted filesystems - + Remount all readonly - + Show all held locks - + Show stack traces - + Dump memory info - + Dump registers and flags - + Dump timers and clockevents - + Dump task list - + Dump uninterruptible tasks - + Dump ftrace buffer diff --git a/src/input/inputEvent.cpp b/src/input/inputEvent.cpp index b623281..cff1ac8 100644 --- a/src/input/inputEvent.cpp +++ b/src/input/inputEvent.cpp @@ -1,8 +1,17 @@ /* - * inputEvent.cpp - * - * Created on: 06.09.2010 - * Author: brs + # 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 - utility routines + # -------------------------------------------------------------------------- */ #include @@ -16,18 +25,29 @@ #include // We implement operators to serialize and load an event: +/** + * Serialize an input event to a \ref QDataStream. + */ QDataStream& operator <<(QDataStream& ostrm, InputEvent const& evt) { ostrm << evt._type << evt._code << evt._value; return ostrm; } +/** + * Load an input event from a \ref QDataStream. + */ QDataStream& operator >>(QDataStream& istrm, InputEvent& evt) { istrm >> evt._type >> evt._code >> evt._value; return istrm; } +/** + * Produce a string-encodeable representation of an input event. + * This consists of a base64-encoded binary representation as + * generated by \ref{operator<<(QDataStream&, InputEvent const&)}. + */ void eventToString(InputEvent const& evt, QString& str) { QByteArray ba; @@ -38,6 +58,10 @@ void eventToString(InputEvent const& evt, QString& str) str = QString::fromAscii(ba.toBase64()); } +/** + * Decode the string representation of an input-event produced by + * \ref eventToString. + */ bool eventFromString(QString const& str, InputEvent& evt) { // TODO This does not do proper error checking. Only use from trusted sources! diff --git a/src/input/inputEvent.h b/src/input/inputEvent.h index f9d3225..afb33e5 100644 --- a/src/input/inputEvent.h +++ b/src/input/inputEvent.h @@ -21,15 +21,23 @@ #include // for translation #include -#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; +/** + * The inputEvent class represents a single input event. + * An input event is any of: + * - Pressing or releasing a keyboard key, + * - Moving the mouse pointer, + * - Pressing or releasing a mouse button, + * - Special system events like "reboot". + * + * Events are described by the \ref type(), \ref code() + * and \ref value(). Possible values for \ref type() are given by + * the \c ET_* constants, and for \ref code() by the \c EC_* constants. + */ class InputEvent { private: @@ -59,109 +67,229 @@ public: { } - static InputEvent mouseMotion(quint16 x, quint16 y) - { - return InputEvent(ET_POINTER, 0, ((quint32)x << 16) | y); - } - - static quint16 mouseButtonsFromQt(int b); + /** \name Factory Functions */ + /* @{ */ + /** + * Generates an event for a mouse button press or release. + * \param button The button that caused this event, as defined by \ref Qt::MouseButton. + * \param buttons The buttons that were pressed at the moment the event was generated, as defined by \ref Qt::MouseButtons. + * If the event is a button press, this includes the pressed button. If it is a button release, + * it does not include the pressed button. + */ static InputEvent mousePressRelease(int button, int buttons); - static InputEvent keyboardPress(int key, int mods); - static InputEvent keyboardRelease(int key, int mods); - - static const quint16 ET_KEY = 0; - static const quint16 ET_BUTTON = 1; - static const quint16 ET_POINTER = 2; - static const quint16 ET_SPECIAL = 3; - static const quint16 EC_PRESS = 0; - static const quint16 EC_RELEASE = 1; - static const quint16 EC_REBOOT = 2; - static const quint16 EC_SYSRQ = 3; - static const quint16 EC_KILL_X = 4; - static const quint16 EC_SAY_HELLO = 5; //< for debugging purposes + /** + * Generates an event for a keyboard press. + * \param key The key code that generated this event, as defined by \ref Qt::Key. + * \param mods The modificator keys that were pressed at the moment the event was generated, + * as defined by \ref Qt::KeyboardModifiers. + */ + static InputEvent keyboardPress(int key, int mods); - typedef quint32 event_key; + /** + * Generates an event for a keyboard release. + * \param key The key code that generated this event, as defined by \ref Qt::Key. + * \param mods The modificator keys that were pressed at the moment the event was generated, + * as defined by \ref Qt::KeyboardModifiers. + */ + static InputEvent keyboardRelease(int key, int mods); - typedef quint32 event_key_modifiers; + /** + * Generates an event for a mouse pointer movement. + * \param x,y X and Y coordinates of the mouse pointer. + */ + static InputEvent mouseMotion(uint16_t x, uint16_t y) + { + return InputEvent(ET_POINTER, 0, ((uint32_t)x << 16) | y); + } - static const quint16 EB_LEFT = 1; - static const quint16 EB_MIDDLE = 2; - static const quint16 EB_RIGHT = 4; + /* @} */ + + /** \name Event Types */ + /* @{ */ + static const uint16_t ET_KEY = 0; /**< The event is related to the keyboard */ + static const uint16_t ET_BUTTON = 1; /**< The event is related to a mouse button */ + static const uint16_t ET_POINTER = 2; /**< The event is related to the mouse pointer */ + static const uint16_t ET_SPECIAL = 3; /**< The event is a special system event */ + /* @} */ + + /** \name Event Codes */ + /* @{ */ + static const uint16_t EC_PRESS = 0; /**< The event is a press (keyboard or mouse button) */ + static const uint16_t EC_RELEASE = 1; /**< The event is a release (keyboard or mouse button) */ + static const uint16_t EC_REBOOT = 2; /**< The event is a request to reboot (special system event) */ + static const uint16_t EC_SYSRQ = 3; /**< The event is a request to perform a Magic-SysRq function (special system event) */ + static const uint16_t EC_KILL_X = 4; /**< The event is a request to kill the X Server (special system event) */ + static const uint16_t EC_SAY_HELLO = 5; /**< The event is a request to write a line to the log file (special system event) */ + /* @} */ + + /** \name Mouse Button Flags */ + /* @{ */ + static const uint16_t EB_LEFT = 1; /**< The left mouse button */ + static const uint16_t EB_MIDDLE = 2; /**< The middle mouse button */ + static const uint16_t EB_RIGHT = 4; /**< The right mouse button */ + /* @} */ static const quint32 MODIFIER_MASK = 0x7e000000; - quint16 type() const + /** \name Event Decoding Functions */ + /* @{ */ + + /** + * Return the event type, as defined by the \c ET_* constants. + */ + uint16_t type() const { return _type; } - quint16 code() const + /** + * Return the event code, as defined by the \c EC_* constants. + */ + uint16_t code() const { return _code; } - quint32 value() const + /** + * Return the value associated with the event. The interpretation + * differs according to event type and code: + * - If the event type is \c ET_KEY, the value specifies which + * key and modifiers were pressed. + * - If the event type is \c ET_BUTTON, the value specifies which + * buttons were pressed and which button generated the event. + * - If the event type is \c ET_POINTER, the value specifies the + * screen coordinates the mouse has moved to. + * - If the event type is \c ET_SPECIAL, the interpretation + * depends on the event code. + */ + uint32_t value() const { return _value; } + /** + * True if the event is a keyboard event. + */ bool isKeyboard() const { return _type == ET_KEY; } + /** + * True if the event is a mouse button event. + */ bool isButton() const { return _type == ET_BUTTON; } + /** + * True if the event is a mouse pointer event. + */ bool isPointer() const { return _type == ET_POINTER; } + /** + * True if the event is a special system event. + */ bool isSpecial() const { return _type == ET_SPECIAL; } + /** + * True if the event is a keyboard or mouse button press event. + */ bool isPress() const { return _code == EC_PRESS; } + /** + * True if the event is a keyboard or mouse button release event. + */ bool isRelease() const { return _code == EC_RELEASE; } - quint16 pressedButton() const + /** + * The mouse button that generated this event. + * \return one of the \c EB_* constants. + */ + uint16_t pressedButton() const { assert(_type == ET_BUTTON); return (_value >> 16); } - quint16 heldButtons() const + /** + * The mouse buttons that were pressed at the moment the + * event was generated. + * \return a bitwise or of \c EB_* constants. + */ + uint16_t heldButtons() const { assert(_type == ET_BUTTON); return (_value & 0xffff); } - quint16 xCoord() const + /** + * The X coordinate the pointer was moved to. + */ + uint16_t xCoord() const { assert(_type == ET_POINTER); return (_value >> 16); } - quint16 yCoord() const + /** + * The Y coordinate the pointer was moved to. + */ + uint16_t yCoord() const { assert(_type == ET_POINTER); return (_value & 0xffff); } + /** + * The key that generated the event, as defined by \ref Qt::Key. + */ + quint32 qtKeysym() const + { + return _value & ~MODIFIER_MASK; + } + + /** + * The modifier keys that were pressed at the moment the event was generated, + * as defined by \ref Qt::KeyboardModifiers. + */ + quint32 qtModifiers() const + { + return _value & MODIFIER_MASK; + } + /* @} */ + + + /** \name Conversion Functions */ + /* @{ */ + + /** + * Converts mouse buttons from the bit flags defined by \ref Qt::MouseButton + * to their internal representation as defined in \ref "Mouse Button Flags". + * \returns A bitwise or of \c EB_* values. + */ + static uint16_t mouseButtonsFromQt(int b); + + /** + * Converts an event type as given by the \c ET_* constants to + * a string. + */ static QString typeToString(quint16 type) { switch(type) @@ -179,6 +307,10 @@ public: } } + /** + * Converts an event code as given by the \c EC_* constants to + * a string. + */ static QString codeToString(quint16 code) { switch(code) @@ -198,20 +330,15 @@ public: } } + /** + * Convert the event to a human-readable representation. + */ QString toString() const { return QString("%1:%2:%3").arg(typeToString(_type)).arg(codeToString(_code)).arg(_value, 8, 16, QLatin1Char('0')); } - quint32 qtKeysym() const - { - return _value & ~MODIFIER_MASK; - } - - quint32 qtModifiers() const - { - return _value & MODIFIER_MASK; - } + /* @} */ // We want to enable InputEvent as a translation context, so we fake the tr method: static QString tr(const char* string) @@ -220,23 +347,51 @@ public: } }; +/** + * The SpecialInputEventDescription class provides a human-readable + * name for special system events. + * + * To use the translations of these descriptions in your program, + * you need to link to the \c libpvsinput library and + * use the \ref USE_PVSINPUT_TRANSLATIONS macro in your + * \c main function. + */ struct SpecialInputEventDescription { + /** + * Initialize an instance of the SpecialInputEventDescription class. + * This is only meant to be called from describeSpecialEvents(). + * If you need to add more special event descriptions, do so from there. + */ SpecialInputEventDescription(quint16 type, quint16 code, quint32 value, QString const& description_) : type(type), code(code), value(value), description(description_) { } + /** \name InputEvent fields + * \see InputEvent + */ + /* @{ */ quint16 type; quint16 code; quint32 value; - QString description; + /* @} */ + + QString description; /**< Human-readable description for a special input event. Can be translated via the + InputEvent::tr(char const*) method. */ + /** + * Returns an \ref InputEvent corresponding to this description. + */ InputEvent toEvent() const { return InputEvent(type, code, value); } + /** + * Returns a \ref QList of all known special system events with their human-readable + * description. + */ static QList describeSpecialEvents(); }; diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index a2e943e..783640f 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -26,11 +26,10 @@ #include "detail/policyChain.h" #include "detail/systemTraits.h" -///////////////////////////////////////////////////////////////////////// -// InputEventContext: -// For handling access control, this specifies who sent the input event. -// This only makes sense in the privileged input handler chain. -///////////////////////////////////////////////////////////////////////// +/** + * For handling access control, this specifies who sent the input event. + * This only really makes sense in the privileged input handler chain. + */ struct InputEventContext { InputEventContext() @@ -38,11 +37,11 @@ struct InputEventContext hasBeenDenied = false; } - virtual pid_t senderPid() const = 0; - virtual uid_t senderUid() const = 0; - virtual gid_t senderGid() const = 0; + virtual pid_t senderPid() const = 0; /**< PID of the sending process */ + virtual uid_t senderUid() const = 0; /**< UID of the sending process */ + virtual gid_t senderGid() const = 0; /**< GID of the sending process */ - // Support the generation of meaningful log messages: + /** Support the generation of meaningful log messages. */ mutable bool hasBeenDenied; }; @@ -61,15 +60,21 @@ namespace input_policy // Policies are tied together using the detail::PolicyChain class. ///////////////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////////////// -// Security Policy: -// At the moment there are two security policies: -// 1. If the user is on a local seat, allow. If the user is privileged, -// allow. Else deny. -// 2. Allow everybody. -// Additional security policies can be added by following the example -// set by AllowLocalOrPrivileged -///////////////////////////////////////////////////////////////////////// +/** + * Security Policy. + * At the moment there are two security policies: + * -* If the user is on a local seat, allow. If the user is privileged, + * allow. Else deny. + * -* Allow everybody. + * + * Additional security policies can be added by following the example + * set by \ref AllowLocalOrPrivileged + * + * \param PolicyImpl The implementation class that security decisions + * should be delegated to. + * \see {AllowLocalOrPrivileged} + * \see {AllowEverybody} + */ template BEGIN_POLICY_CLASS(Security) { @@ -80,25 +85,43 @@ BEGIN_POLICY_CLASS(Security) } END_POLICY_CLASS +/** + * Check the default security model. + */ struct AllowLocalOrPrivileged { static bool allow(InputEventContext const*); }; +/** + * Do not restrict execution. + */ struct AllowEverybody { static bool allow(InputEventContext const*); }; +/** + * Shorthand for unrestricted execution. + */ typedef Security Unprivileged; -///////////////////////////////////////////////////////////////////////// -// System Requirements: -// At the moment, this is trivial, as PVS only runs on Linux. But, -// as porting efforts are already underway, we include the necessary -// machinery anyway. -///////////////////////////////////////////////////////////////////////// +/** + * System Requirements. + * + * At the moment, this is trivial, as PVS only runs on Linux. But, + * as porting efforts are already underway, we include the necessary + * machinery anyway. + * + * \param Trait... a list of system traits that need to be + * present in order for the handler that this policy is applied to + * to run. + */ +#ifdef DOXYGEN_RUNNING +template +#else template +#endif BEGIN_POLICY_CLASS(Require) { static const bool areSystemRequirementsFulfilled = @@ -109,19 +132,27 @@ BEGIN_POLICY_CLASS(Require) } END_POLICY_CLASS -///////////////////////////////////////////////////////////////////////// -// System Requirements: -// At the moment, this is trivial, as PVS only runs on Linux. But, -// as porting efforts are already underway, we include the necessary -// machinery anyway. -///////////////////////////////////////////////////////////////////////// +#ifndef DOXYGEN_RUNNING enum { HANDLER_CODE_DONT_CARE = 0xffff, HANDLER_VALUE_DONT_CARE = 0xffffffff }; - -struct T; - +#endif + +/** + * Event selection. + * + * This policy makes the handler it is applied to applicable if the + * template parameters \c EventType, \c EventCode and \c EventValue + * match the corresponding fields of the incoming \ref InputEvent. + * + * Can be applied multiple times, and will be combined by logical + * OR. + * + * \param EventType Match the \ref InputEvent::type() field. + * \param EventCode (optional:) Match the \ref InputEvent::code() field. + * \param EventValue (optional:) Match the \ref InputEvent::value() field. + */ template @@ -140,6 +171,7 @@ BEGIN_POLICY_CLASS(Match) }; END_POLICY_CLASS +#ifndef DOXYGEN_RUNNING namespace detail { @@ -177,46 +209,71 @@ struct InputEventHandlerPolicyBase } }; -} +} // namespace detail +#endif // DOXYGEN_RUNNING + } -///////////////////////////////////////////////////////////////////////// -// We want a nice non-generic base so we can make a list of polymorphic -// handlers. -// -// The actual handler class need to provide doHandle and can override -// allow and isApplicable. -///////////////////////////////////////////////////////////////////////// +/** + * Base class without template parameters to enable making a list of + * polymorphic event handlers. + * + * The actual handler class needs to provide \ref doHandle and can + * override \ref allow and \ref isApplicable. + * + * \note Do not derive from InputEventHandlerBase to implement + * new event handlers! Derive from InputEventHandler instead. + */ class InputEventHandlerBase { public: enum HandlerStatus { - HANDLER_MATCHED, - HANDLER_NOT_ALLOWED, - HANDLER_NOT_APPLICABLE + HANDLER_MATCHED, /**< The handler matched the input event and was executed. */ + HANDLER_NOT_ALLOWED, /**< Execution of the handler was prevented by security policy. */ + HANDLER_NOT_APPLICABLE /**< The handler did not match the input event. */ }; virtual void initialize() = 0; HandlerStatus handle(InputEvent const& evt, InputEventContext const* context = 0); protected: + /** + * Check security preconditions for the execution of this handler. + * This is normally handled by the \ref input_policy::Security policy. + */ virtual bool allow(InputEvent const& event, InputEventContext const* context = 0) = 0; + + /** + * Check if this handler can handle the incoming input event. + * This is normally handled by the \ref input_policy::Match policy. + */ virtual bool isApplicable(InputEvent const& event, InputEventContext const* context = 0) = 0; + + /** + * Actually handle the incoming event. + * It is assumed that all preconditions have been checked and the handler + * has been initialized at the point where this method is called. + */ virtual void doHandle(InputEvent const& event, InputEventContext const* context = 0) = 0; }; -///////////////////////////////////////////////////////////////////////// -// Now that the machinery is in place, we can finally define what it -// is like to be an input event handler: -///////////////////////////////////////////////////////////////////////// +/** + * Base class for input event handlers. + */ +#ifdef DOXYGEN_RUNNING +template +#else template +#endif class InputEventHandler : public InputEventHandlerBase { +#ifndef DOXYGEN_RUNNING protected: // instantiate our policy: typedef USE_POLICY(input_policy::detail::InputEventHandlerPolicyBase) policy_type; policy_type policy; +#endif public: void initialize() @@ -224,16 +281,11 @@ public: policy.initialize(); } - // Export this so the handler chain can decide whether to include this handler + /** Export this so the handler chain can decide whether to include this handler */ static const bool areSystemRequirementsFulfilled = policy_type::areSystemRequirementsFulfilled; protected: - typedef InputEventHandler super; - - // allow and isApplicable are actually provided by Policy. If the - // handler class wishes to override any of them, the policy implementation - // can be called by means of super. bool allow(InputEvent const&, InputEventContext const* context = 0) { return policy.allow(context); @@ -245,14 +297,19 @@ protected: } }; -///////////////////////////////////////////////////////////////////////// -// And we can chain input handlers together: -///////////////////////////////////////////////////////////////////////// +/** + * Chain \ref InputEventHandler instances together. + * The chain is also responsible for the creation of instances. + * + * \see privilegedInputEventHandlerChain.cpp + * \see unprivilegedInputEventHandlerChain.cpp + */ class InputEventHandlerChain { private: QList handlers; +#ifndef DOXYGEN_RUNNING // Implementation detail ///////////////////////////////////////////////////////////////////////// // We need to statically dispatch on a static member of HandlerType. // Unfortunately, we cannot specialize member functions of a template. @@ -280,18 +337,31 @@ private: { } }; +#endif // DOXYGEN_RUNNING public: - // Add an event handler to the chain. The argument is only for - // compilers which cannot handle template member functions - // correctly. + /** + * Add an event handler to the chain. + * + * \param fake_parameter The parameter is only for + * compilers which cannot handle template member functions + * correctly. + * \return A reference to the receiver, for invocation chaining. + * + * \note Do not pass a value to this function. The function + * handles creation of an instance itself. + */ template - InputEventHandlerChain& add(HandlerType const* = 0) + InputEventHandlerChain& add(HandlerType const* fake_parameter = 0) { ConditionallyAppend::doIt(this); return *this; } + /** + * Call \ref InputEventHandlerBase::initialize() on all + * handlers in the chain. + */ void initialize() { QListIterator i(handlers); @@ -301,6 +371,12 @@ public: } } + /** + * Handle an input event. All handlers in the chain are tried + * in the order they were added, until one handler's + * implementation of InputEventHandlerBase::handle() returns + * InputEventHandlerBase::HANDLER_MATCHED. + */ void handle(InputEvent const& event, InputEventContext const* context = 0) { QListIterator i(handlers); diff --git a/src/input/inputHandlerChains.h b/src/input/inputHandlerChains.h index a91e605..773303b 100644 --- a/src/input/inputHandlerChains.h +++ b/src/input/inputHandlerChains.h @@ -19,7 +19,22 @@ #include "inputEventHandler.h" +/** \defgroup iehc {Input Event Handler Chains} */ +/* @{ */ + +/** + * Make an instance of InputEventHandlerChain that handles + * unprivileged input events, with a PrivilegedInputForwarder + * instance at the end. + */ InputEventHandlerChain makeUnprivilegedInputEventHandlerChain(); + +/** + * Make an instance of InputEventHandlerChain that handles + * privileged events. + */ InputEventHandlerChain makePrivilegedInputEventHandlerChain(); +/* @} */ + #endif /* INPUTHANDLERCHAIN_H_ */ diff --git a/src/input/killX11Handler.h b/src/input/killX11Handler.h index 77d9fdb..6501d5d 100644 --- a/src/input/killX11Handler.h +++ b/src/input/killX11Handler.h @@ -20,11 +20,22 @@ #include #include "inputEventHandler.h" +/** + * Kills the X11 Server on Linux. + */ class KillX11Handler : public InputEventHandler< input_policy::Match, input_policy::Require > { public: + + /** + * Kills the X11 Server on Linux. + * + * The X11-Server is found by asking ConsoleKit for its controlling + * tty. The sole process that has an open file descriptor referencing it + * must be the X Server. It is then sent SIGTERM. + */ void doHandle(InputEvent const&, InputEventContext const*); }; diff --git a/src/input/logNonMatchingHandler.h b/src/input/logNonMatchingHandler.h index 3403640..ab95bce 100644 --- a/src/input/logNonMatchingHandler.h +++ b/src/input/logNonMatchingHandler.h @@ -19,6 +19,9 @@ #include "inputEventHandler.h" +/** + * Send a qWarning() for any InputEvent that does not have a matching handler. + */ class LogNonMatchingHandler : public InputEventHandler { public: diff --git a/src/input/magicSysRqHandler.h b/src/input/magicSysRqHandler.h index ba02997..5afe259 100644 --- a/src/input/magicSysRqHandler.h +++ b/src/input/magicSysRqHandler.h @@ -19,16 +19,20 @@ #include "inputEventHandler.h" +/** + * Emulate the magic SysRq-Key on Linux. + */ class MagicSysRqHandler : public InputEventHandler< input_policy::Match, input_policy::Require > { public: - void doHandle(InputEvent const& evt, InputEventContext const* ctx); -// static void describeInto(QList& list) -// { -// } + /** + * Send the least significant byte of \c evt's InputEvent::value() + * to the magic \c /proc/sysrq-trigger file. + */ + void doHandle(InputEvent const& evt, InputEventContext const* ctx); }; #endif /* MAGICSYSRQHANDLER_H_ */ diff --git a/src/input/privilegedHandlerForwarder.h b/src/input/privilegedHandlerForwarder.h index f5a6cc3..ea3326a 100644 --- a/src/input/privilegedHandlerForwarder.h +++ b/src/input/privilegedHandlerForwarder.h @@ -19,12 +19,25 @@ #include "inputEventHandler.h" +/** + * Forward the incoming InputEvent to \c pvsprivinputd. + */ class PrivilegedHandlerForwarder : public InputEventHandler< input_policy::Require, input_policy::Unprivileged> { public: + + /** + * Forward \c evt to \c pvsprivinputd, taking care that + * the security context is correctly sent. + */ void doHandle(InputEvent const& evt, InputEventContext const* = 0); + + /** + * Read the address of \c pvsprivinputd's listening socket + * from its configuration and connect to it. + */ void initialize(); private: diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h index 92c68fe..37c4c04 100644 --- a/src/input/pvsCheckPrivileges.h +++ b/src/input/pvsCheckPrivileges.h @@ -26,6 +26,9 @@ #include #include "inputEventHandler.h" +/** + * Store the information in an InputEventContext as a plain old datatype. + */ struct CachedInputContext { CachedInputContext(InputEventContext const* source) @@ -69,16 +72,37 @@ uint qHash(CachedInputContext const& p); class QFileSystemWatcher; +/** + * Check user privileges and handle communications with ConsoleKit and PolicyKit. + * This is a singleton class. + */ class PVSCheckPrivileges : public QObject { Q_OBJECT public: + /** + * SessionKind distinguishes between local and remote users. + */ typedef enum { - SESSION_LOCAL, - SESSION_NONLOCAL, - SESSION_LOOKUP_FAILURE, - SESSION_UNKNOWN + SESSION_LOCAL, /**< User is local */ + SESSION_NONLOCAL, /**< User is remote */ + SESSION_LOOKUP_FAILURE, /**< Failure to look up whether the user is local or remote */ + SESSION_UNKNOWN /**< User session kind not (yet) known */ } SessionKind; + + /** + * UserPrivilege distinguishes between privileged and unprivileged users. + */ + typedef enum { + USER_PRIVILEGED, /**< User is privileged */ + USER_UNPRIVILEGED, /**< User is unprivileged */ + USER_LOOKUP_FAILURE, /**< Failure to look up whether the user is privileged or unprivileged */ + USER_UNKNOWN /**< User privilege level not (yet) known */ + } UserPrivilege; + + /** \name Conversion Functions */ + /* @{ */ + static QString toString(SessionKind k) { switch(k) @@ -91,12 +115,6 @@ public: } } - typedef enum { - USER_PRIVILEGED, - USER_UNPRIVILEGED, - USER_LOOKUP_FAILURE, - USER_UNKNOWN - } UserPrivilege; static QString toString(UserPrivilege k) { switch(k) @@ -109,13 +127,40 @@ public: } } + /* @} */ + + /** \name Singleton pattern */ + /* @{ */ + + /** Retrieve the singleton instance. */ static PVSCheckPrivileges* instance(); + + /** Delete the singleton instance. */ static void deleteInstance(); + /* @} */ + + /** \name Privilege Checks */ + /* @{ */ + + /** Check for a minimum SessionKind level. \return true if the requirement is fulfilled. */ bool require(SessionKind sessionKind, CachedInputContext const& sender); + + /** Check for a minimum UserPrivilege level. \return true if the requirement is fulfilled. */ bool require(UserPrivilege userPrivilege, CachedInputContext const& sender); + + /** Check for a minimum SessionKind and UserPrivilege level. \return true if both requirements are fulfilled. */ bool require(SessionKind sessionKind, UserPrivilege userPrivilege, CachedInputContext const& sender); + + /* @} */ + + /** \name Session Information */ + /* @{ */ + + /** Retrieve the name of the user's X session, according to ConsoleKit. */ QString getX11SessionName(CachedInputContext const& sender); + + /** Retrieve the TTY device of the user's X session, according to ConsoleKit. */ QString getX11DisplayDevice(CachedInputContext const& sender); public slots: diff --git a/src/input/pvsPrivInputHandler.h b/src/input/pvsPrivInputHandler.h index e82787b..015dfa1 100644 --- a/src/input/pvsPrivInputHandler.h +++ b/src/input/pvsPrivInputHandler.h @@ -24,10 +24,19 @@ class QSocketNotifier; +/** + * Handle socket communication with instances of the PVS Client Daemon. + * + * \note This runs in the context of a Qt main loop. It does not start + * a handler thread. + */ class PVSPrivInputHandler : public QObject { Q_OBJECT public: + /** + * Listen for InputEvents on file descriptor \c fd. + */ PVSPrivInputHandler(int fd, QObject* parent = 0); virtual ~PVSPrivInputHandler(); diff --git a/src/input/pvsPrivInputSignalHandler.h b/src/input/pvsPrivInputSignalHandler.h index cb75c86..bc549ec 100644 --- a/src/input/pvsPrivInputSignalHandler.h +++ b/src/input/pvsPrivInputSignalHandler.h @@ -19,6 +19,19 @@ #include +/** + * Handle signals. + * + * This class reads \c int values from a file descriptor and dispatches sends + * Qt signals according to the \c SIG... value the integer represents. + * The purpose of this mechanism is to integrate (asynchronous) Unix signal + * handling into the synchronous event-driven Qt main loop. The main() function + * is expected to open a socket pair and install handlers for all relevant signals + * that simply write the number of the signal to that pipe. + * + * If allowUnauthenticatedKilling() has not been called, this class only accepts + * signal numbers that are sent by the same process. + */ class PVSPrivInputSignalHandler : public QObject { Q_OBJECT @@ -28,16 +41,20 @@ public: { } + /** If \c value is \c true, allow sending signal numbers from other processes. */ void allowUnauthenticatedKilling(bool value) { _allowUnauthenticatedKilling = value; } public slots: + /** Connect this slot to a \c QSocketNotifier's \c activated(int) signal. */ void signalReceived(int sigfd); signals: + /** SIGTERM */ void terminate(); + /** SIGHUP */ void reloadConfiguration(); private: diff --git a/src/input/pvsPrivInputSocket.h b/src/input/pvsPrivInputSocket.h index 447360b..a57d730 100644 --- a/src/input/pvsPrivInputSocket.h +++ b/src/input/pvsPrivInputSocket.h @@ -24,14 +24,52 @@ class QSettings; +/** + * Load \c pvsprivinputd's configuration. This keeps a cached copy. + */ QSettings* pvsPrivInputGetSettings(); + +/** + * Update the cached configuration copy kept by pvsPrivInputGetSettings(). + */ QSettings* pvsPrivInputReopenSettings(); + +/** + * Hardcoded to \c /etc/pvsprivinputd.conf + */ QString pvsPrivInputGetSettingsPath(); + +/** + * Retrieve the path at which \c pvsprivinputd listens for datagrams from + * its configuration. + */ QString pvsPrivInputGetSocketAddress(); + +/** + * Enable the receiving of sender credentials on a \c unix(7) socket. + */ bool pvsPrivInputEnableReceiveCredentials(int sock); + +/** + * Make a \c unix(7) socket that is suitable for sending authenticated + * datagrams to \c pvsprivinputd. + */ int pvsPrivInputMakeClientSocket(); + +/** + * Make a listening \c unix(7) socket at the address specified by + * pvsPrivInputGetSocketAddress() that receives sender credentials. + */ int pvsPrivInputMakeServerSocket(); + +/** + * Send an authenticated message on a \c unix(7) socket. + */ bool pvsPrivInputSendMessage(int sock, void* buf, size_t len, int* err = 0); + +/** + * Receive an authenticated message on a \c unix(7) socket. + */ bool pvsPrivInputRecvMessage(int sock, void* buf, size_t& len, pid_t& pid, uid_t& uid, gid_t& gid, int* err = 0); #endif /* PVSPRIVINPUTSOCKET_H_ */ diff --git a/src/input/pvsSyslog.h b/src/input/pvsSyslog.h index 8c9591a..36ee2e0 100644 --- a/src/input/pvsSyslog.h +++ b/src/input/pvsSyslog.h @@ -20,6 +20,9 @@ #include #include +/** + * Listen on a socket or a pipe and redirect input lines to a child class. + */ class PVSLogRedirector : public QObject { Q_OBJECT @@ -33,6 +36,9 @@ private: QByteArray _buf; }; +/** + * Redirect log lines to a Unix syslog service. + */ class PVSSyslogRedirector : public PVSLogRedirector { public: @@ -46,6 +52,9 @@ protected: class QFile; class QTextStream; +/** + * Redirect log lines to a file. + */ class PVSLogfileRedirector : public PVSLogRedirector { public: diff --git a/src/input/rebootSystemHandler.h b/src/input/rebootSystemHandler.h index 4920452..357dcad 100644 --- a/src/input/rebootSystemHandler.h +++ b/src/input/rebootSystemHandler.h @@ -20,10 +20,16 @@ #include #include "inputEventHandler.h" +/** + * Reboot a Linux system. + */ class RebootLinuxSystemHandler : public InputEventHandler< input_policy::Require > { public: + /** + * Send SIGINT to the process with PID 1. + */ void doHandle(InputEvent const&, InputEventContext const*); }; diff --git a/src/input/sayHelloHandler.h b/src/input/sayHelloHandler.h index 00463ca..24118cf 100644 --- a/src/input/sayHelloHandler.h +++ b/src/input/sayHelloHandler.h @@ -20,6 +20,10 @@ #include #include "inputEventHandler.h" +/** + * Write a line to the log stating the PID, UID and GID of the + * PVS Client Daemon. + */ class SayHelloHandler : public InputEventHandler< input_policy::Match, input_policy::Security > diff --git a/src/input/x11FakeKeyboardHandler.h b/src/input/x11FakeKeyboardHandler.h index 6c18dce..7f2d12e 100644 --- a/src/input/x11FakeKeyboardHandler.h +++ b/src/input/x11FakeKeyboardHandler.h @@ -19,6 +19,13 @@ #include "inputEventHandler.h" +/** + * Send keyboard events via the XTest extension. + * This is unbelievably brittle in the face of non-system-standard keyboard + * mappings. Every Linux distribution seems to set up XTest handling in + * a different way. The code goes out of its way to find a usable mapping + * and use it. + */ class X11FakeKeyboardHandler : public InputEventHandler< input_policy::Match, input_policy::Match, diff --git a/src/input/x11FakeMouseHandler.h b/src/input/x11FakeMouseHandler.h index 9d41c31..2700829 100644 --- a/src/input/x11FakeMouseHandler.h +++ b/src/input/x11FakeMouseHandler.h @@ -19,6 +19,9 @@ #include "inputEventHandler.h" +/** + * Send mouse button events via the XTest extension. + */ class X11FakeMouseButtonHandler : public InputEventHandler< input_policy::Match, input_policy::Require, @@ -28,6 +31,9 @@ public: void doHandle(InputEvent const&, InputEventContext const* = 0); }; +/** + * Send mouse pointer events via the XTest extension. + */ class X11FakeMouseMovementHandler : public InputEventHandler< input_policy::Match, input_policy::Require, diff --git a/src/input/x11InputUtils.h b/src/input/x11InputUtils.h index 9c85d09..94b3116 100644 --- a/src/input/x11InputUtils.h +++ b/src/input/x11InputUtils.h @@ -19,6 +19,9 @@ #include +/** + * Store the X11 Display. + */ struct X11InputUtils { static void setDisplay(Display*); static Display* display(); -- cgit v1.2.3-55-g7522