I've created a TCustomControl derived class for a VCL application running on a Windows 8.1 tablet.
I'm using the OnMouseDown / OnMouseUp events even though this is obviously touch based.
What I'd like to do is detect a long press - i.e. touch down and hold for 1 second. So in the OnMouseDown event I record the down timestamp, set a flag to indicate the mouse is down and create an anonymous thread which sleeps for 1 second, and then checks the flag.
In OnMouseUp I set the flag to false.
This works as long as you wiggle your finger on the control. Otherwise if you just touch and hold the mouse down event is not called until you release your finger.
I've look at gestures, but that just looks completely overkill and from what I understand doesn't support long press anyway.
Thanks for any suggestions.
Richard
What you're facing is "normal" yet ridiculously stupid behaviour of Windows with touch input devices. We're facing the same issue for a while now, and are trying to solve it actively for the last couple weeks.
The trick is, that windows handles touch input device as "mouse, that can be fully controlled with single finger". Therefore, it has several states, more than events:
Events are: Touch begin (down), move, up, right click, and if you really want to register for a callback you'll get stationary (not moved since last report but still down).
Meanwhile, there are more states. First, when you press your finger down, it internally detects "Touch down!" event. It than waits a certain amount of time (which might or might not be available to hack-change, depends on drivers etc...), to determine whether what you wanted was a right click (after x time, upon release !before Y time! it will fire right click event) or whether it was a left click down (triggering event TouchBegin - after y time, which is LONGER than x-time, and after the y expires, it will fire left down event (not click!)).
Meanwhile, if the first touch down is interrupted by either move or - !! while waiting for x time to expire!! release of the finger BEFORE x time is ran out, it will automatically trigger left down (on move) or left click (on release). Same goes for any time after the Y time expires as well, or MOVE is triggered.
To put it more simply and understandable, I'll try to give an example:
Let's say that you have touch device, and the timings are as follows:
Point B is beginning, positioned at 0 seconds of our timeline.
Point X is first trigger breakpoint, positioned at 5 seconds of our timeline.
Point Y is second trigger breakpoint, positioned a 10 seconds of our timeline.
You put your finger on touch, and that starts the timeline.
Possible scenarios:
- You release it anytime before point X -> Left click is triggered (Touch down and up events, in order immediately one after another)
- You release it after point X but before point Y -> Right click is triggered (Touch down and up events, with right click flag)
- You reach point Y - Left down is triggered!
- You release it after point Y anytime, no matter if move triggers between release or not (but move is NOT triggered before reaching this point in timeline) -> Left up is triggered.
You trigger (do) move event before reaching point X -> Left down is triggered, followed by as many move events as it detects it, until you release it -> then left up is triggered
You trigger (do) move event after X but before Y -> same as above!
You reach point Y and move it afterwards -> check point no4 above.
Hope this is making any sense to you.
Now to jump to the possible solutions: Custom driver would be one option, but we're not there yet, so we're still trying other options. The most promising for now seems to be use of RAW_INPUT and Touch hooks, looks like we'll have to combine them to get what we want tho.
The bright side is, that windows itself DOES detect when finger touches the device, regardless of the timings and events that it wants to detect, determine and then forward to apps, but they for some reason made it hard to use in such nature. As a proof you could simply check the transparent dot that appears underneath your finger the very first moment you touch the screen.
Meanwhile, Android handles these things way better...
Hope it helps, and I'm happy to come around with the complete solution once we come through and get something good enough for usage.
M.*
If the MouseDown event is not triggered and you want to make your delay counter dependent on it then you are basically screwed. That said, I assume you are open to slight changes of concept. :)
I think it can still be done if you change your button into something like a flip-switch. The user has to "grab" (touch) it, "pull it up" (drag, should trigger StartDrag event) and hold it there for the desired amount of time. Upon release of the switch (MouseDown event), it snaps back down.
To design such a button, you could use a tiny TPanel for the knob and a slightly larger one for allowing limited vertical movement on it. Set BevelInner property to bvLowered and BevelOuter to bvRaised to make it look like a frame and the knob panel its child. Or use a TImage to display the knob in it's up/down positions. In any case, set the knob element's DragKind property to dkDrag or the StartDrag event won't occur. If still no event is fired, please try to detect touch input capabilities and report your findings..
Not sure this qualifies for an answer but maybe it's worth a swing.
Related
I have modified the Google Cardboard DemoScene with my own UI text buttons. By default, these buttons respond to Onclick() or tap events to trigger actions. I would like to trigger these actions when the user sets their gaze on the object for 2 seconds.
I suspect I need to add some kind of conditional statement in the GazeInputModule but I can't figure out how to measure the time. Can anyone point me in the right direction? Is this the right approach or should I try something else? This is all still pretty new to me so even basic tips are very helpful!
Here's how I enabled a button click on a timed gaze. In my case I created a button to load the next scene.
I created a scene in my Unity game, so I didn't start off with modifying the Google Cardboard DemoScene, but the principles are similar.
Create a script named "LoadSceneButton.cs" (or whatever suitable name such as "TimedGazeButton.cs" and attach it to the button you want to enable the timed gaze on. See sample script http://pastebin.com/CXd6HA3C
On the button, add the "Event Trigger" component and set triggers - see screenshot Timed gaze button Event Triggers
Pointer Enter to the button's LoadSceneButton.SetGazedAt, and check the box to pass in the TRUE value. This indicates that user has started gazing at the object.
Pointer Exit to the button's LoadSceneButton.SetGazedAt, and uncheck the box to pass in the FALSE value. This indicates that user has stopped gazing at the object and has moved the reticle somewhere else.
The "LoadSceneButton.cs" will start timing the gaze when user's reticle moves into the button. Once the gaze time has reached a particular duration, the button's OnClick event is invoked. If the user moves the reticle away before that time, the timer is reset.
The version of Unity I used was Google Daydream Technical Preview v5.4.2f2-GVR12 dated 10th November 2016, with Google GVR SDK 1.0.3.
I have a FPS game and using mouse look. I use Mouse.SetPosition to set the mouse position back to center of the game window at every frame. This works great and the mouse look is working very good. The problem is this takes over mouse position for every windows app. If I alt tab to another app, the mouse constantly tries to goto the center of the game window. This seems like very bad behavior. Any idea how to fix this behavior but still allow my mouse look to still work?
It has to do with User32.dll
I was programing an autoclicker to do my homework (AI) simple
And this website helped me alot...
http://www.codeproject.com/Articles/32556/Auto-Clicker-C
So my problem is that I have a TJvDocServerForm with an image inside, now all functionality works when its pinned, however when its unpinned and I try to use the mousewheel to zoom, the form hides straight after the zoom operation.
The zoom works through a scrollboxmousewheel event that triggers a
timer.
The timer then redraws the larger/smaller image through my own
image class when movement on the mousewheel has stopped.
Through break points it appears the draw is causing the form to
hide.
I believe this has got something to do with the focus being lost, however resetting the focus back to he form directly after the draw does not stop the hide as it has already been told to hide.
Is there a way to somehow lock the form from hiding until after the image has been redrawn?
This functionality (the unpinning thing) is rarely used. This code is extremely complex, and changing it is not recommended unless you like causing regressions. How common is the combination of mouse wheel + unpinning? So rare, I'd let it go, if I were you. If you can live without the unpin feature at all, just change dock styles. Personally I hate the unpinned state and I use a dock style that doesn't even support it. The unpinned "zoom away" animation may be directly linked to the focus-loss. You could store that state, wait until the next time through the message loop and then trigger the animation, if you wanted to, but even I, who have done lots of work in JvDocking source code, would be hesitant to try it.
I'm wondering if there's an easy way to tell which input device triggered a particular GUI event.
For example: A TButton.OnClick event gets fired. Did the user trigger it with a keyboard press (shortcut, Enter key for default button, space key for a focused button, etc.) or was it triggered with a mouse click? Is there any easy way to tell?
The reason I'd like to know is so that I can implement keyboard usage hints into some of our applications when the user uses the mouse to initiate actions that could also be done with the keyboard. Our systems on the shop floor are in pretty dusty/dirty environments, and mice tend to not hold up so well in them. Also, in many cases, there's simply not that much room for a mouse to be used. (No, keyboards without numeric keypads is not a solution. They're relied on too heavily.)
However, since our apps run in Windows, users tend to simply use the programs like they would at home -- with a mouse. There's nothing particularly wrong with that, but we've worked hard to optimize the input workflow to be keyboard friendly as well. It'd be nice if there was a low-impact way to indicate to our users that there's a way for them to do the things they're doing without having to grab the mouse.
There's no way to tell from within OnClick. However, you can also attach events to a control that will fire when the mouse rolls over it, which would probably be more appropriate for what you're trying to do anyway. Take a look at the OnMouseEnter and OnMouseLeave events. Also, if you really want something specific to happen when the mouse is clicked, you can attach it to OnMouseUp.
I have the following situation
I handle when the left mouse button is pressed in my Silverlight app and do some things while the mouse is held down and the mouse moves. When the left button is released, I turn off the flag that's telling it to do the stuff and the mouse movement handler then no longer does the stuff.
The problem is: if the user is in the control area, pushes the left button down and moves out of the control area, then releases the button and reenters, the MouseLeftButtonUp event never fires and the processing continues until the user clicks the mouse.
My temporary fix was to turn the mouse flag off on MouseLeave but that's not really what I'm going for. I'd like to check to see the mouse's left button state in the MouseEnter event, but I don't know of a way to do that.
Does anyone know of a way I can access the mouse button state outside of the press events in Silverlight 3? Thanks,
Update
After thorough research, it doesn't look like this is possible in Silverlight 2 (and probably 3.) I found this link. If anyone knows of a workaround, please let me know.
What you need to do can be accomplished with the UIElement.CaptureMouse method:
http://msdn.microsoft.com/en-us/library/system.windows.uielement.capturemouse%28VS.95%29.aspx
When a UIElement has captured the mouse, it will continue to receive mouse events even if the mouse leaves the Silverlight control.