Skip to content

Commit 10fc9e3

Browse files
committed
Update proposal to add 'virtual pointers'
1 parent 8dba362 commit 10fc9e3

File tree

1 file changed

+57
-28
lines changed

1 file changed

+57
-28
lines changed

documentation/proposals/Proposal - Multi-Backend Input.md

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,9 @@ public readonly record struct ConnectionEvent(IInputDevice Device, long Timestam
277277
public readonly record struct KeyChangedEvent(IKeyboard Keyboard, long Timestamp, Button<KeyName> Key, Button<KeyName> Previous, bool IsRepeat, KeyModifiers Modifiers);
278278
public readonly record struct KeyCharEvent(IKeyboard Keyboard, long Timestamp, char? Character);
279279
public readonly record struct ButtonChangedEvent<T>(IButtonDevice<T> Device, long Timestamp, Button<T> Button, Button<T> Previous) where T : struct, Enum;
280-
public readonly record struct PointChangedEvent(IPointer Pointer, long Timestamp, TargetPoint? OldPoint, TargetPoint Point);
280+
public readonly record struct PointChangedEvent(IPointer Pointer, long Timestamp, TargetPoint? OldPoint, TargetPoint? NewPoint);
281281
public readonly record struct PointerGripChangedEvent(IPointer Pointer, long Timestamp, float GripPressure, float Delta);
282+
public readonly record struct PointerTargetChangedEvent(IPointer Pointer, long Timestamp, IPointerTarget Target, bool IsAdded, Box3F<float> OldBounds, Box3F<float> NewBounds);
282283
public readonly record struct MouseScrollEvent(IMouse Mouse, long Timestamp, TargetPoint Point, Vector2 WheelPosition, Vector2 Delta);
283284
public readonly record struct PointerClickEvent(IPointer Pointer, long Timestamp, TargetPoint Point, MouseButton Button);
284285
public readonly record struct JoystickHatMoveEvent(IJoystick Joystick, long Timestamp, Vector2 Value, Vector2 Delta);
@@ -372,23 +373,13 @@ A target is defined as follows:
372373
public interface IPointerTarget
373374
{
374375
/// <summary>
375-
/// The minimum position of points on this target, where <see cref="float.NegativeInfinity" /> represents the lack
376-
/// of a lower bound on a particular axis and <c>0</c> represents an unused axis if <see cref="MaxPosition" /> is
377-
/// also <c>0</c> for that axis.
376+
/// The boundary in which positions of points on this target shall fall. For <see cref="Box3F{T}.Min" />,
377+
/// <see cref="float.NegativeInfinity" /> shall represent the lack of a lower bound on a particular axis. For
378+
/// For <see cref="Box3F{T}.Max" />, <see cref="float.PositiveInfinity" /> shall represent the lack of a lower bound
379+
/// on a particular axis. <c>0</c> represents an unused axis that axis is <c>0</c> on both
380+
/// <see cref="Box3F{T}.Min" /> and <see cref="Box3F{T}.Max" />.
378381
/// </summary>
379-
Vector3 MinPosition { get; }
380-
381-
/// <summary>
382-
/// The maximum position of points on this target, where <see cref="float.PositiveInfinity" /> represents the lack
383-
/// of an upper bound on a particular axis and <c>0</c> represents an unused axis if <see cref="MinPosition" /> is
384-
/// also <c>0</c> for that axis.
385-
/// </summary>
386-
Vector3 MaxPosition { get; }
387-
388-
/// <summary>
389-
/// An optional name describing the target.
390-
/// </summary>
391-
string? Name { get; }
382+
Box3F<float> Bounds { get; }
392383

393384
/// <summary>
394385
/// Gets the number of points with which the given pointer is pointing at this target.
@@ -415,6 +406,10 @@ public interface IPointerTarget
415406
}
416407
```
417408

409+
**FUTURE IMPROVEMENT:** This interface could be expanded to provide rotation of the target itself as well, representing
410+
a full `Transform` structure for the space. At this time, this was not deemed necessary for inclusion, but should be a
411+
trivial extension to add in the future.
412+
418413
**INFORMATIVE TEXT**: Furthermore, it is our eventual goal to be able to support considering VR hands as pointer devices
419414
through raycasting. Such a future proposal will involve a way to create a child target within the bounds of this target
420415
a `IPointerTarget` from that which represents the 3D world (i.e. the entire VR world is a target, and the point
@@ -445,31 +440,39 @@ public enum TargetPointFlags
445440
/// <summary>
446441
/// Represents a point on a target at which a pointer is pointing.
447442
/// </summary>
443+
/// <param name="Id">
444+
/// An integral identifier for the point. This point must be the only point for the device currently pointing at a
445+
/// target with this identifier at any given time. If this point ceases to point at the target, then the identifier
446+
/// becomes free for another device point. This means that this identifier can just be an index, but may be globally
447+
/// unique depending on the backend's capabilities.
448+
/// </param>
448449
/// <param name="Flags">Flags describing the state of the point.</param>
449450
/// <param name="Position">The absolute position on the target at which the pointer is pointing.</param>
450451
/// <param name="NormalizedPosition">
451452
/// The normalized position on the target at which the pointer is pointing, if applicable. If this is not available
452453
/// (e.g. due to the target being infinitely large a.k.a. "unbounded"), then this property shall have a value of
453454
/// <c>default</c>.
454455
/// </param>
455-
/// <param name="Orientation">
456-
/// The angle at which the pointer is pointing at the point on the target. An identity quaternion shall be interpreted
457-
/// as the point directly perpendicular to and facing towards the target. This shall carry an identity quaternion if
458-
/// there is no orientation available.
456+
/// <param name="Pointer">
457+
/// A ray representing the distance and angle at which the pointer is pointing at the point on the target. A ray with an
458+
/// orientation equivalent to an identity quaternion shall be interpreted as the point directly perpendicular to and
459+
/// facing towards the target, with this being the default value should this information be unavailable. If distance
460+
/// information is unavailable, this shall be equivalent to a <c>default</c> vector.
459461
/// </param>
460-
/// <param name="Distance">The distance of the pointer from the point the pointer is pointing at.</param>
461462
/// <param name="Pressure">
462463
/// The pressure applied to the point on the target by the pointer, between <c>0.0</c> representing the minimum amount
463464
/// of pressure and <c>1.0</c> representing the maximum amount of pressure. This shall be <c>1.0</c> if such data is
464465
/// unavailable but the point is otherwise valid.
465466
/// </param>
467+
/// <param name="Target">The pointer being pointed at.</param>
466468
public readonly record struct TargetPoint(
469+
int Id,
467470
TargetPointFlags Flags,
468471
Vector3 Position,
469472
Vector3 NormalizedPosition,
470-
Quaternion Orientation,
471-
Vector3 Distance,
472-
float Pressure
473+
Ray3F<float> Pointer,
474+
float Pressure,
475+
IPointerTarget Target
473476
) {
474477
public bool IsValid => (Flags & Flags.PointingAtTarget) != Flags.NotPointingAtTarget;
475478
}
@@ -480,11 +483,9 @@ The `PointerState` shall be defined as follows:
480483
public class PointerState
481484
{
482485
public ButtonReadOnlyList<PointerButton> Buttons { get; }
483-
public InputReadOnlyList<PointerStatePoint> Points { get; }
486+
public InputReadOnlyList<TargetPoint> Points { get; }
484487
public float GripPressure { get; }
485488
}
486-
487-
public readonly record struct PointerStatePoint(IPointerTarget Target, TargetPoint Point);
488489
```
489490

490491
`Points` represents the `TargetPoint`s this pointer is pointing at on its "native targets" i.e. that which is enumerated
@@ -501,15 +502,43 @@ The handler for pointer inputs shall be defined as follows:
501502
```cs
502503
public interface IPointerInputHandler : IButtonInputHandler<PointerButton>
503504
{
505+
void HandleTargetChanged(PointerTargetChangedEvent @event);
504506
void HandlePointChanged(PointChangedEvent @event);
505507
void HandleGripChanged(PointerGripChangedEvent @event);
506508
}
507509
```
508510

511+
`HandleTargetChanged` must be called when properties on an `IPointerTarget` within `IPointer.Targets` changes, or when
512+
an `IPointerTarget` is added or removed to/from `IPointer.Targets`. `IsAdded` shall be `true` if it has been added,
513+
`false` if it has been removed.
514+
509515
`HandlePointChanged` must be called when a point within `PointerState.Points` changes.
510516

511517
`HandleGripChanged` must be called when `PointerState.GripPressure` changes.
512518

519+
These device interfaces and related APIs are designed to mirror physical hardware that the user uses to point at a
520+
target. However, there are many cases where applications would work better with an abstraction that creates "virtual
521+
pointers" for each point, rather that the points being spread across many logical devices. For this we propose the
522+
following addendum to the `Pointers` class:
523+
524+
```cs
525+
public partial class Pointers
526+
{
527+
public IReadOnlyList<ContextPoint> Points { get; }
528+
}
529+
530+
public readonly record struct ContextPoint(IPointer Device, TargetPoint Point, ButtonReadOnlyList<PointerButton> Buttons, float GripPressure)
531+
{
532+
public int Id { get; }
533+
}
534+
```
535+
536+
`Id` shall be an identifier that mixes `Point.Id` and `Device.Id` in a way that ensures the identifier is unique across
537+
the whole context.
538+
539+
**FUTURE IMPROVEMENT:** The `Pointers` class is also expected to be the site of gesture recognition when proposed in the
540+
future.
541+
513542
`PointerButton` shall be defined as follows:
514543
```cs
515544
public enum PointerButton

0 commit comments

Comments
 (0)