hhpc icon indicating copy to clipboard operation
hhpc copied to clipboard

hhpc does not reset timer on mouse events

Open eazar001 opened this issue 10 years ago • 15 comments

I actually am succesfully working around the issue at the moment, and so far it is okay; but I thought it might help if I present the information to you:

  1. I modified your program to be a 'one-shot' program, where it grabs and hides the mouse, and when the mouse is active again (i.e. moved), it unhides the mouse and actually exits altogether.
  2. I created a small wrapper script in python that creates two threads, one thread (an interrupt thread) that activates only on mouse events, and sends an interrupt request signal to the other thread, which is the timer thread. The signal is simply a boolean variable that tells the timer thread to reset the timer.
  3. If the timer counts down successfully, a process is opened that externally calls your modified one-shot version of hhpc, and then instantly hides the mouse. While your program is running, the python script is blocking any further acitivity on its end. Once the mouse is moved, your program of course, quits. After this the script is unblocked the timer is again reset and the process repeats.
  4. Events are read from /input/dev via xev bindings in a python module. The script is daemonized as a systemd service to remove the need for any manual calls to root.

I didn't bother with profiling, but a quick examination of top showed me that the cpu usage ranged from 0-0.3% CPU usage. It was at 0 of course mainly when the mouse was hidden and/or grabbed by your program. Obviously this is not the most ideal solution, as it requires a wrapper script on top of your executable, and removal of almost half of your code (but it works). I just gave you this hoping it might help you find a more direct solution, and to suggest that (maybe) threading would be a good way to approach this.

eazar001 avatar Feb 13 '14 17:02 eazar001

Very interesting! It would indeed be necessary to have X.org or the kernel notify hhpc of any and all keyboard/mouse events, which would make it all very easy.

Would you happen to know if this /input/dev-way is cross-platform compatible? By that I mean portable to the BSD's?

If so, I think it could all be folded into one thread (I'm loath to start to multi-thread things as I want to keep it very simple, hackable and low-resource). A good way to do this would probably be to add a file descriptor (such as /dev/input/mice) to the select() call.

Is the source of your solution viewable?

EDIT: ugh, just noticed that you need root to even read from /dev/input...

aktau avatar Feb 13 '14 19:02 aktau

  1. Not sure about cross-platform compatible, I wouldn't be surprised if it wasn't, usually linux distros have just the right amount of variation to be annoying.
  2. You don't really have to remove entire chunks of your source code to get this one to work, you can simply comment out your line that says delay(timeout, 0);, and then add the line working=0; and that should suffice for testing on your end of the code (I think). As for my script, I put up a temporary repo so you can view the python wrapper. (Forgive the code, it's very hacky/sloppy), Link is here: https://github.com/eazar001/demo-hhpc-mod-script/blob/master/hhpcd.py

eazar001 avatar Feb 13 '14 19:02 eazar001

EDIT: ugh, just noticed that you need root to even read from /dev/input... --> Yea that is unfortunate, my workaround was using systemd to avoid the need for an explicit sudo or su root. But yea, just needing to get into root was annoying in its own way. = Unfortunately, even systemd is a default that is specific to Arch-Linux and a few others, but hopefully this can spawn some idea.

eazar001 avatar Feb 13 '14 19:02 eazar001

Ok, try the timer-reset-xorg branch if you will:

https://github.com/aktau/hhpc/tree/timer-reset-xorg

I believe it should be better, and use far less resources than the python wrapper, and it doesn't require root privileges. There's a snag though: I think it will stop working if you move from one window to another, but you should test this out on your WM. Please report back with your findings when you get the time ;)

aktau avatar Feb 13 '14 22:02 aktau

Well done again! As far as I can tell, moving across windows does not causing any noticeable bugs for me. I am, however, using Xmonad though, so I cannot speak for every other WM. Were you noticing such a bug on your end?

eazar001 avatar Feb 13 '14 23:02 eazar001

I didn't experience it, but according to the docs, we should've... I'll chalk it up to either me misunderstanding, bad docs or X.org being weird.

aktau avatar Feb 13 '14 23:02 aktau

Heh, I can live with that [=

eazar001 avatar Feb 13 '14 23:02 eazar001

Okay found a bug: resets on pointer motion, but not on button-press this time.

eazar001 avatar Feb 14 '14 07:02 eazar001

Also another major potential bug: It seems that the 'reset functionality' lost its behavior after hours of running. I did a system reboot just to make sure it wasn't ascribable to me. I'll test it for a few more days to make sure it's not a fluke.

eazar001 avatar Feb 14 '14 07:02 eazar001

Okay found a bug: resets on pointer motion, but not on button-press this time.

This is fully expected, unfortunately it seems that the X11 protocol doesn't allow delivering mouseclicks to multiple clients at the same time. Put another way: capturing mouseclicks only works when grabbing the pointer (owning it), which would immobilize the pointer. I haven't been able to get passive grabs to work...

Also another major potential bug: It seems that the 'reset functionality' lost its behavior after hours of running. I did a system reboot just to make sure it wasn't ascribable to me. I'll test it for a few more days to make sure it's not a fluke.

I didn't expect that, must be some flaw in my usage of xlib somewhere... a bit hard to debug like this though. Does it stop pointer hiding in general or just stop resetting the timer? Can you run with the -v switch? I know it prints a lot of info but it could be relevant to see what it prints when it stops resetting.

You sure are thorough ;)

aktau avatar Feb 14 '14 15:02 aktau

This is fully expected, unfortunately it seems that the X11 protocol doesn't allow delivering mouseclicks to multiple clients at the same time. Put another way: capturing mouseclicks only works when grabbing the pointer (owning it), which would immobilize the pointer. I haven't been able to get passive grabs to work...

Understood; this sounds about right, I do recall being harassed by stderr for attempting something of this sort. This leads me back to /dev/input, which just seems so much more cooperative at times. However, as you mentioned previously the whole root issue is quite troublesome. The biggest improvement I have come up with in terms of avoiding root while using /dev/input was to create a user group and add the current user to that adminstrative group on the system, given the premise that the new group is given unmitigated permission to access /dev/input of course. This method avoids requiring root calls, and as far as I can see, presents no security concerns. The main disadvantages I see: It would require a wiki/readme entry on your part, and it is not as easy and straightforward as your current setup.

I didn't expect that, must be some flaw in my usage of xlib somewhere... a bit hard to debug like this though. Does it stop pointer hiding in general or just stop resetting the timer? Can you run with the -v switch? I know it prints a lot of info but it could be relevant to see what it prints when it stops resetting.

I'm still not yet sure whether my meanderings are at least partly cuplable for the aberrance I observed. I'll try to find some time later to dedicate my computer to some qualified testing sessions, using the -v flag too. Overall, thanks for sticking with it and being a great dev! Perhaps I was a QA tester in my past life. [=

eazar001 avatar Feb 14 '14 20:02 eazar001

Possibly we could keep the current timer reset functionality and allow either a compile-time or run-time switch for those that also want resets on mouseclicks. That would compile in support for reading from /dev/input.

Overall, thanks for sticking with it and being a great dev! Perhaps I was a QA tester in my past life. [=

No problem ;)

aktau avatar Feb 15 '14 15:02 aktau

Alright, either a compile-time or run-time flag sounds good to me.

eazar001 avatar Feb 15 '14 17:02 eazar001

Sorry, this is not directly related to the original issue but since eazar001 mentioned a robustness problem in this thread, this is what I initially did in my hhpc-based implementation of similar feature to improve robustness:

  1. XGetInputFocus() can return PointerRoot, at least if no WM is running. (Not sure about None, but added it as well, just in case.)
XGetInputFocus(dpy, &win, &revertTo);
if (win == PointerRoot || win == None)
    win = RootWindow(dpy, DefaultScreen(dpy));
  1. Don't give up on grab failure:
if (!grabbed) continue;
  1. My code processes some control signals from external apps. Therefore, I switched select() to pselect() to avoid any potential race conditions.

P.S. In the end, I completely moved from Xlib to /dev/input interface + platform-specific hardware cursor on/off control. This proved to be more straightforward and just works better for our embedded product. Anyway, thank you both aktau and eazar001 for ideas!

linulin avatar Oct 01 '14 22:10 linulin

@linulin glad it helped! Some interesting notes you have

  1. Don't give up on grab failure:

I would be keen on doing something similar, but some grab failures are just that, real failures that aren't going to solve themselves. Do you remember the actual return code from XGrabPointer which should have been retried on? Perhaps I'm missing a possible case in grabPointer.

  1. XGetInputFocus() can return PointerRoot, at least if no WM is running. (Not sure about None, but added it as well, just in case.)

Hadn't thought of that at all, it should indeed be more robust (though this code isn't mainline yet).

  1. My code processes some control signals from external apps. Therefore, I switched select() to pselect() to avoid any potential race conditions.

I assume your app does more than just hide the mouse pointer, in which case that's probably a good idea indeed :).

Thanks for the input!

aktau avatar Oct 02 '14 07:10 aktau