IllusionMods / KKS_VR

VR plugin for Koikatsu Sunshine (main game and studio)
MIT License
51 stars 11 forks source link

UI pointer / No way to open menu in-game / missing click bindings due to old VRGIN #26

Closed yunacchi closed 1 year ago

yunacchi commented 1 year ago

I've been having some issues while using KKS_VR with Valve Index controllers - most documented bindings work, which are to my knowledge:

Switch tool: B
Show help: Hold B

## Teleport tool
Teleport: Click thumbstick
Rotate before teleport: Rotate thumbstick or touchpad, then click thumbstick
Free camera: Hold A and move

## School tool
Rotate in-place: Thumbstick left/right
Walk forward with camera: Trigger
Activate/Talk: Click thumbstick
F3/Warp screen: Thumbstick up+Click thumbstick
F1/Options screen: Thumbstick down+Click thumbstick
Free camera: Hold A and move

## UI (gear) tool
Freeze/unfreeze UI: A
Activate/Talk: Click thumbstick
Walk forward without camera: Trigger

## UI pointer
Move UI: A (note: this switches the hand back to the UI tool and unfreezes it)
Left click: Trigger
Right click: ?
Middle click: ?

One thing I find missing is the middle click: I can't open the character menu on the UI. This makes it somewhat difficult to save, call, et cetera.

On KK_MainGameVR, this is done via clicking the centered thumbstick with the UI pointer. Still works fine as of 10 minutes ago.
I'm using the default Index bindings on KK_MainGameVR and KKS_VR both - this part in the README:

A laser pointer can also generate a right click (Touchpad right), middle click (Touchpad center) and scroll up/down (Touchpad up/down).

To be honest, I'm not sure where this got lost in translation.

EDIT

Edited with results of investigation below.

KK_MainGameVR uses mosirnik's VRGIN fork, which has middle-click and right-click hooks and works as intended, whereas KKS_VR uses an embedded lib/VRGIN_OpenXR.dll library which wasn't updated with mosirnik's VRGIN fork (and doesn't have the hooks).

See relevant comment for more information, plus a Harmony patch which updates behavior.

yunacchi commented 1 year ago

Hmm. This might be deeper than I initially thought.

KK_MainGameVR uses mosirnik's VRGIN fork, which has a MenuHandler that supports left (trigger press), right (TP right click), and middle (TP center click).

KKS_VR uses an embedded lib/VRGIN_OpenXR.dll library.
I have no idea where that VRGIN_OpenXR actually comes from, but decompiling it shows that the VRGIN.Controls.Handlers.MenuHandler in there does not have hooks for middle and right-click - it only has the left-click. I assume the fork from VRGIN pre-dated the commit that added support for right and middle mouse clicks.

Would I be correct in guessing that there's just no support for middle and right-clicks, regardless of controllers?

yunacchi commented 1 year ago

Thankfully, it's nothing that Harmony can't patch - I'm able to middle-click and right-click with the following patch:

using HarmonyLib;
using UnityEngine;
using Valve.VR;
using VRGIN.Controls;
using VRGIN.Controls.Handlers;
using VRGIN.Core;
using VRGIN.Visuals;

namespace KKS_VR.Controls
{
    /// <summary>
    /// Hooks for <see cref="MenuHandler"/> - notably to add support for features from mosirnik/VRGIN not present in VRGIN_OpenXR,
    /// like middle-click/right-click support on menu UI.
    /// </summary>
    [HarmonyPatch(typeof(MenuHandler))]
    internal class MenuHandlerHooks
    {
        private static TrackpadDirection _PressDirection;

        [HarmonyPatch("CheckInput")]
        [HarmonyPostfix]
        public static void CheckInput(MenuHandler __instance, GUIQuad ____Target, Controller ____Controller)
        {
            if (__instance.LaserVisible && ____Target)
            {
                DeviceLegacyAdapter input = ____Controller.Input;
                if (input.GetPressDown(EVRButtonId.k_EButton_SteamVR_Touchpad))
                {
                    var currentDirection = GetTrackpadDirection(____Controller);
                    _PressDirection = currentDirection;
                    switch (currentDirection)
                    {
                        case TrackpadDirection.Right:
                            VR.Input.Mouse.RightButtonDown();
                            break;
                        case TrackpadDirection.Center:
                            VR.Input.Mouse.MiddleButtonDown();
                            break;
                        default:
                            break;
                    }
                }

                if (input.GetPressUp(EVRButtonId.k_EButton_SteamVR_Touchpad))
                {
                    switch (_PressDirection)
                    {
                        case TrackpadDirection.Right:
                            VR.Input.Mouse.RightButtonUp();
                            break;
                        case TrackpadDirection.Center:
                            VR.Input.Mouse.MiddleButtonUp();
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        public enum TrackpadDirection
        {
            Up,
            Down,
            Left,
            Right,
            Center,
        }

        public static TrackpadDirection GetTrackpadDirection(Controller controller)
        {
            var touchPosition = controller.Input.GetAxis();
            var threshold = 0.8f; // Threshold for a touchpad click to be considered central.
            if (touchPosition.sqrMagnitude < threshold * threshold)
            {
                return TrackpadDirection.Center;
            }
            else if (Mathf.Abs(touchPosition.y) < touchPosition.x)
            {
                return TrackpadDirection.Right;
            }
            else if (Mathf.Abs(touchPosition.x) < touchPosition.y)
            {
                return TrackpadDirection.Up;
            }
            else if (touchPosition.x < -Mathf.Abs(touchPosition.y))
            {
                return TrackpadDirection.Left;
            }
            else
            {
                return TrackpadDirection.Down;
            }
        }
    }
}

But instead of making a dumb PR and forgetting about it, I'd much rather know where this lib/VRGIN_OpenXR.dll comes from.

There has been many more input-related fixes upstream on mosirnik/VRGIN - some code I can't easily patch would fix inputs stuck on scene change, for instance.

RodoxVR commented 1 year ago

I'm also on index controllers and i do have to admit that i miss this feature, i always have to walk to my mouse risking bumping into things, not ideal.

ManlyMarco commented 1 year ago

@yunacchi VRGIN doesn't work under new Unity versions. VRGIN_OpenXR is a modified fork that does but I believe the source was never shared so I had to include the binaries. I'll see what I can do, harmony patching the missing fixes is probably going to be the easiest.

ManlyMarco commented 1 year ago

I ended up decompiling VRGIN_OpenXR and porting the fixes over to it. It now lives in https://github.com/ManlyMarco/VRGIN_OpenXR, feel free to post issues and PRs on there since KKS_VR will now use builds from that repo.

Here's the latest test build, it should have all of the major fixes from the mosirnik branch. Can anyone test if this resolves the issue? (just replace the old dll in KKS_VR) VRGIN_OpenXR.zip

yunacchi commented 1 year ago

Holy cow, that was fast. I was about to propose doing the same thing. Thank you very much.

Can't check right now, but I'll report back later today.

yunacchi commented 1 year ago

Yup, the VRGIN_OpenXR build works perfectly - at least with my Index. Can launch, move around, and interact with the UI as expected.

Apparently some calls to void VRGIN.Core.VRLog.Log(string, object[], LogMode) cause a FormatException in string.Format(string, object[]), but I have no information on the caller or call stack - It's not hindering gameplay in any way, it's just a couple more lines in the logs.

ManlyMarco commented 1 year ago

Thanks for testing! In that case I'll consider this fixed.

If you still get the log issue after I make an official release please open a new issue with a stack trace or steps to reproduce.