/* * SPDX-License-Identifier: AGPL-3.0-or-later * Copyright (C) 2025 Sergej Görzen * This file is part of OmiLAXR. */ using System.ComponentModel; using UnityEngine; #if ENABLE_INPUT_SYSTEM using UnityEngine.InputSystem; #endif namespace OmiLAXR.TrackingBehaviours.Learner { /// /// Tracks mouse input events including clicks, wheel scrolling, and movement. /// Supports both legacy Input Manager and new Input System. /// [AddComponentMenu("OmiLAXR / 3) Tracking Behaviours / Mouse Tracking Behaviour")] [Description("Tracks mouse clicks and wheel.")] public class MouseTrackingBehaviour : TrackingBehaviour { /// /// Contains information about a mouse event including button name and position. /// public struct MouseTrackingBehaviourArgs { /// /// Name of the mouse button that triggered the event. /// public readonly string MouseButton; /// /// Screen position where the mouse event occurred. /// public Vector3 MousePosition; /// /// Initializes mouse tracking event arguments. /// /// Button name (left, right, middle, wheel) /// Mouse position in screen coordinates public MouseTrackingBehaviourArgs(string name, Vector3 position) { MouseButton = name; MousePosition = position; } } /// /// Event triggered when a mouse button is clicked (pressed and released). /// [Gesture("Mouse"), Action("Click")] public readonly TrackingBehaviourEvent OnClicked = new TrackingBehaviourEvent(); /// /// Event triggered when a mouse button is pressed down. /// [Gesture("Mouse"), Action("Press")] public readonly TrackingBehaviourEvent OnPressedDown = new TrackingBehaviourEvent(); /// /// Event triggered when the mouse wheel is scrolled. /// [Gesture("Mouse"), Action("Scroll")] public readonly TrackingBehaviourEvent OnScrolledWheel = new TrackingBehaviourEvent(); /// /// Event triggered when the mouse position changes significantly. /// [Gesture("Mouse"), Action("Move")] public TrackingBehaviourEvent OnMousePositionChanged = new TrackingBehaviourEvent(); // Button state tracking for detecting press/release transitions private bool _isLeftDown; private bool _isRightDown; private bool _isWheelDown; /// /// Minimum movement distance in pixels to trigger position change events. /// public float movementThreshold = 3.0f; private Vector3 _lastMousePosition; private float _mouseWheel; /// /// Minimum wheel scroll delta to trigger scroll events. /// public float mouseWheelThreshold = 0.5f; /// /// Button names corresponding to mouse button indices. /// private static readonly string[] ButtonNames = { "left", "right", "middle" }; /// /// Initialize mouse position tracking. /// protected virtual void Start() { _lastMousePosition = GetMousePosition(); } /// /// Handles mouse button state changes and triggers appropriate events. /// /// Button index (0=left, 1=right, 2=middle) /// Previous button state /// Current mouse position private void HandleMouseClick(int index, ref bool wasDown, Vector3 position) { bool isDown = false; #if ENABLE_INPUT_SYSTEM // Use Input System if available if (Mouse.current != null) { switch (index) { case 0: isDown = Mouse.current.leftButton.isPressed; break; case 1: isDown = Mouse.current.rightButton.isPressed; break; case 2: isDown = Mouse.current.middleButton.isPressed; break; } } #else // Fall back to legacy Input Manager isDown = Input.GetMouseButton(index); #endif var n = ButtonNames[index]; switch (wasDown) { // Button was just pressed case false when isDown: OnPressedDown?.Invoke(this, new MouseTrackingBehaviourArgs(n, position)); break; // Button was just released (clicked) case true when !isDown: OnClicked?.Invoke(this, new MouseTrackingBehaviourArgs(n, position)); break; } wasDown = isDown; } /// /// Updates mouse input tracking each frame. /// private void Update() { var mousePos = GetMousePosition(); // Check all mouse buttons for state changes HandleMouseClick(0, ref _isLeftDown, mousePos); HandleMouseClick(1, ref _isRightDown, mousePos); HandleMouseClick(2, ref _isWheelDown, mousePos); // Detect mouse wheel scrolling var curMouseWheel = GetMouseScroll(); float mouseWheelDis = Mathf.Abs(_mouseWheel - curMouseWheel); if (mouseWheelDis > mouseWheelThreshold) { _mouseWheel = curMouseWheel; OnScrolledWheel?.Invoke(this, new MouseTrackingBehaviourArgs("wheel", mousePos), curMouseWheel); } // Detect significant mouse movement var distance = Vector3.Distance(mousePos, _lastMousePosition); if (distance > movementThreshold) { OnMousePositionChanged?.Invoke(this, mousePos, _lastMousePosition); _lastMousePosition = mousePos; } } /// /// Gets current mouse position using appropriate input system. /// /// Mouse position in screen coordinates private Vector3 GetMousePosition() { #if ENABLE_INPUT_SYSTEM if (Mouse.current != null) { var pos = Mouse.current.position.ReadValue(); return new Vector3(pos.x, pos.y, 0f); } return Vector3.zero; #else return Input.mousePosition; #endif } /// /// Gets current mouse scroll wheel delta. /// /// Scroll wheel delta value private float GetMouseScroll() { #if ENABLE_INPUT_SYSTEM return Mouse.current?.scroll.ReadValue().y ?? 0f; #else return Input.mouseScrollDelta.y; #endif } } }