openvr icon indicating copy to clipboard operation
openvr copied to clipboard

Reading the user's current input binding for the purpose of showing instructions in-game

Open rcigna opened this issue 7 years ago • 3 comments

Hello there!

We are working on porting a Unity game to Open VR and we are interested in supporting the new input system to take advantage of rebind-able actions. Here are some important versions:

  • Unity 2017.4.9f1
  • SteamVR Unity Plugin 2.0 RC3
  • SteamVR beta, build 3058703
  • I'm not sure what version of the OpenVR SDK is being used, or how to find out

Our game has a controls help screen and some brief tutorials, and we feel it is important for those to be correct even after the user has made custom bindings or if the user is using a controller type we haven't specifically developed for.

To do that, we need to be able to:

  1. Take an arbitrary Action from our game.
  2. Get the binding for that Action corresponding to the most reasonable controller.
  3. Get which part of the controller the Action is bound to. We'd like to show graphic icons when possible, but fall back to a user-friendly string if necessary.

Here is an example from our game:

  1. We have an action named "/actions/pointer-style/in/Contextual".
  2. If the user is using the Knuckles, we would pick the Knuckles as the controller to show instructions for.
  3. Our default binding for Contextual on Knuckles is the "click" input on "/user/hand/left/input/b" (because it is mirrored, it is also bound to the "click" input of "/user/hand/right/input/b".) For this we would like to use either an animated image of a B button, or the string "Click B" or "Click the B Button."

Here is what I've tried:

  1. The function GetOriginLocalizedName seems to be exactly what we want, but I can't be sure because the documentation is not clear to me and it states "This function is not yet implemented." I think it might eventually give me "/user/hand/left/input/b", or "B Button", or even "Left B Button", but when I try calling it now with various handles from GetActionOrigins, I always get either the literal string "#InputSourceName" or an InvalidHandle error.
  2. I have tried calling GetActionHandle with "/actions/pointer-style/in/Contextual", then calling GetActionOrigins with the handle I got, then GetOriginTrackedDeviceInfo to get "devicePath", render component name, and device indices -- which allows me to get various ETrackedDeviceProperty. I tested Prop_ControllerType_String, Prop_InputProfilePath_String, and Prop_UserConfigPath_String. The user config returned an UnknownProperty error for every binding, even if I had made a "personal" binding. For "devicePath," it is necessary to use GetInputSourceHandle with known paths and work backward by comparing. The plugin only implements "/user/hand/left" and "/user/hand/right". I was able to guess "/user/gamepad", but my understanding is that devices are not limited to those 3. Render component name often doesn't contain anything. The input profile paths are shorthand for json files in the driver's resources folder that list out each basic input of the devices. For example, on my machine {gamepad} should expand to "Z:\Applications\Steam\steamapps\common\SteamVR\drivers\gamepad\resources". But in any case the file doesn't seem to include meta-inputs that users can still bind to, like using a trackpad as a D-pad. And even if I could expand the path and load the json, I still have no way of knowing which one the action is bound to! Here is a table of the values I get when doing all this for my example above, while I have a gamepad and both knuckles controllers connected: Action handle: 1152973508070867194
Origin Localized Name Index Source Type Input Profile Path Render Component Name
2305895012677714057 #InputSourceName 16 /user/gamepad gamepad {gamepad}/input/gamepad_profile.json (nothing)
2305895012677714396 #InputSourceName 5 /user/hand/left knuckles {knuckles}/input/knuckles_profile.json button_b
2305895012677714430 (InvalidHandle error) 6 /user/hand/right knuckles {knuckles}/input/knuckles_profile.json (nothing)
  1. I have tried calling OpenVR.Settings.GetString with a key of the format "{0}_{1}_{2}", where {0} is the controller type I am interested in, {1} is 250820 (the appid for SteamVR itself,) and {2} is OpenVR.k_pch_App_BindingCurrentURLSuffix_String. If the user has set a personal binding, this will get a string such as this: "vr-input-workshop://1490591285". In my case, that URL appears to refer to the file "Z:\Applications\Steam\steamapps\workshop\content\250820\1490591285\942829618581098361_legacy.bin", which is a json file identical in structure to the default bindings files. But I don't know how to expand that URL at run-time without guessing where Steam is installed based on the working directory, knowing SteamVR's appid, and assuming the file will always be stored in SteamVR's workshop directory, then parsing the json ourselves. And of course this key won't exist if the user has never created a personal binding! So as a fallback we would have to load and parse the default binding json instead. All of which makes me very worried that this method would not be robust in a production environment.
  2. I have tried subscribing to SteamVR_Events.SystemAction with an event type of VREvent_Input_BindingLoadSuccessful. This gives four pieces of information: device index, path message, path URL, and path controller type. Unfortunately it was a bit of a dead-end for me, because the device index was always equal to k_unTrackedDeviceIndexInvalid, and the other three -- though they sound promising -- are all handles referring to strings, like devicePath. And like devicePath, I have no idea how to get back the strings they refer to without knowing them beforehand.

Is it possible to make dynamic instructions like this? If not, will it be possible in the near future? What other methods should I explore? If this is the wrong place to ask this, where should I ask instead?

Thank you for your time. Any help you can provide would be greatly appreciated.

rcigna avatar Aug 24 '18 01:08 rcigna

Thanks for all your work in investigating this issue. It's definitely a scenario we care about. We released version 2 of the plugin today. There should now be hint UI displaying in the plugin now using a system that works in the way you're describing. When the scene starts it should give you an alert with an arrow pointing to the teleport button. Let me know if this system fits your scenario.

keithbradner avatar Sep 21 '18 23:09 keithbradner

Hello zite!

Thank you for updating the example scenes. I also received some help from Joe over in the steam developer hardware forum.

After confirming I had the SteamVR build 1537479688 and checking again, GetOriginLocalizedName now returns a user-friendly string such as "Right Hand Knuckles Controller B Button".

I also ran the updated example scenes in the Unity plugin, and I do see little text boxes pointing to parts of the controller. From what I can tell, these hints are ultimately driven by InputOriginInfo_t's rchRenderModelComponentName (which seems to now consistently give the same string for mirrored bindings.)

Unfortunately, this doesn't exactly work for our game. I should explain that our game is very passive -- the player will rarely walk over and grab things, plus we support controllers that aren't tracked. So our tutorials are actually just small floating 2D cards that are not attached to the controllers. My goal is to have:

  1. An animation of the action being performed on the left.
  2. On the right, a. If the action is bound to a known controller and element, a pre-made animation. My plan was to make these for Oculus Remote, Oculus Touch, Vive Controller, Knuckles Controller, and ordinary gamepad. b. Otherwise, fallback text.

But how do I tell if it's a known element? GetOriginLocalizedName is adequate for the fallback text, but is localized. rchRenderModelComponentName seems to be the only machine-friendly way to distinguish bindings right now, but there's two big problems with it:

  1. It doesn't seem to contain anything for ordinary gamepads (I am using a Dualshock 4 connected via USB.) Since this plugin's example scenes rely so much on tracking, I only tested this in our game.
  2. It doesn't differentiate between meta-inputs on the same physical element. I have in mind using the Vive Controller's trackpad as a dpad, and indeed if I replace every binding for the Vive Controller with one of the four quadrants of the dpad in this plugin's example scene, then every hint points unhelpfully to the same place above the center of the trackpad.

rcigna avatar Sep 25 '18 21:09 rcigna

This seems like an OpenVR bug / feature request at this point. You may be better served in the OpenVR Repo here: https://github.com/ValveSoftware/openvr/issues

keithbradner avatar Jan 02 '19 18:01 keithbradner