OpenTK makes touching button raise click event differently than mouse - wpf

What I am trying to do: I am currently hosting an OpenTK glControl (through a WindowsFormsHost) in my WPF application. The application has many buttons, but we will focus on the pause and play buttons. I use VBO's and this is how I animate GL.DrawArrays(PrimitiveType.LineStrip, 0, frameCount );. It is drawing the range of vertices from 0 to framecount, so when I hit play, it just starts incrementing framecount, which starts animating. When just using a mouse, everything works perfectly.
The Problem: My app needs to work with a touch screen also (FWIW, when I say touch, WPF is seeing it as a stylus, not touch). When the app is NOT animating, touch works like it should, I don't handle touch events so touching buttons just raised the Click event. If we aren't animating, I don't have any problems. So when I use my mouse Click the play button, the UI still responds to my Mouse (clicks work, hovering changes colors as it should, etc), but then touches seemingly get ignored for some period of time. I have to touch a button 3 to 5 times before it does what it is supposed to (like pause). Lets go back and now we aren't animating, this time, if I TOUCH the play button to raise the Click event, it will start animating, but my touches now have the same problem of having to touch multiple times to raise Click event, and on top of that, the UI now does not respond to the mouse (the WindowsFormsHost still reacts to mouse events properly). Clicking on buttons or hovering over buttons doesn't do anything. It is not until I can get the animation to pause again that the UI starts responding to Mouse again.
What I have tried and what (I think) I know: When the UI stops responding to mouse input and touch input is messsed up, if I use MOUSE or TOUCH to click anywhere outside of my app, it works as expected. This leads me to believe it is not a touch screen driver problem or anything. I also used Snoop to see what events were being raised (or not) to see the stylus and the mouse being captured and released and what has focus. I could not find an instance where one was not released. If anyone would like, I can post Snoop results showing differences between mouse and touch clicking. I tried putting a preview mouse down on the MainWindow, but after TOUCHING play, no Mouse clicks raise this event, and the first touch after touching the play button touches randomly will fire this event. I also tried hiding the WindowsFormsHost, and mouse and touch clicks all work like they should minus the glControl. Because I hide the WindowsFormsHost, the paint event never gets fired, leading me to believe there might a problem with the paint function. I am aware of this bug WPF Touch Bug, however I don't really think that this is my problem. Something tells me the interop is what is giving me problems but I am not sure.
My Code:
private void playFwdFunc()
{
//disable undrawing and enable drawing
undraw = false;
draw = true;
//unpause animation
paused = false;
//enable/disable appropriate buttons
pauseBtn.IsEnabled = true;
stepBackBtn.IsEnabled = false;
stepFwdBtn.IsEnabled = false;
clearStart.IsEnabled = true;
clearCurrent.IsEnabled = true;
//refresh control
glControl1.Invalidate();
}
private void playFwdClick(object sender, RoutedEventArgs e)
{
playFwdFunc();
}
In my glPaint event:
if (frameCount < vertices.Length && !paused)
{
//draw more vertices
if (draw)
{
if (0 < (int)(vertices.Length / (25000 / speedTrack.Value)))
frameCount += (int)(vertices.Length / (25000 / speedTrack.Value));
else
frameCount++;
}
//draw less vertices
else if (undraw)
{
if (0 < (int)(vertices.Length / (25000 / speedTrack.Value)))
frameCount -= (int)(vertices.Length / (25000 / speedTrack.Value));
else
frameCount--;
}
//make sure we dont have a negative framecount (null pointer)
if (frameCount < 0)
{
paused = true;
frameCount = 0;
// manageCodeBox();
}
//make sure we dont exceed # of vertices (null pointer)
else if (frameCount > vertices.Length)
{
frameCount = vertices.Length;
paused = true;
// manageCodeBox();
}
}
My Question: Why is clicking a button with mouse making the UI react differently than touching a button, even though they raise the same event? Any input is appreciated.

So I found what was causing the behavior, in my paint function I was constantly raising an event that had a glControl1.Invalidate().
My Best Guess: My only real guess is that certain events like touches which occur on the stylus thread some how gets into a live-lock with the UI thread when calling glControl1.Invalidate(). I think that that is why some touches got accepted, but the UI thread never reached mouse event listeners. As I said: best guess.
My Workaround: I originally made a DispatcherTimer to call glControl1.Invalidate(). Mouse events worked fine, but because touches got promoted to mouse clicks, there was a delay unless I handled the touch event (which I did not want to do for each button on my UI). My next solution seems to be working so far.
In my windows constructor: CompositionTarget.Rendering += invalidateProcessor;.
The function:
private void invalidateProcessor(object sender, EventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => { if (!paused) glControl1.Invalidate(); }), DispatcherPriority.Background);
}
I chose DispatcherPriority.Background because the higher priorities cause a delay in the touches again.

Related

Enabling mouse in Allegro5

I am starting using Allegro in my program in C, but I'm having difficulties creating the buttons. I am using this kind of logic:
if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
{
if ((event.mouse.x >= 442) &&(event.mouse.x <= 471) &&(event.mouse.y >= 202) &&(event.mouse.y <= 238))
{
dig = '1';
entr = 1;
}
But this spaces defined by the axis are non 'clickable'.Somebody here has some tip about the typo of command I should use?
I can only guess what was wrong, but there is no answer yet, so I will provide some tips about the possible problem. Your thread is titled enabling the mouse in allegro 5, so I can only assume you're not getting mouse input.
1) You need to install the mouse driver before you will get any mouse input :
if (!al_install_mouse()) {Fail();}
2) The mouse needs to be registered with your event queue.
al_register_event_source(event_queue , al_get_mouse_event_source());
In a typical GUI, most buttons are only considered 'pressed' if they receive both a mouse button down event over their click area, AND a mouse button up event over the same area. This way you don't get a button press when you click on something else, move the mouse over your button and release it. You also prevent button events from pressing the mouse, moving it off the click area and releasing it.

GtkScrolledWindow Not Responding to Mouse Wheel Unless Cursor is over Scroll Bar

I have a C GTK3 application using a GtkScrolledWindow with a GtkGrid inside it. I'm happy with how everything is laid out, but the ScrolledWindow only scrolls via the mouse wheel if the cursor is over the scroll bar, or if I move the scroll bar with my cursor. The behavior I'm looking for is for the mouse wheel to always scroll the ScrolledWindow when the mouse wheel is used or at least when the cursor is over the ScrolledWindow (which is what I thought the default would be).
Here is where the ScrolledWindow is created :
scroll = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(scroll), BANNER_HIGHT * 4);
(The location of these lines in the application (GitHub))
I'm wondering now if I have to pass a GtkAdjustment to the constructor but it seems like all that does is set the scrolling bounds. I'm also wondering if I could connect a mousescroll event on the main window and try to trigger it manually on the callback, but I don't see a way to do that either.
This actually seems to be a bug in GTK and/or the OS (Ubuntu), I was trying to use the multi-touch scroll gesture on my laptop's trackpad to scroll and that wasn't working. Today, I happened to have a regular mouse with an actual scroll wheel plugged in and noticed it works just fine.
UPDATE: I added the behavior I was looking for by subscribing to scroll events and adjusting the Scrolled Window manually using a GtkAdjustment after all:
bool scroll_entrires(GtkWidget * widget, GdkEvent * event, gpointer data) {
double delta_x, delta_y; // delta_y is not used
if (gdk_event_get_scroll_deltas(event, &delta_x, &delta_y)) {
GtkAdjustment * adj = gtk_scrolled_window_get_vadjustment(
GTK_SCROLLED_WINDOW(scroll));
gtk_adjustment_set_value(adj,
gtk_adjustment_get_value(adj) + 30 * delta_y);
// 30 is a number that I like for my setup but can
// be changed for other situations.
return true; // We have responded to the event
}
return false; // Let other handlers respond to this event
}
// ... (In my init code)
g_signal_connect(window, "scroll-event", G_CALLBACK(scroll_entries), NULL);

WPF TouchDevice get absolute coordinates

I try to create a window, that can be moves or resized via multi-touch gestures. I tried it this way. I captures the TouchDown-Event of the window and saved all active TouchDevices in a List, to know which TouchDevices are active. I catch updated and deactivated event of the TouchDevices to know when they are moved and when they are deactivated. I save the Left and Top Property of the Window and the position where the TouchDevice started and everytime the Updated event is called I move the Window to the new Position relative to the new position of the TouchDevice. This works if I move the finger. But if I don't move the finger (or just very little) the window suddenly began shaking (moving chaotically) and then soon disappears to a position outside of the screen.
I think the problem here is, that the function "GetTouchPoint" of the TouchDevice only give relative coordinates related to the window (even if I set the parameter null instead if the window reference). And because the Window moves the relative position of the TouchDevice (that doesn't move) changes too. So I did a research but wasn't able to find a way to determine the screen coordinates of the touch device.
So I hope anyone can help me how to get the absolute coordinates of the TouchDevice. Or can help me find another way to "DragMove" the window with touch.(I tried DragMove, but that only works for mouse clicks, not TouchDowns) Also I like to resize the window when two Touch Devices are active and therefor I also need absolute coordinates because otherwise same effect happens.
I ran into this issue because my taskbar is on the right edge of the screen, effectively pushing the maximized window to the right. This issue also arises when the application's window is not maximized, and floating somewhere on the screen.
Here is an extension method that fixes the coordinates based on the application window's position.
public static Point FixCoordinates(this Point point)
{
var left = Application.Current.MainWindow.Left;
var top = Application.Current.MainWindow.Top;
return new Point(point.X + left, point.Y + top);
}
You may want to pass in a window that hosts your touched control as a parameter. In my case it is application's main window.
Also, since you tagged the question with "multi-touch", here is a method which averages multiple touch coordinates:
public static Point GetAverage(this IEnumerable<Point> points)
{
var averageX = points.Average(p => p.X);
var averageY = points.Average(p => p.Y);
return new Point(averageX, averageY);
}
And I use it in the code like this:
private void TouchAdornment_TouchDown(object sender, TouchEventArgs e)
{
var touchPosition = (sender as UIElement).TouchesOver.Select(t => t.GetTouchPoint(null).Position).GetAverage().FixCoordinates();
}

WPF Thumb DragDelta moving across monitors

I have a Popup control that I added a thumb to so I can drag it around the screen. The thumb's DragDelta event was overloaded with this:
private static void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Thumb thumb = (Thumb)sender;
Popup popup = thumb.Tag as Popup;
if (popup != null)
{
popup.HorizontalOffset += e.HorizontalChange;
popup.VerticalOffset += e.VerticalChange;
}
}
The Dragging works perfectly (I used the Dragging example from here: http://www.codeproject.com/Articles/43636/WPF-A-search), except for when the popup reaches the end of the monitor and crosses over to the other (dual monitor setup). For instance if I have the popup open on the Left monitor and start dragging it right, when the right border of it touches the edge of the monitor it's movement is erratic and starts moving all around until I move further right and it displays on the other monitor.
I debugged through this scenario, and this is a numerical example of basically what happens:
At edge of screen:
HorizontalOffset = 600
HorizontalChange = 1
Move Right:
HorizontalOffset = 601
HorizontalChange = -800
HorizontalOffset = -199
HorizontalChange = 401
HorizontalOffset = 200
HorizontalChange = -150
Which gives this weird strobe effect of the popup while it moves to the other monitor; Is there something I need to do to get it to transition smoothly across monitors?
I still haven't figured out how to un-bind pop-ups to a screen, but I was able to accomplish what I needed by using the Window control instead. I made WindowStyle.None so there was no border and overloaded the MouseLeftButtonDown event with a delegate to the DragMove() method so they can be dragged around the screen. This allowed me to have very similar look and feel as the pop-ups, but able to drag it around the screen with no flicker.

disable map movement from flicks

I have a map on which I dynamically display pushpins, and would like to interact with the pushpins without interacting with the map (so I can't just disable the map by setting IsEnabled="False", nor can I use an image of the map).
I've tried the techniques depicted here: Handling tap on Pushpin in a fixed Map, which work great for zooming, and panning.
Extending this idea I've set up event handlers for all the events that would seem to match:
Hold="map_Hold"
MapPan="map_MapPan"
MapZoom="Map_MapZoom"
ManipulationStarted="map_ManipulationStarted"
ManipulationDelta="map_ManipulationDelta"
ManipulationCompleted="map_ManipulationCompleted"
MouseLeftButtonDown="map_MouseLeftButtonDown"
MouseLeftButtonUp="map_MouseLeftButtonUp"
TargetViewChanged="map_TargetViewChanged"
ViewChangeStart="map_ViewChangeStart"
ViewChangeEnd="map_ViewChangeEnd"
ViewChangeOnFrame="map_ViewChangeOnFrame"
(in the event handlers I simply set e.Handled = true;)
Yet you can still pan the map by making flicking motions on it (like how you would flick to the next image in the photo app).
Is there a way to disable the map panning altogether?
Or is there a way to interact with the pins if IsEnabled="False"?
This post was a while ago so you probably have solved the problem by now. But I had this problem today and this is the solution I had. (it's not very elegant, but seems to work fine).
For me this problem occurred when letting go of a pushpin after dragging and dropping it - Even though I had disabled the map_pan event when dragging a pushpin, the map would still move from the 'flick' gesture which is created when letting go of a push pin after dragging and dropping it.
First of all, create a page scoped DespatchTimer and an int which will be our counter:
DispatcherTimer dti = new DispatcherTimer();
int counter =0;
Next, in the pushpin's MouseLeftButton up event, disabled your map, start the despatch timer with an interval of 1. Also create the Tick event handler for it.
private void pushpin_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Map.IsEnabled = false;
dti.Interval = new TimeSpan(0, 0, 0, 0, 1); // 1 Seconds
dti.Start();
dti.Tick += new EventHandler(dti_Tick);
//other code logic
}
Next, create dti_Tick event. Within the tick event, stop the despatch timer when it is the second iteration into the tick event and re-enable the map. Reset the counter for future use.
void dti_Tick(object sender, EventArgs e)
{
counter++;
if (counter>= 1)
{
dti.Stop();
Map.IsEnabled = true;
counter= 0;
}
}
This process will have stopped any 'flick' from occuring after your drag and drop pushpin logic. Clearly this code can be further optimised, but hope it is of some help to you.

Resources