summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Braun2010-11-04 00:38:24 +0100
committerSebastien Braun2010-11-04 00:38:24 +0100
commit4fcc0efae9738bb28922da592fff78cfef50277b (patch)
treeb3855b36abe874606a802ec75fc573543d2d7b35
parent[PVSMGRTOUCH] resetall bug fixed (diff)
parentDocumentation fixes and code cleanup (diff)
downloadpvs-4fcc0efae9738bb28922da592fff78cfef50277b.tar.gz
pvs-4fcc0efae9738bb28922da592fff78cfef50277b.tar.xz
pvs-4fcc0efae9738bb28922da592fff78cfef50277b.zip
Merge input handling work to master
-rw-r--r--CMakeLists.txt7
-rw-r--r--INSTALL2
-rw-r--r--doc/doxconf10
-rw-r--r--i18n/pvsmgr_ar_JO.ts118
-rw-r--r--i18n/pvsmgr_de_DE.ts118
-rw-r--r--i18n/pvsmgr_es_MX.ts118
-rw-r--r--i18n/pvsmgr_fr_FR.ts118
-rw-r--r--i18n/pvsmgr_pl_PL.ts118
-rw-r--r--src/gui/frame.cpp57
-rw-r--r--src/gui/frame.h3
-rw-r--r--src/gui/mainWindow.cpp119
-rw-r--r--src/gui/mainWindow.h2
-rw-r--r--src/input/CMakeLists.txt73
-rw-r--r--src/input/allowLocalOrPrivileged.cpp21
-rw-r--r--src/input/detail/Makefile.autogen5
-rw-r--r--src/input/detail/gen/gen_typeList.cpp118
-rw-r--r--src/input/detail/policyChain.h74
-rw-r--r--src/input/detail/systemTraits.h94
-rw-r--r--src/input/detail/typeList.h76
-rw-r--r--src/input/detail/typeList_autogen.h62
-rw-r--r--src/input/i18n.h33
-rw-r--r--src/input/i18n/pvsinput_ar_JO.ts147
-rw-r--r--src/input/i18n/pvsinput_de_DE.ts165
-rw-r--r--src/input/i18n/pvsinput_es_MX.ts147
-rw-r--r--src/input/i18n/pvsinput_fr_FR.ts147
-rw-r--r--src/input/i18n/pvsinput_pl_PL.ts147
-rw-r--r--src/input/incompatibleHandler.h37
-rw-r--r--src/input/inputEvent.cpp68
-rw-r--r--src/input/inputEvent.h315
-rw-r--r--src/input/inputEventHandler.cpp21
-rw-r--r--src/input/inputEventHandler.h499
-rw-r--r--src/input/inputHandlerChain.h49
-rw-r--r--src/input/inputHandlerChains.h40
-rw-r--r--src/input/killX11Handler.cpp6
-rw-r--r--src/input/killX11Handler.h20
-rw-r--r--src/input/logNonMatchingHandler.cpp27
-rw-r--r--src/input/logNonMatchingHandler.h36
-rw-r--r--src/input/magicSysRqHandler.cpp2
-rw-r--r--src/input/magicSysRqHandler.h56
-rw-r--r--src/input/org.openslx.pvs.input.policy4
-rw-r--r--src/input/privilegedHandlerForwarder.cpp4
-rw-r--r--src/input/privilegedHandlerForwarder.h19
-rw-r--r--src/input/privilegedInputHandlerChain.cpp32
-rw-r--r--src/input/pvsCheckPrivileges.h71
-rw-r--r--src/input/pvsPrivInputHandler.cpp30
-rw-r--r--src/input/pvsPrivInputHandler.h13
-rw-r--r--src/input/pvsPrivInputSignalHandler.h17
-rw-r--r--src/input/pvsPrivInputSocket.h38
-rw-r--r--src/input/pvsSyslog.h9
-rw-r--r--src/input/pvsprivinputd.cpp4
-rw-r--r--src/input/pvsprivinputd.gentooinit.in37
-rw-r--r--src/input/pvsprivinputd.lsbinit.in152
-rw-r--r--src/input/rebootSystemHandler.cpp2
-rw-r--r--src/input/rebootSystemHandler.h16
-rw-r--r--src/input/sayHelloHandler.cpp4
-rw-r--r--src/input/sayHelloHandler.h15
-rw-r--r--src/input/unprivilegedInputHandlerChain.cpp34
-rw-r--r--src/input/x11FakeKeyboardHandler.cpp957
-rw-r--r--src/input/x11FakeKeyboardHandler.h15
-rw-r--r--src/input/x11FakeMouseHandler.cpp4
-rw-r--r--src/input/x11FakeMouseHandler.h20
-rw-r--r--src/input/x11InputUtils.h3
-rwxr-xr-xsrc/pvs.cpp20
-rwxr-xr-xsrc/pvs.h5
-rw-r--r--src/pvsmgr.cpp3
-rw-r--r--src/pvsmgrtouch.cpp3
66 files changed, 3196 insertions, 1610 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c111ebc..4eeaea8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -106,13 +106,6 @@ SET( PVSMGR_SRCS
src/gui/processesStartDialog.cpp
src/gui/processWidget.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
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
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/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
@@ -334,124 +334,6 @@ Perform an unprojection or remove remote help to get a target.</source>
</message>
</context>
<context>
- <name>InputEventHandler</name>
- <message>
- <location filename="../src/input/killX11Handler.h" line="30"/>
- <source>Kill X Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="29"/>
- <source>Reboot immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="31"/>
- <source>Crash system</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="33"/>
- <source>Show all held logs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="35"/>
- <source>Send SIGTERM to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="37"/>
- <source>Activate OOM killer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="39"/>
- <source>Send SIGKILL to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="41"/>
- <source>Force thaw filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="43"/>
- <source>Kill all on terminal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="45"/>
- <source>Show stack traces</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="47"/>
- <source>Dump memory info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="49"/>
- <source>Make real-time tasks niceable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="51"/>
- <source>Power off immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="53"/>
- <source>Dump registers and flags</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="55"/>
- <source>Dump timers and clockevents</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="57"/>
- <source>Turn off raw keyboard mode</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="59"/>
- <source>Sync all mounted filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="61"/>
- <source>Dump task list</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="63"/>
- <source>Remount all read-only</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="65"/>
- <source>Dump uninterruptible tasks</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="67"/>
- <source>Dump ftrace buffer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/rebootSystemHandler.h" line="30"/>
- <source>Reboot</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/sayHelloHandler.h" line="30"/>
- <source>Say Hello</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>MainWindow</name>
<message>
<location filename="../build/ui_mainwindow.h" line="418"/>
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
@@ -334,124 +334,6 @@ Perform an unprojection or remove remote help to get a target.</source>
</message>
</context>
<context>
- <name>InputEventHandler</name>
- <message>
- <location filename="../src/input/killX11Handler.h" line="30"/>
- <source>Kill X Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="29"/>
- <source>Reboot immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="31"/>
- <source>Crash system</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="33"/>
- <source>Show all held logs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="35"/>
- <source>Send SIGTERM to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="37"/>
- <source>Activate OOM killer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="39"/>
- <source>Send SIGKILL to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="41"/>
- <source>Force thaw filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="43"/>
- <source>Kill all on terminal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="45"/>
- <source>Show stack traces</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="47"/>
- <source>Dump memory info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="49"/>
- <source>Make real-time tasks niceable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="51"/>
- <source>Power off immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="53"/>
- <source>Dump registers and flags</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="55"/>
- <source>Dump timers and clockevents</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="57"/>
- <source>Turn off raw keyboard mode</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="59"/>
- <source>Sync all mounted filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="61"/>
- <source>Dump task list</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="63"/>
- <source>Remount all read-only</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="65"/>
- <source>Dump uninterruptible tasks</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="67"/>
- <source>Dump ftrace buffer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/rebootSystemHandler.h" line="30"/>
- <source>Reboot</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/sayHelloHandler.h" line="30"/>
- <source>Say Hello</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>MainWindow</name>
<message>
<location filename="../build/ui_mainwindow.h" line="418"/>
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
@@ -334,124 +334,6 @@ Perform an unprojection or remove remote help to get a target.</source>
</message>
</context>
<context>
- <name>InputEventHandler</name>
- <message>
- <location filename="../src/input/killX11Handler.h" line="30"/>
- <source>Kill X Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="29"/>
- <source>Reboot immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="31"/>
- <source>Crash system</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="33"/>
- <source>Show all held logs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="35"/>
- <source>Send SIGTERM to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="37"/>
- <source>Activate OOM killer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="39"/>
- <source>Send SIGKILL to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="41"/>
- <source>Force thaw filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="43"/>
- <source>Kill all on terminal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="45"/>
- <source>Show stack traces</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="47"/>
- <source>Dump memory info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="49"/>
- <source>Make real-time tasks niceable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="51"/>
- <source>Power off immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="53"/>
- <source>Dump registers and flags</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="55"/>
- <source>Dump timers and clockevents</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="57"/>
- <source>Turn off raw keyboard mode</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="59"/>
- <source>Sync all mounted filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="61"/>
- <source>Dump task list</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="63"/>
- <source>Remount all read-only</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="65"/>
- <source>Dump uninterruptible tasks</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="67"/>
- <source>Dump ftrace buffer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/rebootSystemHandler.h" line="30"/>
- <source>Reboot</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/sayHelloHandler.h" line="30"/>
- <source>Say Hello</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>MainWindow</name>
<message>
<location filename="../build/ui_mainwindow.h" line="418"/>
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
@@ -334,124 +334,6 @@ Perform an unprojection or remove remote help to get a target.</source>
</message>
</context>
<context>
- <name>InputEventHandler</name>
- <message>
- <location filename="../src/input/killX11Handler.h" line="30"/>
- <source>Kill X Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="29"/>
- <source>Reboot immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="31"/>
- <source>Crash system</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="33"/>
- <source>Show all held logs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="35"/>
- <source>Send SIGTERM to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="37"/>
- <source>Activate OOM killer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="39"/>
- <source>Send SIGKILL to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="41"/>
- <source>Force thaw filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="43"/>
- <source>Kill all on terminal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="45"/>
- <source>Show stack traces</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="47"/>
- <source>Dump memory info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="49"/>
- <source>Make real-time tasks niceable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="51"/>
- <source>Power off immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="53"/>
- <source>Dump registers and flags</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="55"/>
- <source>Dump timers and clockevents</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="57"/>
- <source>Turn off raw keyboard mode</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="59"/>
- <source>Sync all mounted filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="61"/>
- <source>Dump task list</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="63"/>
- <source>Remount all read-only</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="65"/>
- <source>Dump uninterruptible tasks</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="67"/>
- <source>Dump ftrace buffer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/rebootSystemHandler.h" line="30"/>
- <source>Reboot</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/sayHelloHandler.h" line="30"/>
- <source>Say Hello</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>MainWindow</name>
<message>
<location filename="../build/ui_mainwindow.h" line="418"/>
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
@@ -334,124 +334,6 @@ Perform an unprojection or remove remote help to get a target.</source>
</message>
</context>
<context>
- <name>InputEventHandler</name>
- <message>
- <location filename="../src/input/killX11Handler.h" line="30"/>
- <source>Kill X Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="29"/>
- <source>Reboot immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="31"/>
- <source>Crash system</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="33"/>
- <source>Show all held logs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="35"/>
- <source>Send SIGTERM to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="37"/>
- <source>Activate OOM killer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="39"/>
- <source>Send SIGKILL to all</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="41"/>
- <source>Force thaw filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="43"/>
- <source>Kill all on terminal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="45"/>
- <source>Show stack traces</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="47"/>
- <source>Dump memory info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="49"/>
- <source>Make real-time tasks niceable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="51"/>
- <source>Power off immediately</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="53"/>
- <source>Dump registers and flags</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="55"/>
- <source>Dump timers and clockevents</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="57"/>
- <source>Turn off raw keyboard mode</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="59"/>
- <source>Sync all mounted filesystems</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="61"/>
- <source>Dump task list</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="63"/>
- <source>Remount all read-only</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="65"/>
- <source>Dump uninterruptible tasks</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/magicSysRqHandler.h" line="67"/>
- <source>Dump ftrace buffer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/rebootSystemHandler.h" line="30"/>
- <source>Reboot</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../src/input/sayHelloHandler.h" line="30"/>
- <source>Say Hello</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
<name>MainWindow</name>
<message>
<location filename="../build/ui_mainwindow.h" line="418"/>
diff --git a/src/gui/frame.cpp b/src/gui/frame.cpp
index 1b80c3d..561f3ce 100644
--- a/src/gui/frame.cpp
+++ b/src/gui/frame.cpp
@@ -19,7 +19,6 @@
*/
#include <src/input/inputEvent.h>
-#include <src/input/inputHandlerChain.h>
#include "frame.h"
#include <src/gui/mainWindow.h>
#include <iostream>
@@ -48,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()));
@@ -334,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()
@@ -378,6 +383,12 @@ void Frame::setDozent()
}
}
+void Frame::setCloseUp(bool value)
+{
+ _isCloseUp = value;
+ button_closeUp->setChecked(value);
+}
+
void Frame::remoteControlClicked()
{
if(_remoteControlEnabled)
@@ -434,19 +445,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);
}
}
@@ -519,7 +529,30 @@ 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)
+ {
+ 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() == (char)key || c.toUpper().toLatin1() == (char)key)
+ {
+ // We found a Latin1 char and pray it is the correct case.
+ key = c.cell();
+ }
+ }
+ }
+ sendInputEvent(InputEvent::keyboardPress(key, event->modifiers()));
}
}
else
@@ -592,14 +625,14 @@ void Frame::showSpecialEventMenu()
{
qDebug("Trying to show menu...");
QMenu* menu = new QMenu(this);
- QList<SpecialInputEventDescription> specialEvents = privileged_handler_chain::describe();
- QList<SpecialInputEventDescription>::iterator iter;
+ QList<SpecialInputEventDescription> specialEvents = SpecialInputEventDescription::describeSpecialEvents();
+ QListIterator<SpecialInputEventDescription> 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/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 b6878e8..1376851 100644
--- a/src/gui/mainWindow.cpp
+++ b/src/gui/mainWindow.cpp
@@ -99,7 +99,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
@@ -715,61 +715,82 @@ void MainWindow::closeUp()
{
std::list<QString>* 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<QString>* 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 28f82f7..58787ed 100644
--- a/src/gui/mainWindow.h
+++ b/src/gui/mainWindow.h
@@ -178,6 +178,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();
diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt
index 20fd531..26eeb64 100644
--- a/src/input/CMakeLists.txt
+++ b/src/input/CMakeLists.txt
@@ -2,17 +2,32 @@ include(${QT_USE_FILE})
set(pvsinput_SRCS
inputEvent.cpp
+ unprivilegedInputHandlerChain.cpp
+ inputEventHandler.cpp
+ logNonMatchingHandler.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
@@ -23,7 +38,8 @@ if(UNIX)
killX11Handler.cpp
magicSysRqHandler.cpp
sayHelloHandler.cpp
- inputEventHandler.cpp
+ privilegedInputHandlerChain.cpp
+ allowLocalOrPrivileged.cpp
)
set(pvsprivinputd_MOC_HDRS
@@ -105,10 +121,55 @@ 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_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
+ 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"
+ "<RCC version='1.0'><qresource prefix='/i18n/pvsinput'>")
+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"
+ "<file alias='${qm_basename}'>${qm_rel}</file>")
+endforeach()
+file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/pvsinput.qrc" "</qresource></RCC>")
+
+qt4_add_resources(pvsinput_RCS
+ "${CMAKE_CURRENT_BINARY_DIR}/pvsinput.qrc")
+
add_library(
pvsinput
STATIC
${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/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..cbd52be
--- /dev/null
+++ b/src/input/detail/Makefile.autogen
@@ -0,0 +1,5 @@
+all : typeList_autogen.h
+.PHONY : all
+
+typeList_autogen.h : gen/gen_typeList
+ gen/gen_typeList > typeList_autogen.h
diff --git a/src/input/detail/gen/gen_typeList.cpp b/src/input/detail/gen/gen_typeList.cpp
new file mode 100644
index 0000000..21056f9
--- /dev/null
+++ b/src/input/detail/gen/gen_typeList.cpp
@@ -0,0 +1,118 @@
+/*
+ # 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 <iostream>
+
+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<typename Needle, typename Haystack>\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;
+
+ cout << "template<typename Needle";
+ for(j = 0; j < NUM_MAX_ENTRIES; j++)
+ {
+ if(j == i)
+ continue;
+ cout << ", typename T" << j;
+ }
+ cout << ">\nstruct Contains<Needle, TypeList<";
+ for(j = 0; j < NUM_MAX_ENTRIES; j++)
+ {
+ if(j)
+ cout << ", ";
+ if(j == i)
+ cout << "Needle";
+ else
+ cout << "T" << j;
+ }
+ cout << "> >\n{ static const int index = " << i << "; static const bool value = true; };\n";
+ }
+ cout << "#endif\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<IMPLICIT_TYPE_LIST_ARGS(prefix) >\n";
+
+ return 0;
+}
diff --git a/src/input/detail/policyChain.h b/src/input/detail/policyChain.h
new file mode 100644
index 0000000..efaf371
--- /dev/null
+++ b/src/input/detail/policyChain.h
@@ -0,0 +1,74 @@
+/*
+ # 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<typename BaseCase, typename PolicyList>
+struct PolicyChain : public PolicyList::head::template apply_<PolicyChain<BaseCase, typename PolicyList::tail> >
+{
+};
+
+template<typename BaseCase>
+struct PolicyChain<BaseCase, EmptyList> : public BaseCase
+{
+};
+
+}
+}
+
+/////////////////////////////////////////////////////////////////////////
+// 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<typename NextPolicy> \
+ 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<POLICY_PARAMS>
+// struct MyPolicyBasedClass
+// {
+// typedef USE_POLICY(baseCase) policy_type;
+// };
+//
+// now, the following type is valid:
+// MyPolicyBasedClass<Policy1, Policy2>
+/////////////////////////////////////////////////////////////////////////
+#define POLICY_PARAMS IMPLICIT_TYPE_LIST_PARAMS(Policy)
+#define POLICY_PARAMS_LIST IMPLICIT_TYPE_LIST(Policy)
+#define USE_POLICY(baseCase) ::input_policy::detail::PolicyChain<baseCase, POLICY_PARAMS_LIST>
+
+#endif /* POLICYCHAIN_H_ */
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<IMPLICIT_TYPE_LIST_PARAMS(T)>
+struct AllOf;
+
+template<IMPLICIT_TYPE_LIST_PARAMS(T)>
+struct AnyOf;
+
+namespace detail
+{
+/////////////////////////////////////////////////////////////////////////
+// Does the list of system traits match what we have given?
+/////////////////////////////////////////////////////////////////////////
+template<typename Needles, typename Haystack>
+struct Matches
+{
+ // if Needles is neither AnyOf<...> nor AllOf<...>
+ // then we need to know if the Haystack contains it:
+ static const bool value = Contains<Needles, Haystack>::value;
+};
+
+template<typename Haystack>
+struct MatchesPredicate
+{
+ template<typename Needle>
+ struct apply
+ {
+ static const bool value = Matches<Needle, Haystack>::value;
+ };
+};
+
+template<IMPLICIT_TYPE_LIST_PARAMS_NODEFAULT(T), typename Haystack>
+struct Matches<AnyOf<IMPLICIT_TYPE_LIST_ARGS(T)>, Haystack>
+{
+ static const bool value = ForAnyInTypeList<MatchesPredicate<Haystack>, IMPLICIT_TYPE_LIST(T)>::value;
+};
+
+template<IMPLICIT_TYPE_LIST_PARAMS_NODEFAULT(T), typename Haystack>
+struct Matches<AllOf<IMPLICIT_TYPE_LIST_ARGS(T)>, Haystack>
+{
+ static const bool value = ForAllInTypeList<MatchesPredicate<Haystack>, 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<Predicate, List>::value == true
+// if there is any entry E in List for which
+// Predicate::apply<E>::value == true
+/////////////////////////////////////////////////////////////////////////
+template<typename Predicate, typename List>
+struct ForAnyInTypeList
+{
+ static const bool value =
+ Predicate::template apply<typename List::head>::value ||
+ ForAnyInTypeList<Predicate, typename List::tail>::value;
+};
+
+template<typename Predicate>
+struct ForAnyInTypeList<Predicate, EmptyList>
+{
+ static const bool value = false;
+};
+
+/////////////////////////////////////////////////////////////////////////
+// ForAllInTypeList<Predicate, List>::value == true
+// if there is not any entry E in List for which
+// Predicate::apply<E>::value == false
+/////////////////////////////////////////////////////////////////////////
+template<typename Predicate, typename List>
+struct ForAllInTypeList
+{
+ static const bool value =
+ Predicate::template apply<typename List::head>::value &&
+ ForAllInTypeList<Predicate, typename List::tail>::value;
+};
+
+template<typename Predicate>
+struct ForAllInTypeList<Predicate, EmptyList>
+{
+ 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..79f1335
--- /dev/null
+++ b/src/input/detail/typeList_autogen.h
@@ -0,0 +1,62 @@
+template<typename T0 = void, typename T1 = void, typename T2 = void, typename T3 = void, typename T4 = void, typename T5 = void, typename T6 = void, typename T7 = void, typename T8 = void, typename T9 = void, typename T10 = void, typename T11 = void, typename T12 = void, typename T13 = void, typename T14 = void, typename T15 = void>
+struct TypeList {
+typedef T0 head;
+typedef TypeList<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, void > tail;
+};
+template<typename Needle, typename Haystack>
+struct Contains { static const int index = -1; static const bool value = false; };
+#ifndef DOXYGEN_RUNNING
+template<typename Needle, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<Needle, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 0; static const bool value = true; };
+template<typename Needle, typename T0, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, Needle, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 1; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, Needle, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 2; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, Needle, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 3; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, Needle, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 4; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, Needle, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 5; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, Needle, T7, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 6; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, Needle, T8, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 7; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, Needle, T9, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 8; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, Needle, T10, T11, T12, T13, T14, T15> >
+{ static const int index = 9; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T11, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, Needle, T11, T12, T13, T14, T15> >
+{ static const int index = 10; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T12, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, Needle, T12, T13, T14, T15> >
+{ static const int index = 11; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T13, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, Needle, T13, T14, T15> >
+{ static const int index = 12; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T14, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, Needle, T14, T15> >
+{ static const int index = 13; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T15>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, Needle, T15> >
+{ static const int index = 14; static const bool value = true; };
+template<typename Needle, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14>
+struct Contains<Needle, TypeList<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, Needle> >
+{ static const int index = 15; static const bool value = true; };
+#endif
+typedef TypeList<void, void, void, void, void, void, void, void, void, void, void, void, void, void, void, void > 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<IMPLICIT_TYPE_LIST_ARGS(prefix) >
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 <QCoreApplication>
+#include <QLocale>
+#include <QTranslator>
+
+#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..bf25eda
--- /dev/null
+++ b/src/input/i18n/pvsinput_ar_JO.ts
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="ar_JO">
+<context>
+ <name>InputEvent</name>
+ <message>
+ <location filename="../inputEvent.cpp" line="131"/>
+ <source>Say Hello</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="132"/>
+ <source>Reboot</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="133"/>
+ <source>Kill X Server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="134"/>
+ <source>Reboot immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="135"/>
+ <source>Power off immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="136"/>
+ <source>Crash System</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="137"/>
+ <source>Turn off raw keyboard mode</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="138"/>
+ <source>Send SIGTERM to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="139"/>
+ <source>Send SIGKILL to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="140"/>
+ <source>Kill all on this terminal</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="141"/>
+ <source>Activate OOM killer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="142"/>
+ <source>Make real-time tasks niceable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="143"/>
+ <source>Force-thaw filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="144"/>
+ <source>Sync all mounted filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="145"/>
+ <source>Remount all readonly</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="146"/>
+ <source>Show all held locks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="147"/>
+ <source>Show stack traces</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="148"/>
+ <source>Dump memory info</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="149"/>
+ <source>Dump registers and flags</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="150"/>
+ <source>Dump timers and clockevents</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="151"/>
+ <source>Dump task list</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="152"/>
+ <source>Dump uninterruptible tasks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="153"/>
+ <source>Dump ftrace buffer</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../pvsprivinputd.cpp" line="66"/>
+ <source>Usage: %1 [--help|-h] [--daemon|-d] [--log=&lt;Logger&gt;|-l&lt;Logger&gt;]
+
+Options:
+ --help, -h Show this message
+ --daemon, -d Run in background
+ --log=&lt;Logger&gt;,
+ -l&lt;Logger&gt; Redirect all output to &lt;Logger&gt;
+ valid values are:
+ - any file name
+ - `syslog&apos; to redirect output to the system log
+ - `null&apos; 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
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/src/input/i18n/pvsinput_de_DE.ts b/src/input/i18n/pvsinput_de_DE.ts
new file mode 100644
index 0000000..002016a
--- /dev/null
+++ b/src/input/i18n/pvsinput_de_DE.ts
@@ -0,0 +1,165 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="de_DE">
+<context>
+ <name>InputEvent</name>
+ <message>
+ <location filename="../inputEvent.cpp" line="131"/>
+ <source>Say Hello</source>
+ <translation>Hallo sagen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="132"/>
+ <source>Reboot</source>
+ <translation>Neustart</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="133"/>
+ <source>Kill X Server</source>
+ <translation>X-Server töten</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="134"/>
+ <source>Reboot immediately</source>
+ <translation>Sofort neu starten</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="135"/>
+ <source>Power off immediately</source>
+ <translation>Sofort abschalten</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="136"/>
+ <source>Crash System</source>
+ <translation>Systemabsturz</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="137"/>
+ <source>Turn off raw keyboard mode</source>
+ <translation>RAW-Tastatur-Modus abschalten</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="138"/>
+ <source>Send SIGTERM to all</source>
+ <translation>SIGTERM an alle Prozesse senden</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="139"/>
+ <source>Send SIGKILL to all</source>
+ <translation>SIGKILL an alle Prozesse senden</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="140"/>
+ <source>Kill all on this terminal</source>
+ <translation>Alle Prozesse an diesem Terminal töten</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="141"/>
+ <source>Activate OOM killer</source>
+ <translation>OOM-Killer aktivieren</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="142"/>
+ <source>Make real-time tasks niceable</source>
+ <translation>Nice für Echtzeitprozesse ermöglichen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="143"/>
+ <source>Force-thaw filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="144"/>
+ <source>Sync all mounted filesystems</source>
+ <translation>Alle eingebundenen Dateisysteme sync(2)en</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="145"/>
+ <source>Remount all readonly</source>
+ <translation>Alle Dateisysteme nur-lesbar mounten</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="146"/>
+ <source>Show all held locks</source>
+ <translation>Alle gehaltenen Sperren zeigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="147"/>
+ <source>Show stack traces</source>
+ <translation>Stacktraces anzigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="148"/>
+ <source>Dump memory info</source>
+ <translation>Speicherinfo anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="149"/>
+ <source>Dump registers and flags</source>
+ <translation>Register und Flags anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="150"/>
+ <source>Dump timers and clockevents</source>
+ <translation>Timer und Clockevents anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="151"/>
+ <source>Dump task list</source>
+ <translation>Taskliste anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="152"/>
+ <source>Dump uninterruptible tasks</source>
+ <translation>Ununterbrechbare Tasks anzeigen</translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="153"/>
+ <source>Dump ftrace buffer</source>
+ <translation>ftrace-Puffer anzeigen</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../pvsprivinputd.cpp" line="66"/>
+ <source>Usage: %1 [--help|-h] [--daemon|-d] [--log=&lt;Logger&gt;|-l&lt;Logger&gt;]
+
+Options:
+ --help, -h Show this message
+ --daemon, -d Run in background
+ --log=&lt;Logger&gt;,
+ -l&lt;Logger&gt; Redirect all output to &lt;Logger&gt;
+ valid values are:
+ - any file name
+ - `syslog&apos; to redirect output to the system log
+ - `null&apos; 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
+</source>
+ <translation>Verwendung: %1 [--help|-h] [--daemon|-d] [--log=&lt;Logger&gt;|-l&lt;Logger&gt;]
+
+Optionen:
+ --help, -h Diese Nachricht anzeigen
+ --daemon, -d Im Hintergrund laufen
+ --log=&lt;Logger&gt;,
+ -l&lt;Logger&gt; Alle Ausgaben an &lt;Logger&gt; weiterleiten
+ Mögliche Werte für &lt;Logger&gt;:
+ - Ein Dateiname
+ - `syslog&apos;, um Ausgaben an das Systemlog zu leiten
+ - `null&apos;, 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
+</translation>
+ </message>
+</context>
+</TS>
diff --git a/src/input/i18n/pvsinput_es_MX.ts b/src/input/i18n/pvsinput_es_MX.ts
new file mode 100644
index 0000000..d805d0e
--- /dev/null
+++ b/src/input/i18n/pvsinput_es_MX.ts
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="es_MX">
+<context>
+ <name>InputEvent</name>
+ <message>
+ <location filename="../inputEvent.cpp" line="131"/>
+ <source>Say Hello</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="132"/>
+ <source>Reboot</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="133"/>
+ <source>Kill X Server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="134"/>
+ <source>Reboot immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="135"/>
+ <source>Power off immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="136"/>
+ <source>Crash System</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="137"/>
+ <source>Turn off raw keyboard mode</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="138"/>
+ <source>Send SIGTERM to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="139"/>
+ <source>Send SIGKILL to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="140"/>
+ <source>Kill all on this terminal</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="141"/>
+ <source>Activate OOM killer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="142"/>
+ <source>Make real-time tasks niceable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="143"/>
+ <source>Force-thaw filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="144"/>
+ <source>Sync all mounted filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="145"/>
+ <source>Remount all readonly</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="146"/>
+ <source>Show all held locks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="147"/>
+ <source>Show stack traces</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="148"/>
+ <source>Dump memory info</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="149"/>
+ <source>Dump registers and flags</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="150"/>
+ <source>Dump timers and clockevents</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="151"/>
+ <source>Dump task list</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="152"/>
+ <source>Dump uninterruptible tasks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="153"/>
+ <source>Dump ftrace buffer</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../pvsprivinputd.cpp" line="66"/>
+ <source>Usage: %1 [--help|-h] [--daemon|-d] [--log=&lt;Logger&gt;|-l&lt;Logger&gt;]
+
+Options:
+ --help, -h Show this message
+ --daemon, -d Run in background
+ --log=&lt;Logger&gt;,
+ -l&lt;Logger&gt; Redirect all output to &lt;Logger&gt;
+ valid values are:
+ - any file name
+ - `syslog&apos; to redirect output to the system log
+ - `null&apos; 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
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/src/input/i18n/pvsinput_fr_FR.ts b/src/input/i18n/pvsinput_fr_FR.ts
new file mode 100644
index 0000000..af231ea
--- /dev/null
+++ b/src/input/i18n/pvsinput_fr_FR.ts
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="fr_FR">
+<context>
+ <name>InputEvent</name>
+ <message>
+ <location filename="../inputEvent.cpp" line="131"/>
+ <source>Say Hello</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="132"/>
+ <source>Reboot</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="133"/>
+ <source>Kill X Server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="134"/>
+ <source>Reboot immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="135"/>
+ <source>Power off immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="136"/>
+ <source>Crash System</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="137"/>
+ <source>Turn off raw keyboard mode</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="138"/>
+ <source>Send SIGTERM to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="139"/>
+ <source>Send SIGKILL to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="140"/>
+ <source>Kill all on this terminal</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="141"/>
+ <source>Activate OOM killer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="142"/>
+ <source>Make real-time tasks niceable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="143"/>
+ <source>Force-thaw filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="144"/>
+ <source>Sync all mounted filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="145"/>
+ <source>Remount all readonly</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="146"/>
+ <source>Show all held locks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="147"/>
+ <source>Show stack traces</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="148"/>
+ <source>Dump memory info</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="149"/>
+ <source>Dump registers and flags</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="150"/>
+ <source>Dump timers and clockevents</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="151"/>
+ <source>Dump task list</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="152"/>
+ <source>Dump uninterruptible tasks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="153"/>
+ <source>Dump ftrace buffer</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../pvsprivinputd.cpp" line="66"/>
+ <source>Usage: %1 [--help|-h] [--daemon|-d] [--log=&lt;Logger&gt;|-l&lt;Logger&gt;]
+
+Options:
+ --help, -h Show this message
+ --daemon, -d Run in background
+ --log=&lt;Logger&gt;,
+ -l&lt;Logger&gt; Redirect all output to &lt;Logger&gt;
+ valid values are:
+ - any file name
+ - `syslog&apos; to redirect output to the system log
+ - `null&apos; 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
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/src/input/i18n/pvsinput_pl_PL.ts b/src/input/i18n/pvsinput_pl_PL.ts
new file mode 100644
index 0000000..11365c0
--- /dev/null
+++ b/src/input/i18n/pvsinput_pl_PL.ts
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.0" language="pl_PL">
+<context>
+ <name>InputEvent</name>
+ <message>
+ <location filename="../inputEvent.cpp" line="131"/>
+ <source>Say Hello</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="132"/>
+ <source>Reboot</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="133"/>
+ <source>Kill X Server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="134"/>
+ <source>Reboot immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="135"/>
+ <source>Power off immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="136"/>
+ <source>Crash System</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="137"/>
+ <source>Turn off raw keyboard mode</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="138"/>
+ <source>Send SIGTERM to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="139"/>
+ <source>Send SIGKILL to all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="140"/>
+ <source>Kill all on this terminal</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="141"/>
+ <source>Activate OOM killer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="142"/>
+ <source>Make real-time tasks niceable</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="143"/>
+ <source>Force-thaw filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="144"/>
+ <source>Sync all mounted filesystems</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="145"/>
+ <source>Remount all readonly</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="146"/>
+ <source>Show all held locks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="147"/>
+ <source>Show stack traces</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="148"/>
+ <source>Dump memory info</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="149"/>
+ <source>Dump registers and flags</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="150"/>
+ <source>Dump timers and clockevents</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="151"/>
+ <source>Dump task list</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="152"/>
+ <source>Dump uninterruptible tasks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location filename="../inputEvent.cpp" line="153"/>
+ <source>Dump ftrace buffer</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <location filename="../pvsprivinputd.cpp" line="66"/>
+ <source>Usage: %1 [--help|-h] [--daemon|-d] [--log=&lt;Logger&gt;|-l&lt;Logger&gt;]
+
+Options:
+ --help, -h Show this message
+ --daemon, -d Run in background
+ --log=&lt;Logger&gt;,
+ -l&lt;Logger&gt; Redirect all output to &lt;Logger&gt;
+ valid values are:
+ - any file name
+ - `syslog&apos; to redirect output to the system log
+ - `null&apos; 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
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
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<incompatible::Incompatible> >
+{
+ void doHandle(InputEvent const&, InputEventContext const*);
+};
+
+
+#endif /* INCOMPATIBLEHANDLERTYPE_H_ */
diff --git a/src/input/inputEvent.cpp b/src/input/inputEvent.cpp
index 9b69a3a..cff1ac8 100644
--- a/src/input/inputEvent.cpp
+++ b/src/input/inputEvent.cpp
@@ -1,12 +1,22 @@
/*
- * 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 <QBuffer>
#include <QByteArray>
+#include <QCoreApplication>
#include <QDataStream>
#include <QKeyEvent>
#include <QMouseEvent>
@@ -15,18 +25,29 @@
#include <src/util/consoleLogger.h>
// 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_;
+ 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_;
+ 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;
@@ -37,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!
@@ -97,3 +122,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, description))
+
+QList<SpecialInputEventDescription> SpecialInputEventDescription::describeSpecialEvents()
+{
+ QList<SpecialInputEventDescription> list;
+ 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 7a64bfc..afb33e5 100644
--- a/src/input/inputEvent.h
+++ b/src/input/inputEvent.h
@@ -18,19 +18,26 @@
#define INPUTEVENT_H_
#include <cassert>
-#include <string>
-#include <sstream>
-#include <stdint.h>
-
-#ifndef __linux
-# error "This will only run on a Linux system. Porting is required for other systems."
-#endif
+#include <QCoreApplication> // for translation
+#include <QString>
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:
@@ -40,125 +47,250 @@ 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) : type_(type), code_(code), value_(value)
+ InputEvent(quint16 type, quint16 code, quint32 value = 0) : _type(type), _code(code), _value(value)
{
}
- InputEvent()
+ InputEvent(InputEvent const& other) : _type(other._type), _code(other._code), _value(other._value)
{
}
- static InputEvent mouseMotion(uint16_t x, uint16_t y)
+ InputEvent()
{
- return InputEvent(ET_POINTER, 0, ((uint32_t)x << 16) | y);
}
- static uint16_t 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 uint16_t ET_KEY = 0;
- static const uint16_t ET_BUTTON = 1;
- static const uint16_t ET_POINTER = 2;
- static const uint16_t ET_SPECIAL = 3;
-
- static const uint16_t EC_PRESS = 0;
- static const uint16_t EC_RELEASE = 1;
- static const uint16_t EC_REBOOT = 2;
- static const uint16_t EC_SYSRQ = 3;
- static const uint16_t EC_KILL_X = 4;
- static const uint16_t EC_SAY_HELLO = 5; //< for debugging purposes
-
- typedef uint32_t event_key;
+ /**
+ * 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 uint32_t event_key_modifiers;
+ /**
+ * 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);
- static const uint16_t EB_LEFT = 1;
- static const uint16_t EB_MIDDLE = 2;
- static const uint16_t EB_RIGHT = 4;
+ /**
+ * 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 uint32_t MODIFIER_MASK =
+ /* @} */
+
+ /** \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;
+ /** \name Event Decoding Functions */
+ /* @{ */
+
+ /**
+ * Return the event type, as defined by the \c ET_* constants.
+ */
uint16_t type() const
{
- return type_;
+ return _type;
}
+ /**
+ * Return the event code, as defined by the \c EC_* constants.
+ */
uint16_t code() const
{
- return code_;
+ return _code;
}
+ /**
+ * 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_;
+ return _value;
}
+ /**
+ * True if the event is a keyboard event.
+ */
bool isKeyboard() const
{
- return type_ == ET_KEY;
+ return _type == ET_KEY;
}
+ /**
+ * True if the event is a mouse button event.
+ */
bool isButton() const
{
- return type_ == ET_BUTTON;
+ return _type == ET_BUTTON;
}
+ /**
+ * True if the event is a mouse pointer event.
+ */
bool isPointer() const
{
- return type_ == ET_POINTER;
+ return _type == ET_POINTER;
}
+ /**
+ * True if the event is a special system event.
+ */
bool isSpecial() const
{
- return type_ == ET_SPECIAL;
+ return _type == ET_SPECIAL;
}
+ /**
+ * True if the event is a keyboard or mouse button press event.
+ */
bool isPress() const
{
- return code_ == EC_PRESS;
+ return _code == EC_PRESS;
}
+ /**
+ * True if the event is a keyboard or mouse button release event.
+ */
bool isRelease() const
{
- return code_ == EC_RELEASE;
+ return _code == EC_RELEASE;
}
+ /**
+ * 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);
+ assert(_type == ET_BUTTON);
+ return (_value >> 16);
}
+ /**
+ * 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);
+ assert(_type == ET_BUTTON);
+ return (_value & 0xffff);
}
+ /**
+ * The X coordinate the pointer was moved to.
+ */
uint16_t xCoord() const
{
- assert(type_ == ET_POINTER);
- return (value_ >> 16);
+ assert(_type == ET_POINTER);
+ return (_value >> 16);
}
+ /**
+ * The Y coordinate the pointer was moved to.
+ */
uint16_t yCoord() const
{
- assert(type_ == ET_POINTER);
- return (value_ & 0xffff);
+ assert(_type == ET_POINTER);
+ return (_value & 0xffff);
}
- static std::string typeToString(uint16_t type)
+ /**
+ * 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)
{
@@ -171,13 +303,15 @@ 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)
+ /**
+ * Converts an event code as given by the \c EC_* constants to
+ * a string.
+ */
+ static QString codeToString(quint16 code)
{
switch(code)
{
@@ -192,28 +326,73 @@ 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
+ /**
+ * Convert the event to a human-readable representation.
+ */
+ 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, 8, 16, QLatin1Char('0'));
}
- uint32_t qt_keysym() const
+ /* @} */
+
+ // We want to enable InputEvent as a translation context, so we fake the tr method:
+ static QString tr(const char* string)
{
- return value_ & ~MODIFIER_MASK;
+ return QCoreApplication::translate("InputEvent", string);
}
+};
- uint32_t qt_modifiers() const
+/**
+ * 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_)
{
- return value_ & MODIFIER_MASK;
}
+
+ /** \name InputEvent fields
+ * \see InputEvent
+ */
+ /* @{ */
+ quint16 type;
+ quint16 code;
+ quint32 value;
+ /* @} */
+
+ 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<SpecialInputEventDescription> 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..783640f 100644
--- a/src/input/inputEventHandler.h
+++ b/src/input/inputEventHandler.h
@@ -22,274 +22,377 @@
#include <QList>
#include <QString>
#include <QCoreApplication>
-#include <boost/mpl/contains.hpp>
-#include <boost/mpl/if.hpp>
-#include <boost/mpl/vector.hpp>
#include <src/input/inputEvent.h>
+#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
+/**
+ * For handling access control, this specifies who sent the input event.
+ * This only really makes sense in the privileged input handler chain.
+ */
+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 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 */
- InputEvent toEvent() const
- {
- return InputEvent(evtType, evtCode, evtValue);
- }
+ /** Support the generation of meaningful log messages. */
+ mutable bool hasBeenDenied;
};
-template<quint16 Type = HANDLER_TYPE_DONT_CARE,
- quint16 Code = HANDLER_CODE_DONT_CARE,
- quint32 Value = HANDLER_VALUE_DONT_CARE>
-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;
- }
-
- virtual void initialize()
- {
- }
-
- virtual void handle(InputEvent const& evt, InputEventContext const*) = 0;
+namespace input_policy
+{
- static void describeInto(QList<SpecialInputEventDescription>& description)
+/////////////////////////////////////////////////////////////////////////
+// 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:
+ * -* 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<typename PolicyImpl>
+BEGIN_POLICY_CLASS(Security)
+{
+ bool allow(InputEventContext const* context)
{
+ return PolicyImpl::allow(context);
}
-};
-
-namespace policy {
-
-enum SecurityFlags {
- SEC_FREE_FOR_ALL,
- SEC_PHYSICAL_OR_PRIVILEGED
-};
-
-bool allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx);
-bool allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx);
+}
+END_POLICY_CLASS
-struct SecurityAllowAny
+/**
+ * Check the default security model.
+ */
+struct AllowLocalOrPrivileged
{
- bool allow(InputEvent const& evt, InputEventContext const* ctx)
- {
- return true;
- }
+ static bool allow(InputEventContext const*);
};
-struct SecurityAllowPhysicalOrPrivileged
+/**
+ * Do not restrict execution.
+ */
+struct AllowEverybody
{
- bool allow(InputEvent const& evt, InputEventContext const* ctx)
- {
- if(allowPhysicalSeat(evt, ctx))
- return true;
- else if(allowPrivilegedUser(evt, ctx))
- return true;
- return false;
- }
+ static bool allow(InputEventContext const*);
};
-struct UnixLike;
-struct Linux;
-struct Windows;
-
-#if defined(__linux)
-typedef boost::mpl::vector2<UnixLike,Linux>::type Systems;
-#elif defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
-typedef boost::mpl::vector1<Windows>::type Systems;
+/**
+ * Shorthand for unrestricted execution.
+ */
+typedef Security<AllowEverybody> 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.
+ *
+ * \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<typename Trait...>
#else
-# error "Porting is needed!"
+template<IMPLICIT_TYPE_LIST_PARAMS(Trait)>
#endif
-
-struct SystemEnabled;
-struct SystemDisabled;
-
-template<typename System>
-struct RequireSystem
+BEGIN_POLICY_CLASS(Require)
{
- typedef typename boost::mpl::contains<Systems, System>::type enabled_type;
- static const bool enabled = enabled_type::value;
+ static const bool areSystemRequirementsFulfilled =
+ (NextPolicy::areSystemRequirementsFulfilled
+ && !NextPolicy::areSystemRequirementsVacuouslyFulfilled)
+ || detail::Matches<AllOf<IMPLICIT_TYPE_LIST_ARGS(Trait)>, detail::SystemTraits>::value;
+ static const bool areSystemRequirementsVacuouslyFulfilled = false;
+}
+END_POLICY_CLASS
+
+#ifndef DOXYGEN_RUNNING
+enum {
+ HANDLER_CODE_DONT_CARE = 0xffff,
+ HANDLER_VALUE_DONT_CARE = 0xffffffff
};
+#endif
-struct RequireNoSystem
+/**
+ * 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<unsigned short EventType,
+ unsigned short EventCode = HANDLER_CODE_DONT_CARE,
+ unsigned int EventValue = HANDLER_VALUE_DONT_CARE>
+BEGIN_POLICY_CLASS(Match)
{
- typedef boost::mpl::bool_<true>::type enabled_type;
- static const bool enabled = enabled_type::value;
+ bool isApplicable(InputEvent const& evt)
+ {
+ 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
-}
+#ifndef DOXYGEN_RUNNING
+namespace detail
+{
-template<bool Enabled, typename Delegate, typename SecurityPolicy>
-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<SpecialInputEventDescription>& list)
- {
- Delegate::describeInto(list);
- }
+ // A handler that does not specify requirements works
+ // everywhere
+ static const bool areSystemRequirementsFulfilled = true;
-private:
- Delegate delegate;
- SecurityPolicy securityPolicy;
-};
+ // We need this to implement proper logical OR
+ static const bool areSystemRequirementsVacuouslyFulfilled = true;
-template<typename Delegate, typename SecurityPolicy>
-class HandlerHelper<false, Delegate, SecurityPolicy>
-{
-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<SpecialInputEventDescription>&)
- {
- }
};
-template<typename Delegate, typename SystemPolicy = policy::RequireNoSystem, typename SecurityPolicy = void>
-struct Handler : public HandlerHelper<SystemPolicy::enabled, Delegate, SecurityPolicy>
-{
-};
+} // namespace detail
+#endif // DOXYGEN_RUNNING
-template<typename DefaultSecurityPolicy, typename HandlerType>
-struct ApplyDefaultSecurityPolicy
-{
- typedef HandlerType type;
-};
+}
-template<typename DefaultSecurityPolicy, typename Delegate, typename SystemPolicy>
-struct ApplyDefaultSecurityPolicy<DefaultSecurityPolicy, Handler<Delegate, SystemPolicy, void> >
+/**
+ * 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
{
- typedef Handler<Delegate, SystemPolicy, DefaultSecurityPolicy> type;
-};
+public:
+ enum HandlerStatus
+ {
+ 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. */
+ };
-template<typename DefaultSecurityPolicy, typename Begin, typename End>
-struct InputEventHandlerChainHelper
-{
-private:
- typedef typename boost::mpl::next<Begin>::type next_iterator_type;
- typedef InputEventHandlerChainHelper<DefaultSecurityPolicy, next_iterator_type, End> next_in_chain;
+ virtual void initialize() = 0;
+ HandlerStatus handle(InputEvent const& evt, InputEventContext const* context = 0);
- typedef typename boost::mpl::deref<Begin>::type handler_entry_type;
- typedef typename ApplyDefaultSecurityPolicy<DefaultSecurityPolicy, handler_entry_type>::type handler_type;
+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;
+};
- handler_type _handler;
- next_in_chain _next;
+/**
+ * Base class for input event handlers.
+ */
+#ifdef DOXYGEN_RUNNING
+template<typename Policy...>
+#else
+template<POLICY_PARAMS>
+#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 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:
- static void describeInto(QList<SpecialInputEventDescription>& list)
+ bool allow(InputEvent const&, InputEventContext const* context = 0)
{
- handler_type::describeInto(list);
- next_in_chain::describeInto(list);
+ return policy.allow(context);
}
- static QList<SpecialInputEventDescription> describe()
+ bool isApplicable(InputEvent const& event, InputEventContext const* = 0)
{
- QList<SpecialInputEventDescription> list;
- describeInto(list);
- return list;
+ return policy.isApplicable(event);
}
};
-template<typename DefaultSecurityPolicy, typename End>
-struct InputEventHandlerChainHelper<DefaultSecurityPolicy, End, End>
+/**
+ * Chain \ref InputEventHandler instances together.
+ * The chain is also responsible for the creation of instances.
+ *
+ * \see privilegedInputEventHandlerChain.cpp
+ * \see unprivilegedInputEventHandlerChain.cpp
+ */
+class InputEventHandlerChain
{
- void handle(InputEvent const&, InputEventContext const* context = 0) {
- // do nothing
- }
+private:
+ QList<InputEventHandlerBase*> 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.
+ // So, we need to make this a class with a static non-template member.
+ /////////////////////////////////////////////////////////////////////////
+ template<bool Compatible, typename HandlerType>
+ 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);
+ }
+ };
- void initialize() {
- // do nothing
- }
+ template<typename HandlerType>
+ struct ConditionallyAppend<false, HandlerType>
+ {
+ static void doIt(InputEventHandlerChain*)
+ {
+ }
+ };
+#endif // DOXYGEN_RUNNING
- static void describeInto(QList<SpecialInputEventDescription>&)
+public:
+ /**
+ * 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<typename HandlerType>
+ InputEventHandlerChain& add(HandlerType const* fake_parameter = 0)
{
- // do nothing
+ ConditionallyAppend<HandlerType::areSystemRequirementsFulfilled, HandlerType>::doIt(this);
+ return *this;
}
- static QList<SpecialInputEventDescription> describe()
+ /**
+ * Call \ref InputEventHandlerBase::initialize() on all
+ * handlers in the chain.
+ */
+ void initialize()
{
- return QList<SpecialInputEventDescription>();
+ QListIterator<InputEventHandlerBase*> i(handlers);
+ while(i.hasNext())
+ {
+ i.next()->initialize();
+ }
}
-};
-template<typename DefaultSecurityPolicy, typename Collection>
-struct InputEventHandlerChain :
- public InputEventHandlerChainHelper<DefaultSecurityPolicy,
- typename boost::mpl::begin<Collection>::type,
- typename boost::mpl::end<Collection>::type>
-{
+ /**
+ * 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<InputEventHandlerBase*> i(handlers);
+ while(i.hasNext())
+ {
+ switch(i.next()->handle(event, context))
+ {
+ case InputEventHandlerBase::HANDLER_MATCHED:
+ return;
+ 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 <boost/mpl/list.hpp>
-#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<X11FakeKeyboardHandler, policy::RequireSystem<policy::UnixLike> >,
- Handler<X11FakeMouseButtonHandler, policy::RequireSystem<policy::UnixLike> >,
- Handler<X11FakeMouseMovementHandler, policy::RequireSystem<policy::UnixLike> >,
- Handler<PrivilegedHandlerForwarder>
->::type unprivileged_handler_list;
-
-typedef InputEventHandlerChain<policy::SecurityAllowAny, unprivileged_handler_list> unprivileged_handler_chain;
-
-typedef boost::mpl::list<
- Handler<SayHelloHandler, policy::RequireNoSystem, policy::SecurityAllowAny >,
- Handler<KillX11Handler, policy::RequireSystem<policy::Linux> >,
- Handler<RebootLinuxSystemHandler, policy::RequireSystem<policy::Linux> >,
- Handler<MagicSysRqHandler, policy::RequireSystem<policy::Linux> >
->::type privileged_handler_list;
-
-typedef InputEventHandlerChain<policy::SecurityAllowPhysicalOrPrivileged, privileged_handler_list> privileged_handler_chain;
-
-#endif /* INPUTHANDLERCHAIN_H_ */
diff --git a/src/input/inputHandlerChains.h b/src/input/inputHandlerChains.h
new file mode 100644
index 0000000..773303b
--- /dev/null
+++ b/src/input/inputHandlerChains.h
@@ -0,0 +1,40 @@
+/*
+ # 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"
+
+/** \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.cpp b/src/input/killX11Handler.cpp
index 7ac75a1..8fa8c24 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);
@@ -33,7 +33,7 @@ void KillX11Handler::handle(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;
}
@@ -85,5 +85,5 @@ void KillX11Handler::handle(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);
}
diff --git a/src/input/killX11Handler.h b/src/input/killX11Handler.h
index 2f3ef44..6501d5d 100644
--- a/src/input/killX11Handler.h
+++ b/src/input/killX11Handler.h
@@ -20,15 +20,23 @@
#include <QCoreApplication>
#include "inputEventHandler.h"
-class KillX11Handler : public DefaultInputEventHandler<InputEvent::ET_SPECIAL, InputEvent::EC_KILL_X>
+/**
+ * Kills the X11 Server on Linux.
+ */
+class KillX11Handler : public InputEventHandler<
+ input_policy::Match<InputEvent::ET_SPECIAL, InputEvent::EC_KILL_X>,
+ input_policy::Require<input_policy::LinuxSystem> >
{
public:
- void handle(InputEvent const&, InputEventContext const*);
- static void describeInto(QList<SpecialInputEventDescription>& list)
- {
- list << SpecialInputEventDescription(tr(QT_TRANSLATE_NOOP("InputEventHandler", "Kill X Server")), InputEvent::ET_SPECIAL, InputEvent::EC_KILL_X);
- }
+ /**
+ * 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*);
};
#endif /* KILLX11HANDLER_H_ */
diff --git a/src/input/logNonMatchingHandler.cpp b/src/input/logNonMatchingHandler.cpp
new file mode 100644
index 0000000..b0aa93a
--- /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 <QtDebug>
+
+void LogNonMatchingHandler::doHandle(InputEvent const& event, InputEventContext const* context)
+{
+ // It's not really nonmatched if it has already been denied
+ if(!context || !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..ab95bce
--- /dev/null
+++ b/src/input/logNonMatchingHandler.h
@@ -0,0 +1,36 @@
+/*
+# 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"
+
+/**
+ * Send a qWarning() for any InputEvent that does not have a matching handler.
+ */
+class LogNonMatchingHandler : public InputEventHandler<input_policy::Unprivileged>
+{
+public:
+ bool isApplicable(InputEvent const&, InputEventContext const*)
+ {
+ return true;
+ }
+
+ void doHandle(InputEvent const&, InputEventContext const*);
+};
+
+#endif /* LOGNONMATCHINGHANDLER_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 <QFile>
#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..5afe259 100644
--- a/src/input/magicSysRqHandler.h
+++ b/src/input/magicSysRqHandler.h
@@ -19,54 +19,20 @@
#include "inputEventHandler.h"
-class MagicSysRqHandler : public DefaultInputEventHandler<InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ>
+/**
+ * Emulate the magic SysRq-Key on Linux.
+ */
+class MagicSysRqHandler : public InputEventHandler<
+ input_policy::Match<InputEvent::ET_SPECIAL, InputEvent::EC_SYSRQ>,
+ input_policy::Require<input_policy::LinuxSystem> >
{
public:
- void handle(InputEvent const& evt, InputEventContext const* ctx);
- static void describeInto(QList<SpecialInputEventDescription>& 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');
- }
+ /**
+ * 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/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 @@
<description>Use privileged input actions in PVS</description>
<message>Authentication is required to let PVS use privileged input actions</message>
<defaults>
- <allow_inactive>auth_self_keep</allow_inactive>
- <allow_active>auth_self_keep</allow_active>
+ <allow_inactive>auth_admin_keep</allow_inactive>
+ <allow_active>auth_admin_keep</allow_active>
<allow_any>auth_admin_keep</allow_any>
</defaults>
</action>
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..ea3326a 100644
--- a/src/input/privilegedHandlerForwarder.h
+++ b/src/input/privilegedHandlerForwarder.h
@@ -19,10 +19,25 @@
#include "inputEventHandler.h"
-class PrivilegedHandlerForwarder : public DefaultInputEventHandler<InputEvent::ET_SPECIAL>
+/**
+ * Forward the incoming InputEvent to \c pvsprivinputd.
+ */
+class PrivilegedHandlerForwarder : public InputEventHandler<
+ input_policy::Require<input_policy::UnixLike>,
+ input_policy::Unprivileged>
{
public:
- void handle(InputEvent const& evt, InputEventContext const* = 0);
+
+ /**
+ * 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/privilegedInputHandlerChain.cpp b/src/input/privilegedInputHandlerChain.cpp
new file mode 100644
index 0000000..c1e8629
--- /dev/null
+++ b/src/input/privilegedInputHandlerChain.cpp
@@ -0,0 +1,32 @@
+/*
+ # 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"
+#include "logNonMatchingHandler.h"
+
+InputEventHandlerChain makePrivilegedInputEventHandlerChain()
+{
+ return InputEventHandlerChain().add<RebootLinuxSystemHandler>()
+ .add<SayHelloHandler>()
+ .add<KillX11Handler>()
+ .add<MagicSysRqHandler>()
+ .add<LogNonMatchingHandler>();
+}
diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h
index 62b463c..37c4c04 100644
--- a/src/input/pvsCheckPrivileges.h
+++ b/src/input/pvsCheckPrivileges.h
@@ -26,15 +26,18 @@
#include <QHash>
#include "inputEventHandler.h"
+/**
+ * Store the information in an InputEventContext as a plain old datatype.
+ */
struct CachedInputContext
{
CachedInputContext(InputEventContext const* source)
{
if(source)
{
- pid = source->getSenderPid();
- uid = source->getSenderUid();
- gid = source->getSenderGid();
+ pid = source->senderPid();
+ uid = source->senderUid();
+ gid = source->senderGid();
}
else
{
@@ -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.cpp b/src/input/pvsPrivInputHandler.cpp
index 70ed1bc..d33697a 100644
--- a/src/input/pvsPrivInputHandler.cpp
+++ b/src/input/pvsPrivInputHandler.cpp
@@ -21,7 +21,7 @@
#include <QtDebug>
#include <QSocketNotifier>
#include "inputEvent.h"
-#include "inputEventHandler.h"
+#include "inputHandlerChains.h"
#include "pvsPrivInputSocket.h"
#include "pvsPrivInputHandler.h"
@@ -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;
}
@@ -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()
@@ -85,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/pvsPrivInputHandler.h b/src/input/pvsPrivInputHandler.h
index 9980cdf..015dfa1 100644
--- a/src/input/pvsPrivInputHandler.h
+++ b/src/input/pvsPrivInputHandler.h
@@ -20,14 +20,23 @@
#include <QObject>
#include <QHash>
#include <QPointer>
-#include "inputHandlerChain.h"
+#include "inputEventHandler.h"
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();
@@ -39,7 +48,7 @@ private:
QByteArray _messageAssembly;
int _bytes;
int _fd;
- privileged_handler_chain _handlerChain;
+ InputEventHandlerChain _handlerChain;
};
#endif /* PVSPRIVINPUTHANDLER_H_ */
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 <QObject>
+/**
+ * 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 <QObject>
#include <QString>
+/**
+ * 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/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)
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 <sebastien@sebbraun.de>
+#
+# 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
+
+:
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..357dcad 100644
--- a/src/input/rebootSystemHandler.h
+++ b/src/input/rebootSystemHandler.h
@@ -20,15 +20,17 @@
#include <QCoreApplication>
#include "inputEventHandler.h"
-class RebootLinuxSystemHandler : public DefaultInputEventHandler<InputEvent::ET_SPECIAL, InputEvent::EC_REBOOT>
+/**
+ * Reboot a Linux system.
+ */
+class RebootLinuxSystemHandler : public InputEventHandler<
+ input_policy::Require<input_policy::LinuxSystem> >
{
public:
- void handle(InputEvent const&, InputEventContext const*);
-
- static void describeInto(QList<SpecialInputEventDescription>& list)
- {
- list << SpecialInputEventDescription(tr(QT_TRANSLATE_NOOP("InputEventHandler", "Reboot")), InputEvent::ET_SPECIAL, InputEvent::EC_REBOOT);
- }
+ /**
+ * Send SIGINT to the process with PID 1.
+ */
+ void doHandle(InputEvent const&, InputEventContext const*);
};
#endif /* REBOOTSYSTEMHANDLER_H_ */
diff --git a/src/input/sayHelloHandler.cpp b/src/input/sayHelloHandler.cpp
index fc6f668..301709f 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;
+ cerr << "I'm right here! You sent this message from pid " << ctx->senderPid() << " as user " << ctx->senderUid() << " with gid " << ctx->senderGid() << endl;
}
diff --git a/src/input/sayHelloHandler.h b/src/input/sayHelloHandler.h
index b0d4c7e..24118cf 100644
--- a/src/input/sayHelloHandler.h
+++ b/src/input/sayHelloHandler.h
@@ -20,15 +20,16 @@
#include <QCoreApplication>
#include "inputEventHandler.h"
-class SayHelloHandler : public DefaultInputEventHandler<InputEvent::ET_SPECIAL, InputEvent::EC_SAY_HELLO>
+/**
+ * Write a line to the log stating the PID, UID and GID of the
+ * PVS Client Daemon.
+ */
+class SayHelloHandler : public InputEventHandler<
+ input_policy::Match<InputEvent::ET_SPECIAL, InputEvent::EC_SAY_HELLO>,
+ input_policy::Security<input_policy::AllowEverybody> >
{
public:
- void handle(InputEvent const&, InputEventContext const*);
-
- static void describeInto(QList<SpecialInputEventDescription>& 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..3f47631
--- /dev/null
+++ b/src/input/unprivilegedInputHandlerChain.cpp
@@ -0,0 +1,34 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # privilegedInputHandlerChain.cpp
+ # - Definition of the input handler chains - implementation for
+ # unprivileged chain
+ # --------------------------------------------------------------------------
+ */
+
+#include "x11FakeKeyboardHandler.h"
+#include "x11FakeMouseHandler.h"
+#include "privilegedHandlerForwarder.h"
+#include "incompatibleHandler.h"
+#include "inputHandlerChains.h"
+#include "logNonMatchingHandler.h"
+
+InputEventHandlerChain makeUnprivilegedInputEventHandlerChain()
+{
+ return InputEventHandlerChain().add<X11FakeKeyboardHandler>()
+ .add<X11FakeMouseButtonHandler>()
+ .add<X11FakeMouseMovementHandler>()
+ .add<PrivilegedHandlerForwarder>()
+ .add<IncompatibleHandler>() // See comments in incompatibleHandler.h
+ .add<LogNonMatchingHandler>();
+}
+
diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp
index 0c32b66..f27ea1e 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 <src/util/consoleLogger.h>
#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,45 @@ char modifiernames[][8] = {
"MOD5"
};
-QString modifiers_to_string(xmodifier_type mods)
+// 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;
for(int i = 0; i < 8; i++)
@@ -66,15 +104,23 @@ 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<quint32, KeySym> KeycodeLookupTable;
+KeycodeLookupTable keysyms;
-typedef std::map<quint32, KeySym> lookup_table_type;
-typedef lookup_table_type::const_iterator lookup_table_const_iterator;
-typedef lookup_table_type::iterator lookup_table_iterator;
-lookup_table_type keysyms;
-void initialize_keysyms() {
+// 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_Backtab] = XK_ISO_Left_Tab;
keysyms[Qt::Key_Backspace] = XK_BackSpace;
keysyms[Qt::Key_Return] = XK_Return;
keysyms[Qt::Key_Enter] = XK_KP_Enter;
@@ -140,173 +186,14 @@ 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;
- 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;
@@ -314,10 +201,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 +217,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 +225,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 +249,70 @@ 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];
+// We need to store how to generate KeySyms:
+struct KeySymInfo
+{
+ KeyCode keycode;
+ XModifiers neededModifiers;
+ XModifiers modifierMask;
+};
+typedef std::map<KeySym, KeySymInfo> KeySymToInfoMap;
+KeySymToInfoMap keysymInfos;
+
+// 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];
+
+// How do the X11 modifiers correspond to Qt's KeyboardModifiers?
+typedef std::map<XModifiers, Qt::KeyboardModifier> XToQtModifierMap;
+XToQtModifierMap XToQtModifier;
+typedef std::map<Qt::KeyboardModifier, XModifiers> QtToXModifierMap;
+QtToXModifierMap QtToXModifier;
+
+
+// And how do the modifiers relate to Keycodes?
+typedef std::multimap<XModifiers, int> ModifierToKeycodeMap;
+ModifierToKeycodeMap ModifierToKeycode;
+typedef std::map<int, XModifiers> 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];
+ }
-int xmodifier_from_qtmodifier(Qt::KeyboardModifier m) {
- for(int i = 0; i < 8; i++) {
- if(m == modifier_meaning[i])
- return i;
+ 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));
}
- return -1;
}
-
-typedef std::map<Qt::KeyboardModifier, xmodifier_type> qt_to_xmodifier_type;
-typedef std::map<xmodifier_type, Qt::KeyboardModifier> x_to_qtmodifier_type;
-qt_to_xmodifier_type qt_to_xmodifier;
-x_to_qtmodifier_type x_to_qtmodifier;
-
-typedef std::multimap<xmodifier_type, int> modifier_to_keycode_map;
-modifier_to_keycode_map modifier_to_keycode;
-typedef std::map<int, xmodifier_type> keycode_to_modifier_map;
-keycode_to_modifier_map keycode_to_modifier;
+#endif
// We need to query the input devices, preferrable through XInput2, but
// if that is not available we will contend ourselves with XInput1:
@@ -491,93 +344,190 @@ keycode_to_modifier_map keycode_to_modifier;
}
#endif
-
-void initialize_basic_keycodes()
+// Initialize the above data structures:
+void initializeBasicKeycodes()
{
- for(int i = 0; i < 8; i++) {
- modifier_keycodes[i] = -1;
+ // We temporarily need a list of all known KeySyms:
+ typedef std::set<KeySym> KeySymSet;
+ KeySymSet knownKeySyms;
+
+ for(KeycodeLookupTable::const_iterator kcIter = keysyms.begin();
+ kcIter != keysyms.end();
+ kcIter++)
+ {
+ knownKeySyms.insert((*kcIter).second);
}
- for(int i = 0; i < 0x100; i++) {
- basic_keycodes[i] = -1;
+
+ // Mark everything as unknown initially
+ for(int i = 0; i < 8; i++) {
+ modifierKeycodes[i] = -1;
}
+ keysymInfos.clear();
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;
+#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
+ // 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 < 0x100; j++)
{
- const int idx = i * keysyms_per_code + j;
+ const XModifiers mods = modifierpriority[j];
+ if(mods >= keysymsPerCode)
+ continue;
+
+ const int idx = i * keysymsPerCode + mods;
const KeySym ks = mapping[idx];
- const int keycode = min_keycode + i;
+ const int keycode = minKeycode + i;
- if(ks >= ' ' && ks < 0x100)
+ // to find out if there is a KeySym there that we know about
+ if(knownKeySyms.find(ks) != knownKeySyms.end())
{
- 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(keysymInfos.find(ks) != keysymInfos.end())
continue; // already found
- basic_keycodes[ks] = keycode;
- basic_modifiers[ks] = j;
+ // and record its keycode and needed modifiers.
+ 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<<i), kc));
+ KeycodeToModifier[kc] = (1<<i);
+ if(kc == shiftCode) {
+ XToQtModifier[1<<i] = Qt::ShiftModifier;
+ } else if(kc == controlCode) {
+ XToQtModifier[1<<i] = Qt::ControlModifier;
+ } else if(kc == altCode) {
+ XToQtModifier[1<<i] = Qt::AltModifier;
+ } else if(kc == metaCode) {
+ XToQtModifier[1<<i] = Qt::MetaModifier;
+ } else if(kc == switchCode) {
+ XToQtModifier[1<<i] = Qt::GroupSwitchModifier;
+ }
+
+ // and record the keycode we need to press/release
+ // to activate or deactivate a modifier:
+ if(modifierKeycodes[i] != -1) {
+ continue; // already found
+ }
+
+ // select one arbitrarily
+ modifierKeycodes[i] = kc;
+ }
+ }
+
+ XFreeModifiermap(modkm);
}
+#ifdef HAVE_XKBLIB_H
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);
- int ndevinfos;
- XIDeviceInfo* devinfos = XIQueryDevice(dpy, XIAllDevices, &ndevinfos);
- if(devinfos)
+
+
+ // Is XInput present?
+#if defined(HAVE_XINPUT_H) || defined(HAVE_XINPUT2_H)
+ // We don't care about these:
+ int i1, i2, i3;
+ bool haveXInput = XQueryExtension(dpy, "XInputExtension", &i1, &i2, &i3);
+
+ if(haveXInput)
{
+ Atom xtestDeviceProp = XInternAtom(dpy, "XTEST Device", false);
+
+ // Find the list of input devices:
+ int ndevinfos;
+ XIDeviceInfo* devinfos = XIQueryDevice(dpy, XIAllDevices, &ndevinfos);
+ if(devinfos)
+ {
#ifndef HAVE_XINPUT2_H
# define deviceid id
#endif
- 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);
+ 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.
// Okay, we know which device to query. Now get its keymap:
XkbDescPtr keybDesc = XkbGetKeyboard(dpy, XkbAllComponentsMask, xkbDeviceId);
@@ -586,36 +536,74 @@ 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++)
{
+ 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())
{
-// 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(mods & ~unconsumed)
+ {
+ // we would be recording extraneous modifiers
+ continue;
+ }
+
+ if(keysymInfos.find(ks) != keysymInfos.end())
continue;
- basic_keycodes[ks] = i;
- basic_modifiers[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;
+ }
}
}
}
@@ -626,61 +614,27 @@ void initialize_basic_keycodes()
XkbFreeKeyboard(keybDesc, XkbAllComponentsMask, true);
}
}
+#endif /* HAVE_XKBLIB_H */
- // find out which keycodes cause the modifier state bits:
- XModifierKeymap* modkm;
- modkm = XGetModifierMapping(dpy);
-
- const int shift_kc = XKeysymToKeycode(dpy, XK_Shift_L);
- const int control_kc = XKeysymToKeycode(dpy, XK_Control_L);
- const int alt_kc = XKeysymToKeycode(dpy, XK_Alt_L);
- const int meta_kc = XKeysymToKeycode(dpy, XK_Meta_L);
- const int switch_kc = XKeysymToKeycode(dpy, XK_Mode_switch);
-
- for(int i = 0; i < 8; i++) {
- for(int j = 0; j < modkm->max_keypermod; j++) {
- const int idx = i * modkm->max_keypermod + j;
- const int kc = modkm->modifiermap[idx];
-
- modifier_to_keycode.insert(std::make_pair((1<<i), kc));
- keycode_to_modifier[kc] = (1<<i);
-#define remember_modifier(qmod) do { \
- qt_to_xmodifier[Qt::qmod##Modifier] = 1<<i; \
- x_to_qtmodifier[1<<i] = Qt::qmod##Modifier; \
-} while(false)
- if(kc == shift_kc) {
- remember_modifier(Shift);
- } else if(kc == control_kc) {
- remember_modifier(Control);
- } else if(kc == alt_kc) {
- remember_modifier(Alt);
- } else if(kc == meta_kc) {
- remember_modifier(Meta);
- } else if(kc == switch_kc) {
- remember_modifier(GroupSwitch);
- }
-#undef remember_modifier
-
- if(modifier_keycodes[i] != -1) {
- continue; // already found
- }
-
- // select one arbitrarily
- modifier_keycodes[i] = kc;
- }
+ ConsoleLog writeLine("After initialization, XToQtModifier has the following entries:");
+ for(XToQtModifierMap::const_iterator i = XToQtModifier.begin();
+ i != XToQtModifier.end();
+ i++)
+ {
+ ConsoleLog writeLine(QString(" %1 %2").arg(i->first, 2, 16).arg(i->second, 8, 16));
}
-
- XFreeModifiermap(modkm);
}
-xmodifier_type translate_modifiers(quint32 mods)
+// Translate a Qt KeyboardModifiers flag to
+// its corresponding X11 modifier bitmask
+XModifiers translateModifiers(quint32 mods)
{
- xmodifier_type ret = 0;
+ XModifiers ret = 0;
- for(int j = 1; j < 8; j++) {
- xmodifier_type i = 1<<j;
+ for(int j = 0; j < 8; j++) {
+ XModifiers i = 1<<j;
- if(mods & x_to_qtmodifier[i])
+ if(mods & XToQtModifier[i])
{
ret |= i;
}
@@ -689,92 +643,98 @@ xmodifier_type translate_modifiers(quint32 mods)
return ret;
}
-typedef std::set<int> 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<int> IntSet;
+IntSet pressedModifierKeys;
+XModifiers currentModifiers = 0;
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<int, bool> modifier_tweak_type;
-typedef std::vector<modifier_tweak_type> 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<int, bool> ModifierTweak;
+typedef std::vector<ModifierTweak> 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)));
+ 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++)
{
- xmodifier_type i = 1<<j;
-
- ConsoleLog writeLine(QString("Checking for %1...").arg(modifiers_to_string(i)));
+ XModifiers i = 1<<j;
+ // Do we need to activate the modifier?
if((i & neededState) && !(i & actualState))
{
ConsoleLog writeLine(QString("tweakModifiers: Modifier %1 needs to be pressed").arg(modifiernames[j]));
- // needs to be pressed
-
- //find the keycode:
- int kc;
- modifier_to_keycode_map::iterator iter = modifier_to_keycode.find(i);
+ //find the keycode
+ ModifierToKeycodeMap::iterator iter = ModifierToKeycode.find(i);
- if((iter == modifier_to_keycode.end()) || ((*iter).first != i))
+ if((iter == ModifierToKeycode.end()) || ((*iter).first != i))
{
- continue; // we don't know a key that triggers this modifier
+ // we don't know a key that triggers this modifier
+ continue;
}
- ConsoleLog writeLine(QString(" pressing key %1").arg((*iter).second));
XTestFakeKeyEvent(dpy, (*iter).second, 1, CurrentTime);
+ // record the tweak
tracker.push_back(std::make_pair((*iter).second, true));
}
+ // or do we need to deactivate it?
else if((!(i & neededState)) && (i & actualState))
{
ConsoleLog writeLine(QString("tweakModifiers: Modifier %1 needs to be released").arg(modifiernames[j]));
- // needs to be released
-
int kc = -1;
- // first, check whether any of the currently pressed keys has triggered this modifier:
- int_set_type::iterator iter, end = pressed_modifier_keys.end();
- for(iter = pressed_modifier_keys.begin(); iter != end; iter++)
+ // first, check whether any of the currently pressed keys has triggered this modifier:
+ IntSet::iterator iter, end = pressedModifierKeys.end();
+ for(iter = pressedModifierKeys.begin(); iter != end; iter++)
{
- keycode_to_modifier_map::iterator modmap_iter = keycode_to_modifier.find(*iter);
- if(modmap_iter != keycode_to_modifier.end()) {
- if(modmap_iter->second == i) {
+ KeycodeToModifierMap::iterator modmapIter = KeycodeToModifier.find(*iter);
+ if(modmapIter != KeycodeToModifier.end()) {
+ if(modmapIter->second == i) {
kc = *iter;
// release this key:
- ConsoleLog writeLine(QString(" releasing key %1").arg(kc));
XTestFakeKeyEvent(dpy, kc, 0, CurrentTime);
tracker.push_back(std::make_pair(kc, false));
}
@@ -790,117 +750,128 @@ 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();
- for(i = tracker.begin(); i != end; i++) {
- modifier_tweak_type& t = *i;
+ TweakSequence::reverse_iterator i, end = tracker.rend();
+ for(i = tracker.rbegin(); i != end; 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;
}
-void X11FakeKeyboardHandler::handle(InputEvent const& evt, InputEventContext const*)
+// 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();
+ XTestGrabControl(dpy, 1);
+
// find out which keysym caused this event:
- lookup_table_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())
- {
- case Qt::Key_Backtab:
- handle(InputEvent(evt.type(), evt.code(), evt.qt_modifiers() | Qt::ShiftModifier | Qt::Key_Tab));
- break;
- default:
- ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qt_keysym(), 8, 16));
- }
+ ConsoleLog writeLine(QString("Unknown keysym received: %1").arg(evt.qtKeysym(), 8, 16));
} else {
KeySym ks = (*i).second;
- // is it a "normal" key?
- if(ks >= ' ' && ks < 0x100)
+ KeySymToInfoMap::const_iterator infoIter = keysymInfos.find(ks);
+ if(infoIter != keysymInfos.end())
{
- if(basic_keycodes[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 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)));
+ 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, basic_keycodes[ks], current_modifiers))
- {
- XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime);
- }
- else
- {
- // what modifier keys do we need to press?
- xmodifier_type mods = translate_modifiers(evt.qt_modifiers());
+ // 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 we do not differentiate upper and lower case,
- // and instead let the sender handle those modifiers,
- // we need to AND ShiftModifier and LockModifier out.
- mods |= basic_modifiers[ks] & ~(1<<ShiftMapIndex) & ~(1<<LockMapIndex);
- }
- else
- {
- // Not an alpha character. We do need to respect Shift and Lock for those:
- mods |= basic_modifiers[ks];
- }
+ // Determine which modifiers actually need to be active
+ XModifiers neededMods;
+ neededMods = (mods
+ & (needed | ~mask)) // Cleer the needed-clear modifiers
+ | (needed & mask); // Set the needed-set modifiers
- // now, tweak the modifiers
- tweak_sequence_type tweaks;
- tweakModifiers(dpy, mods, current_modifiers, tweaks);
+ // Modifiers need to be tracked BEFORE tweaking, as we may be
+ // pressing a modifier key, and we don't want to release it
+ // when untweaking.
+ trackModifiers(info.keycode, true);
- // press the key:
- XTestFakeKeyEvent(dpy, basic_keycodes[ks], 1, CurrentTime);
+ // now, tweak the modifiers
+ TweakSequence tweaks;
+ tweakModifiers(dpy, neededMods, currentModifiers, tweaks);
- // and release the modifiers:
- untweakModifiers(dpy, tweaks);
- }
- }
- else
- {
- // just release the key.
- XTestFakeKeyEvent(dpy, basic_keycodes[ks], 0, CurrentTime);
- }
+ // press the key:
+ XTestFakeKeyEvent(dpy, info.keycode, 1, CurrentTime);
+
+ // and release the modifiers:
+ untweakModifiers(dpy, tweaks);
}
else
{
- ConsoleLog writeLine(QString("No keycode is mapped to `%1'").arg(XKeysymToString(ks)));
+ // just release the key.
+ XTestFakeKeyEvent(dpy, info.keycode, 0, CurrentTime);
+ trackModifiers(info.keycode, false);
}
}
else
{
- // It is some kind of "special" key, so we just fake that, then:
- KeyCode kc = XKeysymToKeycode(dpy, ks);
- if(kc != 0)
- {
- ConsoleLog writeLine(QString("%1 special keycode %2, hopefully giving keysym %3").arg(evt.isPress() ? "Pressed" : "Released").arg(kc).arg(XKeysymToString(ks)));
- XTestFakeKeyEvent(dpy, kc, evt.isPress(), CurrentTime);
- // and track it if it is a modifier key:
- trackModifiers(kc, evt.isPress());
- }
- else
- {
- ConsoleLog writeLine(QString("No keycode is mapped to %1").arg(XKeysymToString(ks)));
- }
+ ConsoleLog writeLine(QString("No keycode is mapped to `%1'").arg(XKeysymToString(ks)));
}
}
+ XTestGrabControl(dpy, 0);
+
// Since there may not be a mainloop running, we need to manually flush the event queue
XFlush(dpy);
}
diff --git a/src/input/x11FakeKeyboardHandler.h b/src/input/x11FakeKeyboardHandler.h
index 3dde7cc..7f2d12e 100644
--- a/src/input/x11FakeKeyboardHandler.h
+++ b/src/input/x11FakeKeyboardHandler.h
@@ -19,10 +19,21 @@
#include "inputEventHandler.h"
-class X11FakeKeyboardHandler : public DefaultInputEventHandler<InputEvent::ET_KEY>
+/**
+ * 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<InputEvent::ET_KEY, InputEvent::EC_PRESS>,
+ input_policy::Match<InputEvent::ET_KEY, InputEvent::EC_RELEASE>,
+ input_policy::Require<input_policy::X11GUI>,
+ 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 <X11/extensions/XTest.h>
#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..2700829 100644
--- a/src/input/x11FakeMouseHandler.h
+++ b/src/input/x11FakeMouseHandler.h
@@ -19,16 +19,28 @@
#include "inputEventHandler.h"
-class X11FakeMouseButtonHandler : public DefaultInputEventHandler<InputEvent::ET_BUTTON>
+/**
+ * Send mouse button events via the XTest extension.
+ */
+class X11FakeMouseButtonHandler : public InputEventHandler<
+ input_policy::Match<InputEvent::ET_BUTTON>,
+ input_policy::Require<input_policy::X11GUI>,
+ input_policy::Unprivileged>
{
public:
- void handle(InputEvent const&, InputEventContext const* = 0);
+ void doHandle(InputEvent const&, InputEventContext const* = 0);
};
-class X11FakeMouseMovementHandler : public DefaultInputEventHandler<InputEvent::ET_POINTER>
+/**
+ * Send mouse pointer events via the XTest extension.
+ */
+class X11FakeMouseMovementHandler : public InputEventHandler<
+ input_policy::Match<InputEvent::ET_POINTER>,
+ input_policy::Require<input_policy::X11GUI>,
+ 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/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 <X11/Xlib.h>
+/**
+ * Store the X11 Display.
+ */
struct X11InputUtils {
static void setDisplay(Display*);
static Display* display();
diff --git a/src/pvs.cpp b/src/pvs.cpp
index bda16f8..755eea5 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"
@@ -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)
{
@@ -755,16 +758,23 @@ bool PVS::createMulticastTransfer(QString const& objectPath, quint64& transferID
// Input handling
+bool PVS::inputEventsAllowed()
+{
+ QString lecturer = getConfigValue("Permissions/vnc_lecturer");
+ return lecturer == "rw";
+}
+
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 f99e497..db87b8e 100755
--- a/src/pvs.h
+++ b/src/pvs.h
@@ -29,7 +29,7 @@
#include <QFile>
#include <QTextStream>
#include <QDir>
-#include "src/input/inputHandlerChain.h"
+#include "src/input/inputEventHandler.h"
class PVSServiceDiscovery;
class PVSDiscoveredServer;
@@ -173,7 +173,8 @@ private:
int _timerLockDelay;
// input event handling:
- unprivileged_handler_chain _inputEventHandlers;
+ InputEventHandlerChain _inputEventHandlers;
+ bool inputEventsAllowed();
void handleInputEvent(InputEvent const& evt);
void initializeInputEventHandling();
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 <QtGui/QDesktopServices>
#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."));