I am trying to detect a horizontal swipe gesture with GestureRecognizer by hooking up to the CrossSliding event.
_gr = new GestureRecognizer
{
GestureSettings = GestureSettings.ManipulationTranslateX |
GestureSettings.ManipulationTranslateY |
GestureSettings.CrossSlide
};
_gr.CrossSliding += OnSwipe;
_gr.ManipulationStarted += OnManipulationStarted;
_gr.ManipulationUpdated += OnManipulationUpdated;
_gr.ManipulationCompleted += OnManipulationCompleted;
_gr.CrossSlideHorizontally = true;
As you can see from the code above, not only swipe should be detected, but also dragging gestures.
My problem is I can't seem to customize the swipe gesture.
I want to customize the minimum speed and distance a user has to drag the pointer before the gesture is considered a swipe. In the current state even the slowest and smallest horizontal drag motion will trigger a CrossSliding event.
I saw the CrossSlideThresholds class that allows to customize the gesture, but I couldn't see how it could be used to configure speed and distance of the swipe gesture.
Is the CrossSliding event the proper way to detect a swipe? If so, how can I configure speed and swipe distance?
If not, how can I detect a swipe gesture?
I could not find any built in way to detect a swipe, so I implemented my own detection method.
The code detects a horizontal swipe.
The shown methods are the event handlers for the GestureRecognizer events:
readonly Stopwatch _manipulationTimer = new Stopwatch();
public void OnManipulationStarted(ManipulationStartedEventArgs e)
{
_manipulationTimer.Restart();
}
public void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
var millis = _manipulationTimer.ElapsedMilliseconds;
if (Math.Abs(e.Cumulative.Translation.Y) < MaxVerticalSwipeDistanceInPix &&
Math.Abs(e.Cumulative.Translation.X) > MinHorizontalSwipeDistanceInPix &&
millis > MinSwipeDurationInMillis &&
millis < MaxSwipeDurationInMillis &&
Math.Abs(e.Cumulative.Scale - 1) < 0.01 // 1 touch point
)
{
var leftSwipe = e.Cumulative.Translation.X < 0;
if (leftSwipe)
{
}
else // right swipe
{
}
}
_manipulationTimer.Stop();
_manipulationTimer.Reset();
}
Related
I need some really accurate way to determine when surface dial rotation end:
private void OnRotationChanged(RadialController sender, RadialControllerRotationChangedEventArgs args)
{
double angle = args.RotationDeltaInDegrees;
}
I stay really lost about how can determine in ultra accurate way when rotation end.
This is my first try but work super erratic.
bool start = true;
private void OnRotationChanged(RadialController sender, RadialControllerRotationChangedEventArgs args)
{
if (start == true)
{
start = false;
//send mouse left down event relative to mouse position
VirtualMouse.LeftDown(0, 0);
}
if (timer != null)
{
timer.Tick -= timer_Tick;
}
timer = new DispatcherTimer { Interval = TimeSpan.FromMillisecond(10) };
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
if (args.RotationDeltaInDegrees > 0)
{
//move mouse 1 pixel + Y relative to mouse postion
VirtualMouse.Move(0, 1);
}
else
{
//move mouse 1 pixel - Y relative to mouse postion
VirtualMouse.LeftDown(0, -1);
}
}
void timer_Tick(object sender, EventArgs e)
{
start = true;
//release the left mouse down relative to mouse position
VirtualMouse.LeftUp(0, 0);
}
When I said accurate, I mean some way to detect in any scenario.
Example, if you rotate slow and timer is around 1ms, every new event from dial (rotated slow) never reach the unhook in time. If I increase the timer all the whole detection result in a non accurate process adding non desired latency.
I know this not is the way to go, just testing, but not idea how can achieve a proper detection in scenarios when I rotate the dial slow, or faster for obtain a real indicator the dial stop of rotate or is rotating.
Determine when rotation start is a cake, but rotarion end?
Surface dial can provide precision of 0.1 degres, is really accurate optical device. So one complete rotation is capable of provide 3600 events/angles report.
......dont know, thinking and thinking.
I am doing a project about a chess-like game, so players own their pawns on the map. Every time player decides to move a pawn, he needs to get a number from a dice, then that pawn would move according to the rolled number. Move function of pawns is finished, but I didn't show the moving process for them.
I have one panel for map and four panels for starting base(holding the pawns at the beginning of the game).
GUI for gameboard
In paint event, I ask the system to draw everything.
private void P_Map_Paint(object sender, PaintEventArgs e)
{
manager.VisualizeCollection(map, gr_map);
manager.VisualizeStartingBase(bases, grs);
manager.VisualizePawns(manager.Players, grs, gr_map);
manager.DisplayAvailablePawn(gr_map, grs);
manager.DisplaySelectedPawn(gr_map, grs);
}
For every move of a pawn, I am trying to use a timer to make the image moving on the screen.
public void DoMovement(Pawn pawn)
{
if (TargetSpot != null)
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
EventHandler t_tick = null;
Point targetP = TargetSpot.Location;
Point currentP = pawn.ImageLocation;
int XMove = (targetP.X - currentP.X) / 10;
int YMove = (targetP.Y - currentP.Y) / 10;
Rectangle drawRange = new Rectangle(pawn.ImageLocation.X - (int)(0.5 * pawn.Image.Width),
pawn.ImageLocation.Y - (int)(0.5 * pawn.Image.Height), pawn.Image.Width, pawn.Image.Height);
t_tick = (senders, args) =>
{
if (currentP.X > targetP.X - XMove || currentP.X < targetP.X + XMove)
{// if the image of the pawn doesn't reach the destination
//we keep moving it and ask the pawn to redraw the old place
pawn.ImageLocation = new Point(currentP.X + XMove, currentP.Y + YMove);
pawn.CurrentPanel.Invalidate(drawRange);
}
else
{
pawn.CurrentLocation.LeaveAPawn(pawn);
pawn.CurrentLocation = TargetSpot;
TargetSpot.AddAPawn(pawn);
pawn.CurrentPanel.Invalidate(drawRange);
}
};
t.Tick += t_tick;
t.Interval = 300;
t.Start();
}
}
This is not working fine, everything on the panel is still redrawing. Why?
Excepting the project, I do have a question about the invalidating a region. Like I told the rules of drawing to paint event, then the panel invalidates itself. When we are going to invalidate a region, how the system knows the rule about drawing?
I am writing a program using the Surface SDK and .NET 4.0. I have to distinguish between multi-touch events and I'm having trouble distinguishing between gestures.
With two fingers I want to be able to zoom and rotate, but because generally the fingers are not moving in straight lines or perfect circles on the screen, the result is a combination of zoom and rotate. Could someone point out how this problem can be overcome? I am using some thresholds for ignoring small deviations, but these thresholds need to be manually tweaked and I couldn't find a good value for them.
I was thinking I could detect which kind of a gesture it is in the onManipulationStarting method and ignore the rest, but sometimes the gesture can start with just one finger on the screen and I'm identifying the wrong gesture.
I am including some code below:
private void OnManipulationDeltaHandler(object sender, ManipulationDeltaEventArgs mdea)
{
var zoomAmount = Math.Abs(mdea.DeltaManipulation.Scale.Length - Math.Sqrt(2));
// ZOOM ACTION: 2 fingers and scaling bigger than a threshold
if ((TouchesOver.Count() == 2) && (zoomAmount > scaleThreshold))
{
if (ZoomCommand != null)
{
if (Math.Abs(zoomAmount - 0) > 0.1)
{
ZoomCommand.Execute((-zoomAmount).ToString());
}
}
}
else
{
var rotateAmount = -mdea.DeltaManipulation.Rotation;
if ((TouchesOver.Count() == 2))
{
headValue += rotateAmount;
if (HeadRotationCommand != null)
{
HeadRotationCommand.Execute(new Orientation(pitchValue, headValue, rotateAmount));
}
}
}
mdea.Handled = true;
base.OnManipulationDelta(mdea);
}
Can someone help? Thanks!
I'm using a simple ChartPlotter in my C# WPF application. When I zoom in/out by mouse scrolling, both Axis are changed. How can I control the zooming by mouse scrolling so it will affect only the X-Axis?
This feature is already built into D3, if you hover your mouse over one of the axes, and do a mouse wheel scroll, the zoom is only pertained to the axis you were hovered over. If you want to replicate this in your code, you can see examples of it in the source code.
The zoom feature is implemented in "MouseNavigation.cs". The MouseWheel handler will call underneath function:
Viewport.Visible = Viewport.Visible.Zoom(zoomTo, zoomSpeed);
And fortunately, there is a ZoomX function for your needs.
Thus just remove MouseNavigation from your plotter, then re-implement your own as below:
// Remove mouse navigation
plotter.Children.Remove(plotter.MouseNavigation);
// ZoomX when wheeling mouse
private void plotter_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
{
if (!e.Handled)
{
Point mousePos = e.GetPosition(this);
Point zoomTo = mousePos.ScreenToViewport(plotter.Viewport.Transform);
double zoomSpeed = Math.Abs(e.Delta / Mouse.MouseWheelDeltaForOneLine);
zoomSpeed *= 1.2;
if (e.Delta < 0)
{
zoomSpeed = 1 / zoomSpeed;
}
plotter.Viewport.SetChangeType(ChangeType.Zoom);
plotter.Viewport.Visible = plotter.Viewport.Visible.ZoomX(zoomTo, zoomSpeed);
plotter.Viewport.SetChangeType();
e.Handled = true;
}
}
How can you read two gestures at the same time. I'm currently developing a game where two players should use the FreeDrag gesture.
What happens now is:
When player A starts, and he is dragging it works perfectly. If player B then also starts it's FreeDrag gesture, the TouchPanel.ReadGesture(); doesn't register it until player A's gesture is finished.
I use the following code:
In Initialize()
TouchPanel.EnabledGestures = GestureType.FreeDrag;
In Update()
if (TouchPanel.IsGestureAvailable)
{
GestureSample touch = TouchPanel.ReadGesture();
if (touch.GestureType == GestureType.FreeDrag)
{
if (touch.Position.Y > GraphicsDevice.Viewport.Height/2)
{
//logic Player A here
}
else
{
//logic Player B there
}
}
}
You have an example in the MSDN documentation:
http://msdn.microsoft.com/en-us/library/ff827740.aspx
// get any gestures that are ready.
while (TouchPanel.IsGestureAvailable)
{
GestureSample gs = TouchPanel.ReadGesture();
switch (gs.GestureType)
{
case GestureType.VerticalDrag:
// move the poem screen vertically by the drag delta
// amount.
poem.offset.Y -= gs.Delta.Y;
break;
case GestureType.Flick:
// add velocity to the poem screen (only interested in
// changes to Y velocity).
poem.velocity.Y += gs.Delta.Y;
break;
}
}
You can't, FreeDrag isn't a multitouch gesture, you should try using TouchLocation and TouchCollection which let you detect multitouch. Unfortunately you can't use default gestures you've declared in TouchPanel.EnabledGestures.