]> ToastFreeware Gitweb - gregoa/zavai.git/blobdiff - src/input.vala
Notes about remotising devices
[gregoa/zavai.git] / src / input.vala
index 3bdd61b343b66f1cf11155e54d6064c3bf6cc2f5..ffa0add9fad3fffc5f9bce4216c0956e6417f0fd 100644 (file)
@@ -21,7 +21,7 @@
 namespace zavai {
 namespace input {
 
-public abstract class DevInput : zavai.Service
+public class DevInput : zavai.Service
 {
     public string device { get; construct; }
 
@@ -30,6 +30,11 @@ public abstract class DevInput : zavai.Service
     protected IOChannel fd = null;
     protected uint fd_watch = 0;
 
+    public DevInput(string name, string device)
+    {
+        Object(name: "input.power_button", device: "/dev/input/event0");
+    }
+
     protected void close_fd()
     {
         if (fd != null)
@@ -123,21 +128,118 @@ public abstract class DevInput : zavai.Service
     }
 }
 
-public class PowerButton : DevInput
+public class HotKeys : zavai.Service
+{
+    protected List<int> grabbed;
+    public signal bool hotkey(uint keycode, ulong time, bool pressed);
+
+    public HotKeys()
+    {
+        Object(name: "input.hotkeys");
+
+        grabbed = new List<int>();
+    }
+
+    // Hotkey handlink takes inspiration from
+    // http://old.nabble.com/-PATCH--Initial-non-working-implementation-of-wxWindow::%28Un%29RegisterHotKey-on-wxGTK-td14557263.html
+    private static Gdk.FilterReturn on_hotkey(Gdk.XEvent* xevent, Gdk.Event? event, void* data)
+    {
+        // Global events don't get their data translated to gdk, as there is no
+        // GdkWindow to work with, therefore we need to use the xevent, because
+        // GdkEvent* is always GDK_NOTHING
+        X.Event* xev = (X.Event*)xevent;
+
+        switch (xev->type)
+        {
+            case X.EventType.KeyPress:
+                return zavai.input.hotkeys.my_on_hotkey(xev, true);
+            case X.EventType.KeyRelease:
+                return zavai.input.hotkeys.my_on_hotkey(xev, false);
+            default:
+                return Gdk.FilterReturn.CONTINUE;
+        }
+    }
+
+    //public Gdk.FilterReturn on_hotkey(Gdk.XEvent xevent, Gdk.Event? event)
+    private Gdk.FilterReturn my_on_hotkey(X.Event* xev, bool pressed)
+    {
+        // From http://tronche.com/gui/x/xlib/input/pointer-grabbing.html:
+        //
+        // A timestamp is a time value, expressed in milliseconds. It typically is the
+        // time since the last server reset. Timestamp values wrap around (after about
+        // 49.7 days). The server, given its current time is represented by timestamp
+        // T, always interprets timestamps from clients by treating half of the
+        // timestamp space as being later in time than T. One timestamp value, named
+        // CurrentTime, is never generated by the server. This value is reserved for
+        // use in requests to represent the current server time. 
+
+        if (grabbed.index((int)xev->xkey.keycode) == -1)
+            return Gdk.FilterReturn.CONTINUE;
+
+        if (hotkey(xev->xkey.keycode, xev->xkey.time, pressed))
+            return Gdk.FilterReturn.REMOVE;
+        return Gdk.FilterReturn.CONTINUE;
+    }
+
+    public void grab(int keycode, int modifiers, bool owner_events)
+    {
+        // We need to grab the keys we want to listen to
+        int res = Gdk.x11_get_default_xdisplay().grab_key(keycode, modifiers, Gdk.x11_get_default_root_xwindow(), owner_events, X.GrabMode.Async, X.GrabMode.Async);
+        if (res != 0)
+            stderr.printf("Grab result: %d\n", res); // We get BadRequest and don't know why
+        grabbed.append(keycode);
+    }
+
+    /// Start reading from the device
+    public override void start()
+    {
+        if (started) return;
+
+        //gdk_window_add_filter (NULL, _wxgtk_global_hotkey_callback, this);
+        ((Gdk.Window*)null)->add_filter((Gdk.FilterFunc)on_hotkey);
+
+        grab(160, 0, false);
+
+        base.start();
+    }
+
+    // Stop reading from the device
+    public override void stop()
+    {
+        if (!started) return;
+
+        //gdk_window_remove_filter(NULL, _wxgtk_global_hotkey_callback, this); 
+        ((Gdk.Window*)null)->remove_filter((Gdk.FilterFunc)on_hotkey);
+
+        base.stop();
+    }
+}
+
+public class PowerButton : zavai.Service
 {
+    protected DevInput devinput;
+
     public signal void power_button(Posix.timeval* time, bool pressed);
 
     public PowerButton()
     {
         // FIXME: change to event0 for the power button
         // FIXME: change to event4 for the aux button and headset button
-        //device = "/dev/input/event1";
-        Object(
-        name: "input.power_button",
-        device: "/dev/input/event0"
-    );
-
-        event += on_event;
+        string inputdev = "/dev/input/event0";
+        if (Posix.access(inputdev, Posix.R_OK) == 0)
+        {
+            zavai.log.info("Handle power button via " + inputdev);
+            // Listen via input device
+            devinput = new DevInput("input.power_button", "/dev/input/event0");
+            devinput.event += on_event;
+            devinput.request("powerbutton");
+        } else {
+            zavai.log.info("Handle power button via XGrabKey on keycode " + zavai.config.power_button_keycode.to_string());
+            // Listen via X
+            hotkeys.hotkey += on_hotkey;
+            hotkeys.grab(zavai.config.power_button_keycode, 0, false);
+            hotkeys.request("powerbutton");
+        }
     }
 
     protected bool on_event(LinuxInput.Event* ev)
@@ -149,8 +251,25 @@ public class PowerButton : DevInput
         }
         return true;
     }
+
+    protected bool on_hotkey(uint keycode, ulong time, bool pressed)
+    {
+        if (keycode == zavai.config.power_button_keycode)
+        {
+            // Convert X time to a fake timeval
+            // TODO: handle wraparound
+            Posix.timeval tv = {
+                (time_t)(time / 1000),
+                (long)((time % 1000) * 1000)
+            };
+            power_button(&tv, pressed);
+            return true;
+        }
+        return false;
+    }
 }
 
+
 /*
 # TODO:
 #  - hook into the headset plugged/unplugged event
@@ -293,10 +412,12 @@ class Audio:
 */
 
 
+public HotKeys hotkeys = null;
 public PowerButton power_button = null;
 
 public void init()
 {
+    hotkeys = new HotKeys();
     power_button = new PowerButton();
 }