summaryrefslogtreecommitdiffstats
path: root/src/input/inputEventHandler.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/input/inputEventHandler.h')
-rw-r--r--src/input/inputEventHandler.h407
1 files changed, 208 insertions, 199 deletions
diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h
index 52e3338..5b03a90 100644
--- a/src/input/inputEventHandler.h
+++ b/src/input/inputEventHandler.h
@@ -22,274 +22,283 @@
#include <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
+struct InputEventContext
{
- SpecialInputEventDescription(QString const& d, quint16 t, quint16 c, quint32 v = 0)
- : descriptionString(d), evtType(t), evtCode(c), evtValue(v)
+ InputEventContext()
{
+ hasBeenDenied = false;
}
- QString descriptionString;
- quint16 evtType;
- quint16 evtCode;
- quint32 evtValue;
+ virtual pid_t getSenderPid() const = 0;
+ virtual uid_t getSenderUid() const = 0;
+ virtual gid_t getSenderGid() const = 0;
- InputEvent toEvent() const
- {
- return InputEvent(evtType, evtCode, evtValue);
- }
+ mutable bool hasBeenDenied;
};
-template<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;
- }
+namespace input_policy
+{
- virtual void initialize()
+/////////////////////////////////////////////////////////////////////////
+// Policy:
+// Modifies the behaviour of an input handler class.
+//
+// There are several kinds of policy:
+// - Security Policy (When to allow a certain action)
+// - System Requirements (When to enable a certain handler)
+// - Applicability (When to consider a certain handler)
+//
+// Policies are tied together using the detail::PolicyChain class.
+/////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////
+// Security Policy:
+// At the moment there are two security policies:
+// 1. If the user is on a local seat, allow. If the user is privileged,
+// allow. Else deny.
+// 2. Allow everybody.
+// Additional security policies can be added by following the example
+// set by AllowLocalOrPrivileged
+/////////////////////////////////////////////////////////////////////////
+template<typename PolicyImpl>
+BEGIN_POLICY_CLASS(Security)
+{
+ bool allow(InputEventContext const* context)
{
+ return PolicyImpl::allow(context);
}
+}
+END_POLICY_CLASS
- virtual void handle(InputEvent const& evt, InputEventContext const*) = 0;
-
- static void describeInto(QList<SpecialInputEventDescription>& description)
- {
- }
+struct AllowLocalOrPrivileged
+{
+ static bool allow(InputEventContext const*);
};
-namespace policy {
-
-enum SecurityFlags {
- SEC_FREE_FOR_ALL,
- SEC_PHYSICAL_OR_PRIVILEGED
+struct AllowEverybody
+{
+ static bool allow(InputEventContext const*);
};
-bool allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx);
-bool allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx);
+typedef Security<AllowEverybody> Unprivileged;
-struct SecurityAllowAny
+/////////////////////////////////////////////////////////////////////////
+// System Requirements:
+// At the moment, this is trivial, as PVS only runs on Linux. But,
+// as porting efforts are already underway, we include the necessary
+// machinery anyway.
+/////////////////////////////////////////////////////////////////////////
+template<typename SystemTrait>
+BEGIN_POLICY_CLASS(Require)
{
- bool allow(InputEvent const& evt, InputEventContext const* ctx)
- {
- return true;
- }
+ static const bool areSystemRequirementsFulfilled =
+ NextPolicy::areSystemRequirementsFulfilled &&
+ detail::Matches<SystemTrait, detail::SystemTraits>::value;
+}
+END_POLICY_CLASS
+
+/////////////////////////////////////////////////////////////////////////
+// System Requirements:
+// At the moment, this is trivial, as PVS only runs on Linux. But,
+// as porting efforts are already underway, we include the necessary
+// machinery anyway.
+/////////////////////////////////////////////////////////////////////////
+enum {
+ HANDLER_CODE_DONT_CARE = 0xffff,
+ HANDLER_VALUE_DONT_CARE = 0xffffffff
};
-struct SecurityAllowPhysicalOrPrivileged
+struct T;
+
+template<unsigned short EventType,
+ unsigned short EventCode = HANDLER_CODE_DONT_CARE,
+ unsigned int EventValue = HANDLER_VALUE_DONT_CARE>
+BEGIN_POLICY_CLASS(Match)
{
- bool allow(InputEvent const& evt, InputEventContext const* ctx)
+ bool isApplicable(InputEvent const& evt)
{
- if(allowPhysicalSeat(evt, ctx))
- return true;
- else if(allowPrivilegedUser(evt, ctx))
- return true;
- return false;
+ if(evt.type() != EventType)
+ return NextPolicy::isApplicable(evt);
+ if(EventCode != HANDLER_CODE_DONT_CARE && evt.code() != EventCode)
+ return NextPolicy::isApplicable(evt);
+ if(EventValue != HANDLER_VALUE_DONT_CARE && evt.value() != EventValue)
+ return NextPolicy::isApplicable(evt);
+ return true;
}
};
+END_POLICY_CLASS
-struct UnixLike;
-struct Linux;
-struct Windows;
-
-#if defined(__linux)
-typedef boost::mpl::vector2<UnixLike,Linux>::type Systems;
-#elif defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
-typedef boost::mpl::vector1<Windows>::type Systems;
-#else
-# error "Porting is needed!"
-#endif
-
-struct SystemEnabled;
-struct SystemDisabled;
-
-template<typename System>
-struct RequireSystem
-{
- typedef typename boost::mpl::contains<Systems, System>::type enabled_type;
- static const bool enabled = enabled_type::value;
-};
-
-struct RequireNoSystem
+namespace detail
{
- typedef boost::mpl::bool_<true>::type enabled_type;
- static const bool enabled = enabled_type::value;
-};
-}
-
-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;
-};
-
-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>
-{
-};
+}
+}
-template<typename DefaultSecurityPolicy, typename HandlerType>
-struct ApplyDefaultSecurityPolicy
+/////////////////////////////////////////////////////////////////////////
+// We want a nice non-generic base so we can make a list of polymorphic
+// handlers.
+//
+// The actual handler class need to provide doHandle and can override
+// allow and isApplicable.
+/////////////////////////////////////////////////////////////////////////
+/* interface */ class InputEventHandlerBase
{
- typedef HandlerType type;
-};
+public:
+ enum HandlerStatus
+ {
+ HANDLER_MATCHED,
+ HANDLER_NOT_ALLOWED,
+ HANDLER_NOT_APPLICABLE
+ };
-template<typename DefaultSecurityPolicy, typename Delegate, typename SystemPolicy>
-struct ApplyDefaultSecurityPolicy<DefaultSecurityPolicy, Handler<Delegate, SystemPolicy, void> >
-{
- typedef Handler<Delegate, SystemPolicy, DefaultSecurityPolicy> type;
+ virtual void initialize() = 0;
+ HandlerStatus handle(InputEvent const& evt, InputEventContext const* context = 0);
+
+protected:
+ virtual bool allow(InputEvent const& event, InputEventContext const* context = 0) = 0;
+ virtual bool isApplicable(InputEvent const& event, InputEventContext const* context = 0) = 0;
+ virtual void doHandle(InputEvent const& event, InputEventContext const* context = 0) = 0;
};
-template<typename DefaultSecurityPolicy, typename Begin, typename End>
-struct InputEventHandlerChainHelper
+/////////////////////////////////////////////////////////////////////////
+// Now that the machinery is in place, we can finally define what it
+// is like to be an input event handler:
+/////////////////////////////////////////////////////////////////////////
+template<POLICY_PARAMS>
+class InputEventHandler : public InputEventHandlerBase
{
-private:
- typedef typename boost::mpl::next<Begin>::type next_iterator_type;
- typedef InputEventHandlerChainHelper<DefaultSecurityPolicy, next_iterator_type, End> next_in_chain;
-
- typedef typename boost::mpl::deref<Begin>::type handler_entry_type;
- typedef typename ApplyDefaultSecurityPolicy<DefaultSecurityPolicy, handler_entry_type>::type handler_type;
-
- handler_type _handler;
- next_in_chain _next;
+protected:
+ typedef USE_POLICY(input_policy::detail::InputEventHandlerPolicyBase) policy_type;
+ policy_type policy;
public:
- void handle(InputEvent const& evt, InputEventContext const* context = 0) {
- if(!_handler.handle(evt, context)) {
- _next.handle(evt, context);
- }
+ void initialize()
+ {
+ policy.initialize();
}
- void initialize() {
- _handler.initialize();
- _next.initialize();
- }
+ // Export this so the handler chain can decide whether to include this handler
+ static const bool areSystemRequirementsFulfilled = policy_type::areSystemRequirementsFulfilled;
+
+protected:
+
+ typedef InputEventHandler super;
- static void describeInto(QList<SpecialInputEventDescription>& list)
+ // allow and isApplicable are actually provided by Policy. If the
+ // handler class wishes to override any of them, the policy implementation
+ // can be called by means of super.
+ bool allow(InputEvent const&, InputEventContext const* context = 0)
{
- handler_type::describeInto(list);
- next_in_chain::describeInto(list);
+ return policy.allow(context);
}
- static QList<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>
+/////////////////////////////////////////////////////////////////////////
+// And we can chain input handlers together:
+/////////////////////////////////////////////////////////////////////////
+class InputEventHandlerChain
{
- void handle(InputEvent const&, InputEventContext const* context = 0) {
- // do nothing
- }
+private:
+ QList<InputEventHandlerBase*> handlers;
+
+ /////////////////////////////////////////////////////////////////////////
+ // We need to statically dispatch on a static member of HandlerType.
+ // Unfortunately, we cannot specialize member functions of a template.
+ // So, we need to make this a class with a static non-template member.
+ /////////////////////////////////////////////////////////////////////////
+ template<bool Applicable, typename HandlerType>
+ struct ConditionallyAppend
+ {
+ 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*)
+ {
+ }
+ };
- static void describeInto(QList<SpecialInputEventDescription>&)
+public:
+ // Add an event handler to the chain. The argument is only for
+ // compilers which cannot handle template member functions
+ // correctly.
+ template<typename HandlerType>
+ InputEventHandlerChain& add(HandlerType const* = 0)
{
- // do nothing
+ ConditionallyAppend<HandlerType::areSystemRequirementsFulfilled, HandlerType>::doIt(this);
+ return *this;
}
- static QList<SpecialInputEventDescription> describe()
+ 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>
-{
+ 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:
+ break;
+ case InputEventHandlerBase::HANDLER_NOT_ALLOWED:
+ context->hasBeenDenied = true;
+ case InputEventHandlerBase::HANDLER_NOT_APPLICABLE:
+ continue;
+ }
+ }
+ }
};
#endif /* INPUTEVENTHANDLER_H_ */