Skip to content

Commit 4403b60

Browse files
committed
Add input options which will provide updates over the connection
1 parent 570dc45 commit 4403b60

11 files changed

Lines changed: 169 additions & 55 deletions

File tree

EasyFramework

OpenVROverlayPipe/GraphicsSingleton.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
using OpenTK.Graphics.OpenGL;
22
using System;
3+
using System.Runtime.Versioning;
34
using OpenVROverlayPipe.Notification;
45

56
namespace OpenVROverlayPipe
67
{
8+
[SupportedOSPlatform("windows7.0")]
79
internal class GraphicsSingleton
810
{
911
private static GraphicsSingleton? _instance;

OpenVROverlayPipe/Input/DataOverlay.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,25 @@ public class DataOverlay
2828
public float PitchDeg = 0;
2929
public float RollDeg = 0;
3030

31+
public InputObject? Input = null;
3132
public FollowObject? Follow = null;
3233
public TransitionObject? TransitionIn = null;
3334
public TransitionObject? TransitionOut = null;
3435
public AnimationObject[] Animations = [];
3536
public TextAreaObject[] TextAreas = [];
37+
38+
public class InputObject
39+
{
40+
public bool Mouse = false;
41+
public bool SmoothScroll = false;
42+
public bool DiscreteScroll = false;
43+
public bool Touchpad = false;
44+
45+
public bool IsUsed()
46+
{
47+
return Mouse || SmoothScroll || DiscreteScroll || Touchpad;
48+
}
49+
}
3650

3751
public class FollowObject
3852
{

OpenVROverlayPipe/Input/InputMessageKeyEnum.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ public enum InputMessageKeyEnum
77
EnqueueOverlay,
88
DismissOverlay,
99
ListChannels,
10-
DismissChannel
10+
DismissChannel,
11+
OverlayEvent
1112
}

OpenVROverlayPipe/MainController.cs

Lines changed: 69 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -110,14 +110,13 @@ private void RegisterEvents() {
110110
{
111111
JsonUtils.JsonDataParseResult<T> dataResult = JsonUtils.ParseData<T>(inputMessage.Data?.GetRawText());
112112
var data = dataResult.Data;
113-
if (data == null)
114-
{
115-
var errorMessage = $"Input was invalid, see Data as a reference. Error: {dataResult.Message}";
116-
_ = _server.SendMessageToSingle(
117-
session,
118-
JsonSerializer.Serialize(OutputMessage.CreateError(errorMessage, inputMessage, dataResult.Empty), JsonUtils.GetOptions())
119-
);
120-
}
113+
if (data != null) return data;
114+
115+
var errorMessage = $"Input was invalid, see Data as a reference. Error: {dataResult.Message}";
116+
_ = _server.SendMessageToSingle(
117+
session,
118+
JsonSerializer.Serialize(OutputMessage.CreateError(errorMessage, inputMessage, dataResult.Empty), JsonUtils.GetOptions())
119+
);
121120
return data;
122121
}
123122

@@ -136,7 +135,7 @@ private void PostNotification(WebSocketSession session, InputMessage inputMessag
136135

137136
// Image
138137
Debug.WriteLine($"Overlay handle {overlayHandle} for '{data.Title}'");
139-
Debug.WriteLine($"Image Hash: {CreateMd5(data.ImageData)}");
138+
Debug.WriteLine($"Image Hash: {MiscUtils.HashMd5(data.ImageData)}");
140139
var bitmap = new NotificationBitmap_t();
141140
try
142141
{
@@ -194,27 +193,76 @@ private void PostImageNotification(WebSocketSession session, InputMessage inputM
194193
overlay = new Overlay($"OpenVROverlayPipe[{channel}]", channel);
195194
if (!overlay.IsInitialized()) return;
196195

197-
overlay.DoneEvent += (_, args) =>
196+
overlay.DoneEvent += (_, doneEvent) =>
198197
{
199-
OnOverlayDoneEvent(args);
198+
OnOverlayDoneEvent(doneEvent);
199+
};
200+
overlay.OverlayEvent += (_, overlayEvent) =>
201+
{
202+
OnOverlayEvent(overlayEvent);
200203
};
201204
Session.Overlays.TryAdd(channel, overlay);
202205
}
203206
if (overlay.IsInitialized()) overlay.EnqueueNotification(sessionId, data, nonce);
204207
}
205208

206-
private void OnOverlayDoneEvent(string[] args)
209+
private void OnOverlayDoneEvent(OverlayDone doneEvent)
207210
{
208-
if (args.Length != 3) return;
209-
210-
var sessionId = args[0];
211-
var nonce = args[1];
212-
var error = args[2];
213-
var sessionExists = Session.Sessions.TryGetValue(sessionId, out var session);
211+
var sessionExists = Session.Sessions.TryGetValue(doneEvent.SessionId, out var session);
214212
if (sessionExists) _ = _server.SendMessageToSingleOrAll(session, JsonSerializer.Serialize(
215-
error.Length > 0
216-
? OutputMessage.CreateError(error, null, nonce, InputMessageKeyEnum.EnqueueOverlay)
217-
: OutputMessage.CreateResult("OK", null, nonce, InputMessageKeyEnum.EnqueueOverlay), JsonUtils.GetOptions())
213+
doneEvent.Error.Length > 0
214+
? OutputMessage.CreateError(doneEvent.Error, null, doneEvent.Nonce, doneEvent.Channel, InputMessageKeyEnum.EnqueueOverlay)
215+
: OutputMessage.CreateResult("OK", null, doneEvent.Nonce, doneEvent.Channel, InputMessageKeyEnum.EnqueueOverlay), JsonUtils.GetOptions())
216+
);
217+
}
218+
219+
private void OnOverlayEvent(OverlayEvent overlayEvent)
220+
{
221+
var sessionExists = Session.Sessions.TryGetValue(overlayEvent.SessionId, out var session);
222+
if (!sessionExists) return;
223+
224+
var typeEnum = (EVREventType)overlayEvent.Event.eventType;
225+
var mouse = overlayEvent.Event.data.mouse;
226+
var scroll = overlayEvent.Event.data.scroll;
227+
var touchpad = overlayEvent.Event.data.touchPadMove;
228+
dynamic? data;
229+
switch(typeEnum)
230+
{
231+
case EVREventType.VREvent_MouseMove:
232+
data = new OutputDataPosition(mouse.x, mouse.y);
233+
break;
234+
case EVREventType.VREvent_MouseButtonDown:
235+
case EVREventType.VREvent_MouseButtonUp:
236+
var buttonEnum = (EVRMouseButton)mouse.button;
237+
data = new OutputDataButton(buttonEnum);
238+
break;
239+
case EVREventType.VREvent_ScrollSmooth:
240+
data = new OutputDataPosition(scroll.xdelta, scroll.ydelta);
241+
break;
242+
case EVREventType.VREvent_ScrollDiscrete:
243+
data = new OutputDataPosition(scroll.xdelta, scroll.ydelta);
244+
break;
245+
case EVREventType.VREvent_TouchPadMove:
246+
data = new OutputDataPosition(touchpad.fValueXRaw, touchpad.fValueYRaw);
247+
break;
248+
default:
249+
data = null;
250+
break;
251+
}
252+
if (data == null) return;
253+
254+
var eventName = Enum.GetName(typeof(EVREventType), typeEnum);
255+
if (eventName == null) return;
256+
257+
_ = _server.SendMessageToSingleOrAll(session, JsonSerializer.Serialize(
258+
OutputMessage.CreateResult(
259+
eventName.Replace("VREvent_", ""),
260+
data,
261+
overlayEvent.Nonce,
262+
overlayEvent.Channel,
263+
InputMessageKeyEnum.OverlayEvent
264+
), JsonUtils.GetOptions()
265+
)
218266
);
219267
}
220268
#endregion
@@ -274,11 +322,9 @@ private void InitServer(Action<SuperServer.ServerStatus, int> serverStatus)
274322
case InputMessageKeyEnum.None:
275323
break;
276324
case InputMessageKeyEnum.EnqueueNotification:
277-
// TODO: Need to instantiate DATA with CONSTRUCTOR in DATA OBJECTS check OPENVR2WS
278325
if(session != null) PostNotification(session, inputMessage);
279326
break;
280327
case InputMessageKeyEnum.EnqueueOverlay:
281-
// TODO: Need to instantiate DATA with CONSTRUCTOR in DATA OBJECTS check OPENVR2WS
282328
if(session != null) PostImageNotification(session, inputMessage);
283329
break;
284330
case InputMessageKeyEnum.DismissOverlay:
@@ -315,20 +361,5 @@ public void Shutdown()
315361
_shouldShutDown = true;
316362
_ = _server.Stop();
317363
}
318-
319-
private static string CreateMd5(string input) // https://stackoverflow.com/a/24031467
320-
{
321-
// Use input string to calculate MD5 hash
322-
var inputBytes = Encoding.ASCII.GetBytes(input);
323-
var hashBytes = MD5.HashData(inputBytes);
324-
325-
// Convert the byte array to hexadecimal string
326-
var sb = new StringBuilder();
327-
foreach (var t in hashBytes)
328-
{
329-
sb.Append(t.ToString("X2"));
330-
}
331-
return sb.ToString();
332-
}
333364
}
334365
}

OpenVROverlayPipe/Notification/Animator.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,27 @@ internal class Animator
2525
private Action? _requestForNewData;
2626
private Action<string, string>? _responseAtCompletion;
2727
private Action<string, string, string?>? _responseAtError;
28+
private Action<string, string, VREvent_t>? _overlayEvent;
2829
private volatile DataOverlay? _data;
2930
private volatile string? _nonce;
3031
private volatile bool _shouldShutdown;
3132
private double _elapsedTime;
3233
private string _sessionId = "";
34+
private bool _isUsingInput = false;
3335

3436
public Animator(
3537
ulong overlayHandle,
3638
Action requestForNewAnimation,
3739
Action<string, string> responseAtCompletion,
38-
Action<string, string, string?> responseAtError
40+
Action<string, string, string?> responseAtError,
41+
Action<string, string, VREvent_t> overlayEvent
3942
)
4043
{
4144
_overlayHandle = overlayHandle;
4245
_requestForNewData = requestForNewAnimation;
4346
_responseAtCompletion = responseAtCompletion;
4447
_responseAtError = responseAtError;
48+
_overlayEvent = overlayEvent;
4549

4650
var thread = new Thread(Worker);
4751
if (!thread.IsAlive) thread.Start();
@@ -167,12 +171,26 @@ private void Worker() {
167171
// Initialize things that stay the same during the whole animation
168172
stage = AnimationStage.LoadingImage;
169173
properties = _data;
174+
_isUsingInput = properties.Input?.IsUsed() == true;
170175
useWorldDeviceTransform = properties.AnchorType != 0 && properties.AttachToAnchor && (properties.IgnoreAnchorYaw || properties.IgnoreAnchorPitch || properties.IgnoreAnchorRoll);
171176
follow = properties.Follow;
172177
followTween = Get(follow?.EaseType ?? EasingType.Linear, follow?.EaseMode ?? EasingMode.InOut);
173178
var hmdHz = (int) Math.Round(_vr.GetFloatTrackedDeviceProperty(0, ETrackedDeviceProperty.Prop_DisplayFrequency_Float));
174179
hz = properties.AnimationHz > 0 ? properties.AnimationHz : hmdHz;
175180
msPerFrame = 1000 / hz;
181+
182+
// Input
183+
OpenVR.Overlay.SetOverlayInputMethod(
184+
_overlayHandle,
185+
properties.Input?.Mouse == true
186+
? VROverlayInputMethod.Mouse
187+
: VROverlayInputMethod.None
188+
);
189+
OpenVR.Overlay.SetOverlayFlag(_overlayHandle, VROverlayFlags.SendVRDiscreteScrollEvents, properties.Input?.DiscreteScroll == true);
190+
OpenVR.Overlay.SetOverlayFlag(_overlayHandle, VROverlayFlags.SendVRSmoothScrollEvents, properties.Input?.SmoothScroll == true);
191+
OpenVR.Overlay.SetOverlayFlag(_overlayHandle, VROverlayFlags.SendVRTouchpadEvents, properties.Input?.Touchpad == true);
192+
OpenVR.Overlay.SetOverlayFlag(_overlayHandle, VROverlayFlags.MakeOverlaysInteractiveIfVisible, _isUsingInput);
193+
OpenVR.Overlay.SetOverlayFlag(_overlayHandle, VROverlayFlags.VisibleInDashboard, false);
176194

177195
// Set anchor
178196
switch (properties.AnchorType)
@@ -289,6 +307,14 @@ bool LoadImage()
289307
}
290308
#endregion
291309
}
310+
else if(_isUsingInput)
311+
{
312+
var overlayEvents = _vr.GetNewOverlayEvents(_overlayHandle);
313+
foreach (var overlayEvent in overlayEvents)
314+
{
315+
_overlayEvent?.Invoke(_sessionId, _nonce ?? "", overlayEvent);
316+
}
317+
}
292318

293319
if (!skip && stage != AnimationStage.Idle && stage != AnimationStage.LoadingImage) // Animate
294320
{
@@ -474,6 +500,7 @@ public void Shutdown() {
474500
_requestForNewData = null;
475501
_responseAtCompletion = null;
476502
_responseAtError = null;
503+
_overlayEvent = null;
477504
_data = null;
478505
_shouldShutdown = true;
479506
}

OpenVROverlayPipe/Notification/Overlay.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ internal class Overlay
1919
private readonly int _channel;
2020
private bool _initSuccess;
2121
private readonly ConcurrentQueue<QueueItem?> _notifications = new();
22-
public EventHandler<string[]>? DoneEvent;
22+
public EventHandler<OverlayDone>? DoneEvent;
23+
public EventHandler<OverlayEvent>? OverlayEvent;
2324

2425
public Overlay(string title, int channel) {
2526
_title = title;
@@ -55,10 +56,14 @@ private void Reinitialize() {
5556
},
5657
(sessionId, nonce) => {
5758
Debug.WriteLine($"Nonce value at completion: {nonce}");
58-
DoneEvent?.Invoke(this, new string[] { sessionId, nonce, "" });
59+
DoneEvent?.Invoke(this, new OverlayDone(sessionId, nonce, _channel, ""));
5960
},
6061
(sessionId, nonce, error) => {
61-
DoneEvent?.Invoke(this, new string[] { sessionId, nonce, error });
62+
DoneEvent?.Invoke(this, new OverlayDone(sessionId, nonce, _channel, error ?? ""));
63+
},
64+
(sessionId, nonce, vrEvent) =>
65+
{
66+
OverlayEvent?.Invoke(this, new OverlayEvent(sessionId, nonce, _channel, vrEvent));
6267
}
6368
);
6469
});
@@ -81,4 +86,20 @@ public void EnqueueNotification(string sessionId, DataOverlay data, string? nonc
8186
return success ? item : null;
8287
}
8388
}
89+
90+
internal class OverlayDone(string sessionId, string nonce, int channel, string error)
91+
{
92+
public string SessionId = sessionId;
93+
public string Nonce = nonce;
94+
public int Channel = channel;
95+
public string Error = error;
96+
}
97+
98+
internal class OverlayEvent(string sessionId, string nonce, int channel, VREvent_t vrEvent)
99+
{
100+
public string SessionId = sessionId;
101+
public string Nonce = nonce;
102+
public int Channel = channel;
103+
public VREvent_t Event = vrEvent;
104+
}
84105
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using Valve.VR;
2+
3+
namespace OpenVROverlayPipe.Output;
4+
5+
public class OutputDataButton(EVRMouseButton button = 0)
6+
{
7+
public EVRMouseButton Button = button;
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace OpenVROverlayPipe.Output;
2+
3+
public class OutputDataPosition(float x = 0, float y = 0)
4+
{
5+
public float X = x;
6+
public float Y = y;
7+
}

0 commit comments

Comments
 (0)