Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Unity UI World Space Canvas + CursorLockMode.Locked incompatible?

Discussion in 'UGUI & TextMesh Pro' started by mrmcduck, Oct 9, 2018.

  1. mrmcduck


    Nov 26, 2015
    Hello fellow Unity devs!

    I am working on a immersive UI system for a first person game which displays as much UI elements as possible on in-game computer screens. Obviously the mouse controls looking around, and therefore i'd like to use the center of the screen as mouse cursor for the UI elements when the player stands in front of a screen with a world space canvas.

    Sadly this seems impossible, according to a official unity post:
    "[...] Thus we have removed the interactability of a locked cursor with the UI. To simulate this behavor you would need to derive from StandaloneInputModule and override the GetMousePointerEventData function to force the position to anything you want. [...]"

    There are a few workarounds including in the statement above, but they all don't seem to be an option, because simulating the mouse cursor position by setting it manually in a custom InputModule is only a very small part of the issues. I need standard UI event system behaviors, e.g. Drag&Drop-, PointerIn-, PointerExit-, ... events.

    Am I missing something or is this just impossible - unless I rewrite the whole UI system?
  2. 00jknight


    Mar 28, 2014
  3. DeveloperJake


    May 25, 2020
    I have the same problem, considering this is 2 years old and I'm using unity 2022, I don't think they plan on patching this any time soon
  4. JJTheOwO


    Oct 18, 2020
    I have found a solution, and it's extremely jank, but works (based on very limited testing, it might impact other systems, but oh well)

    First, you need to create a new script to make the cursor work, keep it disabled when not in locked mode, because it forces locked mode on (use singleton if you want or something).

    The script is just this:
    Code (CSharp):
    1. Class WorldSpaceUIEnabler {
    2.     private void Update() {
    3.         Cursor.lockState = CursorLockMode.Confined;
    4.     }
    6.     private void LateUpdate() {
    7.         Cursor.lockState = CursorLockMode.Locked;
    8.     }
    9. }
    What's important is the execution order
    in Project Settings > Script Execution Order
    add this script above UnityEngine.EventSystems.EventSystem (earlier)
    and there you go, whenever this script is enabled, the cursor will be in locked mode, but still be able to interact with World Space UI.

    If there are issues, then oh well, not something i encountered in the 5minutes since finding this out.

    UPDATE: forgot to check if it works with sliders, it does surprisingly well
    Last edited: May 28, 2022
    emongev and Jonawott like this.
  5. coolcatcoder


    Jun 29, 2022
    Sorry for necrobumping, but I can't seem to get this working in the 2021 lts with the new input system, does this still work, or is there a new workaround?

    Edit: I have found that by having both the new and old input systems enabled, but using the old Standalone Input Module on the event system that it works fine! Yay!
    Last edited: Nov 26, 2022
  6. krwiak121


    Jun 15, 2018
    This is an old topic but maybe it will help many people, my solution is:
    • Create a new script and Inherit GraphicRaycaster
    • Change the override void Raycast and change the position to the center of the screen
    • Remove GraphicRaycaster from Canvas and add your custom script
    • Don't forget if you have a crosshair in the middle of the screen, turn off RaycastTarget there
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using UnityEngine.EventSystems;
    4. using UnityEngine.UI;
    6. public class RaycasterWorld : GraphicRaycaster
    7. {
    8.     public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    9.     {
    10.         //Set middle screen pos or you can set variable on start and use it
    11.         eventData.position = new(Screen.width / 2, Screen.height / 2);
    12.         base.Raycast(eventData, resultAppendList);
    13.     }
    14. }