Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

start of adding touch input #1898

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
05061f2
start of adding touch input
Pyrdacor Jan 14, 2024
5071a09
Added missing mouse update call for SDL backend
Pyrdacor Jan 14, 2024
53b77ef
Added touch device interface and touch finger struct
Pyrdacor Jan 14, 2024
952a717
Added gesture recognizer dummy and SDL touch device
Pyrdacor Jan 14, 2024
93d9fc1
Extended input contexts for touch devices
Pyrdacor Jan 14, 2024
ee06cdc
Implemented touch gesture recognizer
Pyrdacor Jan 14, 2024
0d7ffef
Some gesture recognizer improvements/adjustments
Pyrdacor Jan 14, 2024
ce5fcbb
Gesture recognizer adjustments
Pyrdacor Jan 14, 2024
0a662c5
Some more gesture recognizer adjustments
Pyrdacor Jan 14, 2024
1eeef24
Extended AndroidInputDemo for touch
Pyrdacor Jan 14, 2024
79588da
Improved touch device disposing
Pyrdacor Jan 14, 2024
bffb083
Updated public api
Pyrdacor Jan 14, 2024
82a8e0d
Added value range info for normalized touch finger props
Pyrdacor Jan 14, 2024
8570b0b
Fixed wrong finger down value
Pyrdacor Jan 14, 2024
dc017dd
Fixed finger move distance and added remark
Pyrdacor Jan 14, 2024
6779df9
Added double tap elapse handling for 3rd double tap behavior
Pyrdacor Jan 15, 2024
cff6e21
Zoom distance is now given in absolute values
Pyrdacor Jan 15, 2024
0798841
Zoom gesture now works with a single distance value
Pyrdacor Jan 15, 2024
8c8581e
Updated demo project for last commit change
Pyrdacor Jan 15, 2024
2f0042a
Added stuff to the public API for the 10th time or so ...
Pyrdacor Jan 15, 2024
d968f4f
Updated net 2.0 public API definition
Pyrdacor Jan 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.companyname.AndroidInputDemo">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true">
</application>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.AndroidInputDemo">
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true"></application>
<uses-sdk />
</manifest>
135 changes: 134 additions & 1 deletion examples/CSharp/OpenGL Demos/AndroidInputDemo/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public class MainActivity : SilkActivity
private static int counter = 0;

private static IInputContext input;
private static ITouchDevice currentTouchDevice;
private static Gesture trackedGestures = Gesture.All;
private static DoubleTapBehavior doubleTapBehavior = DoubleTapBehavior.EmitFirstSingleTap;
private static MultiGestureHandling multiGestureHandling = MultiGestureHandling.RecognizeBothGestures;

/// <summary>
/// This is where the application starts.
Expand Down Expand Up @@ -69,6 +73,15 @@ private unsafe static void OnLoad()

input.Keyboards[0].KeyChar += KeyChar;

if (input.PrimaryTouchDevice != null)
SetupTouchDevice(input.PrimaryTouchDevice);

input.ConnectionChanged += (device, connected) =>
{
if (connected && device is ITouchDevice touchDevice)
SetupTouchDevice(touchDevice);
};

Vbo = new BufferObject<float>(Gl, Vertices, BufferTargetARB.ArrayBuffer);
Vao = new VertexArrayObject<float, uint>(Gl, Vbo, null);

Expand All @@ -82,12 +95,96 @@ private unsafe static void OnLoad()
1.0f, 2.0f);
}

private static void GestureRecognizer_Rotate(Vector2 position, float angle)
{
DebugLog($"Rotate gesture at {position} with rotation {angle} degree");
}

private static void GestureRecognizer_Zoom(Vector2 position, Vector2 zoom)
{
DebugLog($"Zoom gesture at {position} with zoom {zoom}");
}

private static void GestureRecognizer_Hold(Vector2 position)
{
Gl.ClearColor(1.0f, 0.0f, 0.0f, 1.0f);
DebugLog($"Hold gesture at {position}");
}

private static void GestureRecognizer_Swipe(Vector2 direction)
{
DebugLog($"Swipe gesture with direction {direction}");
}

private static void GestureRecognizer_DoubleTap(Vector2 position)
{
Gl.ClearColor(0.0f, 0.0f, 1.0f, 1.0f);
DebugLog($"Double Tap gesture at {position}");
}

private static void GestureRecognizer_Tap(Vector2 position)
{
Gl.ClearColor(0.0f, 1.0f, 0.0f, 1.0f);
DebugLog($"Tap gesture at {position}");
}

private static void KeyChar(IKeyboard arg1, char arg2)
{
if (arg2 == 'c')
Array.Clear(Vertices);
if (arg2 == 'k')
input.Keyboards[0].EndInput();
if (arg2 == 't')
ToggleGesture(Gesture.Tap);
if (arg2 == 'd')
ToggleGesture(Gesture.DoubleTap);
if (arg2 == 's')
ToggleGesture(Gesture.Swipe);
if (arg2 == 'h')
ToggleGesture(Gesture.Hold);
if (arg2 == 'z')
ToggleGesture(Gesture.Zoom);
if (arg2 == 'r')
ToggleGesture(Gesture.Rotate);
if (arg2 == '0')
SetDoubleTapBehavior(DoubleTapBehavior.WaitForDoubleTapTimeElapse);
if (arg2 == '1')
SetDoubleTapBehavior(DoubleTapBehavior.EmitFirstSingleTap);
if (arg2 == '2')
SetDoubleTapBehavior(DoubleTapBehavior.EmitBothSingleTaps);
if (arg2 == '7')
SetMultiGestureHandling(MultiGestureHandling.RecognizeBothGestures);
if (arg2 == '8')
SetMultiGestureHandling(MultiGestureHandling.PrioritizeZoomGesture);
if (arg2 == '9')
SetMultiGestureHandling(MultiGestureHandling.PrioritizeRotateGesture);
}

private static void ToggleGesture(Gesture gesture)
{
if (trackedGestures.HasFlag(gesture))
trackedGestures &= ~gesture;
else
trackedGestures |= gesture;

if (currentTouchDevice?.GestureRecognizer != null)
currentTouchDevice.GestureRecognizer.TrackedGestures = trackedGestures;
}

private static void SetDoubleTapBehavior(DoubleTapBehavior doubleTapBehavior)
{
MainActivity.doubleTapBehavior = doubleTapBehavior;

if (currentTouchDevice?.GestureRecognizer != null)
currentTouchDevice.GestureRecognizer.DoubleTapBehavior = doubleTapBehavior;
}

private static void SetMultiGestureHandling(MultiGestureHandling multiGestureHandling)
{
MainActivity.multiGestureHandling = multiGestureHandling;

if (currentTouchDevice?.GestureRecognizer != null)
currentTouchDevice.GestureRecognizer.MultiGestureHandling = multiGestureHandling;
}

private static void MouseDown(IMouse arg1, MouseButton arg2)
Expand Down Expand Up @@ -131,5 +228,41 @@ private static void OnClose()
Vao.Dispose();
Shader.Dispose();
}

private static void SetupTouchDevice(ITouchDevice touchDevice)
{
if (currentTouchDevice == touchDevice)
return;

TouchGestureRecognizer gestureRecognizer;

if (currentTouchDevice != null)
{
gestureRecognizer = currentTouchDevice.GestureRecognizer;
gestureRecognizer.Tap -= GestureRecognizer_Tap;
gestureRecognizer.DoubleTap -= GestureRecognizer_DoubleTap;
gestureRecognizer.Swipe -= GestureRecognizer_Swipe;
gestureRecognizer.Hold -= GestureRecognizer_Hold;
gestureRecognizer.Zoom -= GestureRecognizer_Zoom;
gestureRecognizer.Rotate -= GestureRecognizer_Rotate;
}

currentTouchDevice = touchDevice;
gestureRecognizer = currentTouchDevice.GestureRecognizer;
gestureRecognizer.TrackedGestures = trackedGestures;
gestureRecognizer.DoubleTapBehavior = doubleTapBehavior;
gestureRecognizer.MultiGestureHandling = multiGestureHandling;
gestureRecognizer.Tap += GestureRecognizer_Tap;
gestureRecognizer.DoubleTap += GestureRecognizer_DoubleTap;
gestureRecognizer.Swipe += GestureRecognizer_Swipe;
gestureRecognizer.Hold += GestureRecognizer_Hold;
gestureRecognizer.Zoom += GestureRecognizer_Zoom;
gestureRecognizer.Rotate += GestureRecognizer_Rotate;
}

private static void DebugLog(string message)
{
Android.Util.Log.Debug(nameof(AndroidInputDemo), message);
}
}
}
}
27 changes: 27 additions & 0 deletions src/Input/Silk.NET.Input.Common/Enums/DoubleTapBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Silk.NET.Input
{
/// <summary>
/// Controls the behavior of the double tap gesture tracking.
/// </summary>
public enum DoubleTapBehavior
{
/// <summary>
/// Always emit the first tap as a single tap.
/// </summary>
EmitFirstSingleTap,

/// <summary>
/// Always emit the first and second tap as single taps.
/// </summary>
EmitBothSingleTaps,

/// <summary>
/// Do not emit single taps and wait for the double tap time to elapse.
/// The first single tap is only emitted after the time has elapsed.
/// </summary>
WaitForDoubleTapTimeElapse
}
}
54 changes: 54 additions & 0 deletions src/Input/Silk.NET.Input.Common/Enums/Gesture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace Silk.NET.Input
{
/// <summary>
/// Recognizable touch gesture.
/// </summary>
[Flags]
public enum Gesture
{
/// <summary>
/// No gesture.
/// </summary>
None = 0,

/// <summary>
/// Tap gesture.
/// </summary>
Tap = 1,

/// <summary>
/// Double tap gesture.
/// </summary>
DoubleTap = 2,

/// <summary>
/// Swipe gesture.
/// </summary>
Swipe = 4,

/// <summary>
/// Long hold gesture.
/// </summary>
Hold = 8,

/// <summary>
/// Zoom gesture.
/// </summary>
Zoom = 16,

/// <summary>
/// Rotate gesture.
/// </summary>
Rotate = 32,

/// <summary>
/// All gestures.
/// </summary>
All = Tap | DoubleTap | Swipe | Hold | Zoom | Rotate
}
}
26 changes: 26 additions & 0 deletions src/Input/Silk.NET.Input.Common/Enums/MultiGestureHandling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Silk.NET.Input
{
/// <summary>
/// Controls the behavior of how multiple two-finger gestures are handled.
/// </summary>
public enum MultiGestureHandling
{
/// <summary>
/// Only recognize the zoom gesture if both the zoom and the rotate gesture are performed.
/// </summary>
PrioritizeZoomGesture,

/// <summary>
/// Only recognize the rotate gesture if both the zoom and the rotate gesture are performed.
/// </summary>
PrioritizeRotateGesture,

/// <summary>
/// Recognize both gestures if they are performed (zoom and rotate).
/// </summary>
RecognizeBothGestures
}
}
19 changes: 19 additions & 0 deletions src/Input/Silk.NET.Input.Common/Interfaces/IInputContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,25 @@ public interface IInputContext : IDisposable
/// </remarks>
IReadOnlyList<IMouse> Mice { get; }

/// <summary>
/// A list of all available touch devices.
/// </summary>
/// <remarks>
/// On some backends, this list may only contain 1 item. This is most likely because the underlying API doesn't
/// support multiple touch devices.
/// On some backends, this list might be empty. This is most likely because the underlying API doesn't
/// support touch devices.
/// </remarks>
IReadOnlyList<ITouchDevice> TouchDevices { get; }

/// <summary>
/// The primary touch device if any.
/// </summary>
/// <remarks>
/// On some backends this might just be an educated guess. Or might be null even though there are touch devices.
/// </remarks>
ITouchDevice? PrimaryTouchDevice { get; }

/// <summary>
/// A list of all other available input devices.
/// </summary>
Expand Down
48 changes: 48 additions & 0 deletions src/Input/Silk.NET.Input.Common/Interfaces/ITouchDevice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Numerics;

namespace Silk.NET.Input
{
/// <summary>
/// An interface representing a touch device.
/// </summary>
public interface ITouchDevice : IInputDevice, IDisposable
{
/// <summary>
/// The known fingers this touch device has tracked.
/// </summary>
// ReSharper disable once ReturnTypeCanBeEnumerable.Global
IReadOnlyDictionary<long, TouchFinger> Fingers { get; }

/// <summary>
/// A recognizer for gestures.
/// </summary>
TouchGestureRecognizer GestureRecognizer { get; }

/// <summary>
/// Checks if a specific finger is currently down on the touch surface.
/// </summary>
/// <param name="index">The finger index to check.</param>
/// <returns>Whether or not the finger is pressed down.</returns>
bool IsFingerDown(long index);

/// <summary>
/// Called when a finger touches the surface.
/// </summary>
event Action<ITouchDevice, TouchFinger>? FingerDown;

/// <summary>
/// Called when a finger is lifted from the surface.
/// </summary>
event Action<ITouchDevice, TouchFinger>? FingerUp;

/// <summary>
/// Called when the finger is moved while on the surface.
/// </summary>
event Action<ITouchDevice, TouchFinger, Vector2>? FingerMove;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public void Dispose()
public abstract IReadOnlyList<IJoystick> Joysticks { get; }
public abstract IReadOnlyList<IKeyboard> Keyboards { get; }
public abstract IReadOnlyList<IMouse> Mice { get; }
public abstract IReadOnlyList<ITouchDevice> TouchDevices { get; }
public abstract ITouchDevice? PrimaryTouchDevice { get; }
public abstract IReadOnlyList<IInputDevice> OtherDevices { get; }
public abstract event Action<IInputDevice, bool>? ConnectionChanged;
}
Loading
Loading