I want to make a virtual mouse that the player can control using a gamepad so that players can navigate menus and move the mouse to play minigames.
I used this code in order to simulate a click and move the cursor based on the joystick input, but this code only works in a Windows build and uses an unreliable “DllImport” that doesn’t work in the WebGL build.
Do you know how can I achieve the same thing using a better system or why the “DllImport” doesn’t work in the WebGL build?
Code:
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class InputManager : MonoBehaviour, ISettingsSavedData
{
[SerializeField] float joystickMouseSensitivity;
[SerializeField] float minJoystickMouseSensitivity, maxJoystickMouseSensitivity;
// Deadzone to prevent small joystick movements interapting with mouse movement
[SerializeField] float joystickDeadzone = 0.1f;
public bool cursorLocked, cursorVisible;
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
//Mouse actions
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public Inputs inputActions { get; private set; }
public static InputManager Instance { get; private set; }
private void Awake()
{
HandleSingletonLogic();
CreateNewInput();
inputActions.Player.TestMenuScene.performed += TestMenuScene_performed;
}
private void Start()
{
inputActions.Joystick.MousePress.started += MousePress_started;
inputActions.Joystick.MousePress.canceled += MousePress_canceled;
}
private void Update()
{
HandleControllerMouse();
}
private void OnDestroy()
{
inputActions.Joystick.MousePress.started -= MousePress_started;
inputActions.Joystick.MousePress.canceled -= MousePress_canceled;
}
public void SaveMyData(ref SettingsMenuData settingsData)
{
// no need to save data
}
public void LoadGameData(SettingsMenuData settingsData)
{
joystickMouseSensitivity = Utilities.MapValueToNormalizeMinMax(settingsData.joystickSensitivity,
minJoystickMouseSensitivity, maxJoystickMouseSensitivity);
}
public void ApplyCursor()
{
Cursor.lockState = cursorLocked ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = cursorVisible;
}
private void CreateNewInput()
{
if (inputActions != null) return;
inputActions = new Inputs();
inputActions.Enable();
}
private void TestMenuScene_performed(InputAction.CallbackContext obj)
{
/*Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
GameSaveManager.Instance.SaveGame();
LevelManager.Instance.LoadScene(0);*/
FindObjectOfType<GameManager>().IncreaseMoneyAmount(10000);
}
private void HandleSingletonLogic()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
private void MousePress_canceled(InputAction.CallbackContext obj)
{
//Call the imported function with the cursor's current position
uint X = (uint)Input.mousePosition.x;
uint Y = (uint)Input.mousePosition.y;
mouse_event(MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
private void MousePress_started(InputAction.CallbackContext obj)
{
//Call the imported function with the cursor's current position
uint X = (uint)Input.mousePosition.x;
uint Y = (uint)Input.mousePosition.y;
mouse_event(MOUSEEVENTF_LEFTDOWN, X, Y, 0, 0);
}
private void HandleControllerMouse()
{
Vector2 joystickInput = inputActions.Joystick.JoystickDelta.ReadValue<Vector2>();
if (joystickInput.magnitude > joystickDeadzone)
{
// Handle deltaTime only if the game is not paused
float deltaTime = Time.unscaledDeltaTime;
Vector3 moveDelta = new Vector3(joystickInput.x, joystickInput.y, 0) * joystickMouseSensitivity * deltaTime;
Vector3 newMousePosition = Mouse.current.position.ReadValue() + (Vector2)moveDelta;
// Clamp the position
newMousePosition.x = Mathf.Clamp(newMousePosition.x, 0, Screen.width);
newMousePosition.y = Mathf.Clamp(newMousePosition.y, 0, Screen.height);
// Update mouse position
Mouse.current.WarpCursorPosition(newMousePosition);
}
}
private void SetInputMap(InputAction inputAction, bool active)
{
if (active) inputAction.Enable();
else inputAction.Disable();
}
public void SetPlayerControlsActive(bool active)
{
SetInputMap(inputActions.Player.Move, active);
SetInputMap(inputActions.Player.CameraRotation, active);
SetInputMap(inputActions.Player.Interact, active);
//SetInputMap(inputActions.Joystick.JoystickDelta, !active);
Cursor.lockState = active ? CursorLockMode.Locked : CursorLockMode.None;
Cursor.visible = !active;
}
}