summaryrefslogtreecommitdiff
path: root/MouseMate.c
diff options
context:
space:
mode:
Diffstat (limited to 'MouseMate.c')
-rw-r--r--MouseMate.c546
1 files changed, 546 insertions, 0 deletions
diff --git a/MouseMate.c b/MouseMate.c
new file mode 100644
index 0000000..b835b83
--- /dev/null
+++ b/MouseMate.c
@@ -0,0 +1,546 @@
+/*
+ * mousemate plugin for VDR
+ *
+ * MouseMate.c - MouseMate control class
+ *
+ *
+ * This code is distributed under the terms and conditions of the
+ * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details.
+ */
+
+#include <linux/input.h>
+#include <string.h>
+#include <errno.h>
+#include <iostream>
+
+#include "MouseMate.h"
+#include "ButtonObserver.h"
+
+// buffer size for reading events
+const int BUFFER_SIZE=32;
+
+#ifdef DEBUG
+const char * strContextsDebug[kContexts] =
+{
+ "Normal",
+ "Menu",
+ "Replay",
+ "Replay DVD",
+ "Replay MP3",
+ "Replay CDDA",
+ "Replay IMAGE",
+ "Normal alternative",
+ "Menu alternative",
+ "Replay alternative",
+ "Replay DVD alternative",
+ "Replay MP3 alternative",
+ "Replay CDDA alternative",
+ "Replay IMAGE alternative"
+};
+
+const char * strEventsDebug[kEvents] =
+{
+ "TurnWheelLeft",
+ "TurnWheelRight",
+ "TurnXLeft",
+ "TurnXRight",
+ "TurnYLeft",
+ "TurnYRight",
+ "LeftClick",
+ "LeftDoubleClick",
+ "LeftPushedTurnLeft",
+ "LeftPushedTurnRight",
+ "MiddleClick",
+ "MiddleDoubleClick",
+ "MiddlePushedTurnLeft",
+ "MiddlePushedTurnRight",
+ "RightClick",
+ "RightDoubleClick",
+ "RightPushedTurnLeft",
+ "RightPushedTurnRight",
+ "SidePushedTurnLeft",
+ "SidePushedTurnRight",
+ "SideClick",
+ "SideDoubleClick",
+ "ExtraClick",
+ "ExtraDoubleClick",
+ "ExtraPushedTurnLeft",
+ "ExtraPushedTurnRight",
+ "ForwardClick",
+ "ForwardDoubleClick",
+ "ForwardPushedTurnLeft",
+ "ForwardPushedTurnRight",
+ "BackClick",
+ "BackDoubleClick",
+ "BackPushedTurnLeft",
+ "BackPushedTurnRight",
+ "TaskClick",
+ "TaskDoubleClick"
+ "TaskPushedTurnLeft",
+ "TaskPushedTurnRight"
+};
+#endif
+
+cMouseMate * MouseMate;
+
+cMouseMate::cMouseMate()
+:pushed(false),
+lastPush(0),
+offset(0),
+offsetX(0),
+offsetY(0),
+click(false),
+turn(false),
+toggle(false),
+toggletime(0),
+btnCount(0),
+active(false)
+{
+ fd = open(MouseMateSetup.device, O_RDONLY);
+ if (fd < 0)
+ {
+ esyslog("mousemate: unable to open %s: %s\n", MouseMateSetup.device, strerror(errno));
+ fd = -1;
+ return;
+ }
+
+ // Check if same EV_VERSION is used, because of hardcoded values below
+ if (EV_VERSION!=0x010000)
+ {
+ esyslog("mousemate: Warning this Plugin is written for another EV_VERSION!"
+ "mousemate: This may cause incompatibility!");
+ }
+
+ uint8_t evtype_bitmask[KEY_MAX/8+1];
+ int yalv;
+ memset(evtype_bitmask, 0, sizeof(evtype_bitmask));
+
+ if (ioctl(fd, EVIOCGBIT(EV_KEY, KEY_MAX), evtype_bitmask) < 0)
+ {
+ esyslog("mousemate: %s: EVIOCGBIT failed: %s\n", MouseMateSetup.device, strerror(errno));
+ return;
+ }
+
+ for (yalv = BTN_MOUSE; yalv < BTN_MOUSE+9; yalv++)
+ {
+ if (test_bit(yalv, evtype_bitmask))
+ {
+ /* this means that the bit is set in the event types list */
+ switch (yalv)
+ {
+ case BTN_LEFT :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_LEFT\n");
+ #endif
+ buttonObservers[0].Init(BTN_LEFT, kEventLeftClick, kEventLeftDoubleClick, kEventLeftPushedTurnLeft, kEventLeftPushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_RIGHT :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_RIGHT\n");
+ #endif
+ buttonObservers[1].Init(BTN_RIGHT, kEventRightClick, kEventRightDoubleClick,kEventRightPushedTurnLeft, kEventRightPushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_MIDDLE :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_MIDDLE\n");
+ #endif
+ buttonObservers[2].Init(BTN_MIDDLE, kEventMiddleClick, kEventMiddleDoubleClick, kEventMiddlePushedTurnLeft, kEventMiddlePushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_SIDE :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found TN_SIDE\n");
+ #endif
+ buttonObservers[3].Init(BTN_SIDE, kEventSideClick, kEventSideDoubleClick, kEventSidePushedTurnLeft, kEventSidePushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_EXTRA :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_EXTRA\n");
+ #endif
+ buttonObservers[4].Init(BTN_EXTRA, kEventExtraClick, kEventExtraDoubleClick, kEventExtraPushedTurnLeft, kEventExtraPushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_FORWARD :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_FORWARD\n");
+ #endif
+ buttonObservers[5].Init(BTN_FORWARD, kEventForwardClick, kEventForwardDoubleClick, kEventForwardPushedTurnLeft, kEventForwardPushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_BACK :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_BACK\n");
+ #endif
+ buttonObservers[6].Init(BTN_BACK, kEventBackClick, kEventBackDoubleClick,kEventBackPushedTurnLeft, kEventBackPushedTurnRight);
+ btnCount++;
+ break;
+ case BTN_TASK :
+ #ifdef DEBUG
+ dsyslog("mousemate: button found BTN_TASK\n");
+ #endif
+ buttonObservers[7].Init(BTN_TASK, kEventTaskClick, kEventTaskDoubleClick, kEventTaskPushedTurnLeft, kEventTaskPushedTurnRight);
+ btnCount++;
+ break;
+ }
+ }
+ }
+
+ #ifdef DEBUG
+ dsyslog("mousemate: number of found buttons btnCount = %i\n",btnCount);
+ #endif
+
+ if (btnCount<3)
+ {
+ esyslog("mousemate: number of buttons < 3 \n"
+ "mousemate: ******** plugin not started ******** \n" );
+ return;
+ }
+
+ Monitor=new cMouseMateMonitor;
+ Start();
+}
+
+
+cMouseMate::~cMouseMate()
+{
+ delete Monitor;
+ active = false;
+ close(fd);
+ Cancel(3);
+}
+
+
+bool cMouseMate::IsButtonUsed(unsigned int buCo)
+{
+ return !buttonObservers[buCo-BTN_MOUSE].buttonCode ? false : true;
+}
+
+
+short int cMouseMate::Get_btnCount()
+{
+ return btnCount;
+}
+
+
+void cMouseMate::Action()
+{
+ active = true;
+ dsyslog("MouseMate thread started (pid=%d)", getpid());
+
+ struct input_event events[BUFFER_SIZE];
+ int r;
+ int num;
+ int i;
+
+ while (fd >= 0 && active)
+ {
+ LOCK_THREAD;
+ if (cFile::FileReady(fd, 100))
+ {
+ r = safe_read(fd, events, sizeof(struct input_event) * BUFFER_SIZE);
+ if (r > 0)
+ {
+ num = r / sizeof(struct input_event);
+ for (i = 0; i < num; i++)
+ {
+ ProcessInputEvent(&events[i]);
+ }
+ }
+ else
+ {
+ LOG_ERROR;
+ }
+ }
+
+ // controll more than one button with buttonObserver & for loop
+ for (i=0; i < btnCount; i++)
+ {
+ if (buttonObservers[i].click && !buttonObservers[i].pushed)
+ {
+ uint64_t current = TimeMs();
+ if (current - buttonObservers[i].lastPush > (uint64_t) MouseMateSetup.doubleClickTime)
+ {
+ #ifdef DEBUG
+ dsyslog("mousemate: click (main loop)\n");
+ #endif
+ ProcessEvent(buttonObservers[i].clickEvent);
+ buttonObservers[i].click = false;
+ }
+ }
+
+ // toggle?
+ if (buttonObservers[i].pushed && !turn && MouseMateSetup.alternative)
+ {
+ uint64_t current = TimeMs();
+ if (current - buttonObservers[i].lastPush > (uint64_t) MouseMateSetup.toggleClickTime)
+ {
+ Toggle();
+ // clear events
+ struct input_event dummyevents[BUFFER_SIZE];
+ r = safe_read(fd, dummyevents, sizeof(struct input_event) * BUFFER_SIZE);
+ }
+ }
+ }
+
+ // handle automatic toggle off after "toggleOffTime" since last event
+ if(toggle && MouseMateSetup.autotoggleoff && MouseMateSetup.alternative)
+ {
+ uint64_t current = TimeMs();
+ if (current - toggletime > (uint64_t) MouseMateSetup.toggleOffTime )
+ {
+ Toggle();
+ #ifdef DEBUG
+ dsyslog("mousemate: toggle inactive automatically after %i ms \n", MouseMateSetup.toggleOffTime);
+ #endif
+ // clear events
+ struct input_event dummyevents[BUFFER_SIZE];
+ r = safe_read(fd, dummyevents, sizeof(struct input_event) * BUFFER_SIZE);
+ }
+ }
+ }
+ dsyslog("MouseMate thread ended (pid=%d)", getpid());
+}
+
+
+void cMouseMate::Toggle()
+{
+ if (toggle)
+ {
+ toggle= false;
+ #ifdef DEBUG
+ dsyslog("mousemate: toggle inactive \n");
+ #endif
+ }
+ else
+ {
+ toggle=true;
+ toggletime=TimeMs();
+ #ifdef DEBUG
+ dsyslog("mousemate: toggle active after %i ms pushed button\n", MouseMateSetup.toggleClickTime);
+ #endif
+ }
+
+ // controll more than one button with buttonObservers & for loop
+ int i;
+ for (i=0; i<btnCount; i++)
+ {
+ buttonObservers[i].pushed=false;
+ buttonObservers[i].click=false;
+ }
+
+ // set scroll lock led if led = true
+ if (MouseMateSetup.led)
+ {
+ int fc;
+ fc = open(MouseMateSetup.cdevice, O_RDWR);
+ // can console device be opened?
+ if (fc)
+ {
+ struct input_event ev;
+ ev.type = EV_LED;
+ ev.code = LED_SCROLLL;
+ ev.value = toggle;
+ write(fc, &ev, sizeof(struct input_event));
+ close(fc);
+ }
+ else
+ {
+ esyslog("mousemate: unable to open console device %s: %s\n", MouseMateSetup.cdevice, strerror(errno));
+ fc = -1;
+ return;
+ }
+ }
+}
+
+
+void cMouseMate::ProcessInputEvent(struct input_event * ev)
+{
+ bool pushed=false;
+ int button=2;
+
+ switch (ev->type)
+ {
+ case EV_REL:
+ if (ev->code == Wheel)
+ {
+ turn = true;
+ offset += (int) ev->value;
+ for (int i=0; i < btnCount; i++)
+ {
+ if (buttonObservers[i].pushed)
+ {
+ pushed=true;
+ button=i;
+ }
+ }
+ if (pushed)
+ {
+ if ((int) ev->value < 0)
+ {
+ while (offset <= -MouseMateSetup.sensitivity)
+ {
+ ProcessEvent(buttonObservers[button].pushedTurnLeftEvent);
+ offset += MouseMateSetup.sensitivity;
+ }
+ }
+ if ((int) ev->value > 0)
+ {
+ while (offset >= MouseMateSetup.sensitivity)
+ {
+ ProcessEvent(buttonObservers[button].pushedTurnRightEvent);
+ offset -= MouseMateSetup.sensitivity;
+ }
+ }
+ }
+ else
+ {
+ for (int i=0; i < btnCount; i++)
+ {
+ if (buttonObservers[i].click)
+ {
+ #ifdef DEBUG
+ dsyslog("mousemate: click (ProcessInputEvent)\n");
+ #endif
+ ProcessEvent(buttonObservers[i].clickEvent);
+ buttonObservers[i].click = false;
+ }
+ }
+ if ((int) ev->value < 0)
+ {
+ while (offset <= -MouseMateSetup.sensitivity)
+ {
+ ProcessEvent(kEventTurnWheelLeft);
+ offset += MouseMateSetup.sensitivity;
+ }
+ }
+ if ((int) ev->value > 0)
+ {
+ while (offset >= MouseMateSetup.sensitivity)
+ {
+ ProcessEvent(kEventTurnWheelRight);
+ offset -= MouseMateSetup.sensitivity;
+ }
+ }
+ }
+ }
+
+ if(MouseMateSetup.extraturns)
+ {
+ if (ev->code == REL_X)
+ {
+ offsetX += (int) ev->value;
+ if ((int) ev->value < 0)
+ {
+ while (offsetX <= -MouseMateSetup.sensitivityX)
+ {
+ ProcessEvent(kEventTurnXLeft);
+ offsetX += MouseMateSetup.sensitivityX;
+ }
+ }
+ if ((int) ev->value > 0)
+ {
+ while (offsetX >= MouseMateSetup.sensitivityX)
+ {
+ ProcessEvent(kEventTurnXRight);
+ offsetX -= MouseMateSetup.sensitivityX;
+ }
+ }
+ }
+ if (ev->code == REL_Y)
+ {
+ offsetY += (int) ev->value;
+ if ((int) ev->value < 0)
+ {
+ while (offsetY <= -MouseMateSetup.sensitivityY)
+ {
+ ProcessEvent(kEventTurnYLeft);
+ offsetY += MouseMateSetup.sensitivityY;
+ }
+ }
+ if ((int) ev->value > 0)
+ {
+ while (offsetY >= MouseMateSetup.sensitivityY)
+ {
+ ProcessEvent(kEventTurnYRight);
+ offsetY -= MouseMateSetup.sensitivityY;
+ }
+ }
+ }
+ }
+ break;
+ case EV_KEY:
+
+ for (int i=0; i<btnCount; i++)
+ {
+ if (ev->code == buttonObservers[i].buttonCode)
+ {
+ if (ev->value)
+ {
+ buttonObservers[i].pushed = true;
+ turn = false;
+ offset = 0;
+ buttonObservers[i].lastPush = TimeMs();
+ }
+ else
+ {
+ if (buttonObservers[i].click)
+ {
+ #ifdef DEBUG
+ dsyslog("mousemate: double click\n");
+ #endif
+ ProcessEvent(buttonObservers[i].doubleClickEvent);
+ buttonObservers[i].click = false;
+ }
+ else
+ {
+ if (!turn)
+ buttonObservers[i].click = true;
+ }
+ buttonObservers[i].pushed = false;
+ turn = false;
+ offset = 0;
+ }
+ }
+ }
+ break;
+ }
+ #ifdef EVENTCODE_SNIFFER
+ printf("mousemate: ev->type = 0x%04x\n", ev->type);
+ printf("mousemate: ev->code = 0x%04x\n", ev->code);
+ printf("mousemate: ev->value = %i\n", int(ev->value));
+ printf("-----------------------------\n");
+ #endif
+}
+
+
+void cMouseMate::ProcessEvent(int event)
+{
+ int context= Monitor->GetContext(toggle);
+
+ if (!toggle)
+ {
+ SendKey(MouseMateSetup.keys[context][event]);
+ }
+ else
+ {
+ toggletime=TimeMs(); // updating toggletime for key is pressed in toggle mode
+ SendKey(MouseMateSetup.keys[context][event]);
+ }
+
+ #ifdef DEBUG
+ dsyslog("mousemate: toggle=%i, event=%s, context=%s\n",toggle,
+ strEventsDebug[event],strContextsDebug[context]);
+ eKeys keyNr=MouseMateSetup.keys[context][event];
+ dsyslog("mousemate: sent key= nr %i, %s\n",keyNr, cKey::ToString(keyNr));
+ #endif
+}
+
+
+void cMouseMate::SendKey(eKeys key)
+{
+ if (key != kNone)
+ cRemote::Put(key);
+}