/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR. */ using System; using UnityEngine; using UnityEngine.EventSystems; namespace OmiLAXR.Components { /// /// Handles pointer interaction events for UI elements, supporting both mouse and XR interaction. /// Implements Unity's pointer interface to track hover, press, and release events. /// public class InteractionEventHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler { public delegate void InteractionEventHandlerAction(InteractionEventHandler sender, InteractionEventArgs args); /// /// Contains data about the pointer interaction events. /// public struct InteractionEventArgs { public string Device { get; set; } /// /// Total number of presses recorded since this component was initialized. /// public uint TotalPresses { get; set; } /// /// Number of presses recorded during the current hover. /// public uint PressesInHover { get; set; } /// /// Duration in seconds that the pointer has been hovering over this element. /// public float HoverDuration { get; set; } /// /// Duration in seconds that the pointer has been pressing this element. /// public float PressDuration { get; set; } } // Timestamp when the pointer starts hovering over this element private float _hoverStartTime; // Timestamp when the pointer starts pressing this element private float _pressStartTime; // Flags to track the current interaction state private bool _isHovering; private bool _isPressing; // Sum of how often the button was pressed inside a hover private uint _pressHoverSum; private uint _pressTotalSum; /// /// Event triggered when the pointer starts hovering over this element. /// public event InteractionEventHandlerAction OnHoverStarted; /// /// Event triggered when the pointer stops hovering over this element. /// public event InteractionEventHandlerAction OnHoverEnded; /// /// Event triggered when the pointer begins pressing this element. /// public event InteractionEventHandlerAction OnPressStarted; /// /// Event triggered when the pointer releases this element after pressing. /// public event InteractionEventHandlerAction OnPressEnded; /// /// Event triggered when a complete click action occurs (press and release while hovering). /// Only fires when the element is released while the pointer is still hovering over it. /// public event InteractionEventHandlerAction OnClicked; /// /// Whether the pointer is currently hovering over this element. /// public bool IsHovering => _isHovering; /// /// Whether the pointer is currently pressing this element. /// public bool IsPressing => _isPressing; public static string GetDeviceName(PointerEventData eventData) { // 1. Prüfe pointerId (klassisch) if (eventData.pointerId == -1) return "Touch"; if (eventData.pointerId == 0) return "Mouse"; if (eventData.pointerId > 0) return $"Touch {eventData.pointerId}"; // 2. Optional: Analyse des Raycast-Moduls var moduleType = eventData.pointerPressRaycast.module?.GetType().Name ?? "UnknownModule"; // 3. Rückfall return $"Unknown input via {moduleType}"; } /// /// Called when the pointer enters this UI element. /// Records the start time and logs the event. /// public void OnPointerEnter(PointerEventData eventData) { _hoverStartTime = Time.time; _isHovering = true; _pressHoverSum = 0; OnHoverStarted?.Invoke(this, new InteractionEventArgs() { TotalPresses = _pressTotalSum, PressesInHover = _pressHoverSum, HoverDuration = 0, PressDuration = 0, Device = GetDeviceName(eventData) }); } /// /// Called when the pointer exits this UI element. /// Calculates the hover duration, logs the event, and triggers the OnHoverEnded event. /// public void OnPointerExit(PointerEventData eventData) { if (!_isHovering) return; _isHovering = false; OnHoverEnded?.Invoke(this, new InteractionEventArgs() { TotalPresses = _pressTotalSum, PressesInHover = _pressHoverSum, HoverDuration = Time.time - _hoverStartTime, PressDuration = _isPressing ? Time.time - _pressStartTime : 0, Device = GetDeviceName(eventData) }); } /// /// Called when the pointer is pressed down on this UI element. /// Records the start time and triggers the OnPressStarted event. /// public void OnPointerDown(PointerEventData eventData) { _pressStartTime = Time.time; _isPressing = true; OnPressStarted?.Invoke(this, new InteractionEventArgs() { TotalPresses = _pressTotalSum, PressesInHover = _pressHoverSum, HoverDuration = Time.time - _hoverStartTime, PressDuration = 0, Device = GetDeviceName(eventData) }); } /// /// Called when the pointer is released on this UI element. /// Calculates the press duration, increments press counters, and triggers the OnPressEnded event. /// Also triggers OnClicked if the release happens while still hovering over the element. /// public void OnPointerUp(PointerEventData eventData) { if (!_isPressing) return; var pressDuration = Time.time - _pressStartTime; _isPressing = false; _pressHoverSum++; _pressTotalSum++; var eventArgs = new InteractionEventArgs() { TotalPresses = _pressTotalSum, PressesInHover = _pressHoverSum, HoverDuration = Time.time - _hoverStartTime, PressDuration = pressDuration, Device = GetDeviceName(eventData) }; OnPressEnded?.Invoke(this, eventArgs); // If we're still hovering when the press ends, this is considered a "click" if (_isHovering) { OnClicked?.Invoke(this, eventArgs); } } } }