summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>2012-12-27 12:35:59 +0100
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>2012-12-27 12:35:59 +0100
commit4777ed032ac40cc71cf8bfedaedd56eecf77c5b2 (patch)
treeb4d419d41823156964acedd65e21a18e685470de
parent5838dca17110ab50e660f0e231fd7268f2880a82 (diff)
downloadvdr-plugin-inputdev-4777ed032ac40cc71cf8bfedaedd56eecf77c5b2.tar.gz
vdr-plugin-inputdev-4777ed032ac40cc71cf8bfedaedd56eecf77c5b2.tar.bz2
implemented magic keysequence to remove input device on demand
-rw-r--r--inputdev.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/inputdev.c b/inputdev.c
index c309439..03c039c 100644
--- a/inputdev.c
+++ b/inputdev.c
@@ -38,6 +38,125 @@ inline static bool test_bit(unsigned int bit, unsigned long const mask[])
return (m & (1u << i)) != 0u;
}
+class MagicState {
+private:
+ static bool const IS_SUPPORTED_;
+
+ unsigned int state_;
+ struct timespec next_;
+
+ static int compare(struct timespec const &a,
+ struct timespec const &b);
+
+ static void add(struct timespec &res,
+ struct timespec const &a,
+ struct timespec const &b);
+
+public:
+ static struct timespec const TIMEOUT;
+
+ MagicState() : state_(0) {}
+ bool process(struct input_event const &ev);
+
+};
+
+static bool check_clock_gettime(void)
+{
+ struct timespec tmp;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tmp) < 0) {
+ fprintf(stderr,
+ "clock_gettime() not available; magic keysequences will not be available: %s\n",
+ strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool const MagicState::IS_SUPPORTED_ = check_clock_gettime();
+struct timespec const MagicState::TIMEOUT = { 1, 500000000 };
+
+int MagicState::compare(struct timespec const &a, struct timespec const &b)
+{
+ if (a.tv_sec < b.tv_sec)
+ return -1;
+ else if (a.tv_sec > b.tv_sec)
+ return + 1;
+ else if (a.tv_nsec < b.tv_nsec)
+ return -1;
+ else if (a.tv_nsec > b.tv_nsec)
+ return +1;
+ else
+ return 0;
+}
+
+void MagicState::add(struct timespec &res,
+ struct timespec const &a, struct timespec const &b)
+{
+ assert(a.tv_nsec < 1000000000);
+ assert(b.tv_nsec < 1000000000);
+
+ res.tv_sec = a.tv_sec + b.tv_sec;
+ res.tv_nsec = a.tv_nsec + b.tv_nsec;
+
+ if (res.tv_nsec >= 1000000000) {
+ res.tv_nsec -= 1000000000;
+ res.tv_sec += 1;
+ }
+}
+
+bool MagicState::process(struct input_event const &ev)
+{
+ static unsigned int const SEQUENCE[] = {
+ KEY_LEFTSHIFT,
+ KEY_LEFTSHIFT,
+ KEY_ESC,
+ KEY_LEFTSHIFT,
+ };
+
+ unsigned int code;
+
+ assert(state_ < ARRAY_SIZE(SEQUENCE));
+
+ if (!IS_SUPPORTED_)
+ return false;
+
+ if (ev.type != EV_KEY || ev.value != 1)
+ // ignore non-key events and skip release- and repeat events
+ return false;
+
+ // translate some keys
+ switch (ev.code) {
+ case KEY_RIGHTSHIFT: code = KEY_LEFTSHIFT; break;
+ default: code = ev.code;
+ }
+
+ if (state_ > 0) {
+ struct timespec now;
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if (compare(next_, now) < 0)
+ // reset state due to timeout
+ state_ = 0;
+
+ add(next_, now, TIMEOUT);
+ }
+
+ if (SEQUENCE[state_] == code)
+ ++state_;
+ else
+ state_ = 0;
+
+ if (state_ == ARRAY_SIZE(SEQUENCE)) {
+ state_ = 0;
+ return true;
+ }
+
+ return false;
+}
+
+
class cInputDevice : public cListObject {
private:
cInputDeviceController &controller_;
@@ -45,6 +164,7 @@ private:
cString description_;
int fd_;
dev_t dev_t_;
+ class MagicState magic_state_;
public:
// the vdr list implementation requires knowledge about the containing
@@ -327,6 +447,13 @@ void cInputDevice::handle(void)
(unsigned int)(ev.time.tv_usec),
ev.type, ev.code, ev.value);
+ if (magic_state_.process(ev)) {
+ isyslog("%s: magic keysequence from %s; detaching device\n",
+ controller_.plugin_name(), get_dev_path());
+ controller_.remove_device(this);
+ return;
+ }
+
switch (ev.type) {
case EV_KEY:
is_valid = true;