Skip to content

Commit 8ae58a6

Browse files
committed
Add project files.
1 parent e15ed23 commit 8ae58a6

File tree

4 files changed

+366
-0
lines changed

4 files changed

+366
-0
lines changed

opengloves-osc.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.5.33516.290
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "opengloves-osc", "opengloves-osc\opengloves-osc.csproj", "{57A61514-BF07-4E25-A8A8-C6234F5DD0E1}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{57A61514-BF07-4E25-A8A8-C6234F5DD0E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{57A61514-BF07-4E25-A8A8-C6234F5DD0E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{57A61514-BF07-4E25-A8A8-C6234F5DD0E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{57A61514-BF07-4E25-A8A8-C6234F5DD0E1}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {0661A035-2C3E-4330-9006-6DE49F0C82BF}
24+
EndGlobalSection
25+
EndGlobal

opengloves-osc/GloveInputLink.cs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
using System.IO.Pipes;
2+
using System.Runtime.InteropServices;
3+
4+
/*
5+
* library created by Rin.
6+
* discord: Riɳ#0001
7+
*
8+
* This library is for interacting with the openGloves driver.
9+
* More specifically, it is designed to send glove inputs via named pipes to control the buttons, fingers, and other inputs.
10+
*
11+
* written in c# for those like me who are scared of c++
12+
*
13+
* --------------------Thanks To--------------------
14+
*
15+
* danwillm - He helped a ton with formatting the InputData struct.
16+
* I couldn't have done this without him so huge thanks.
17+
*
18+
* L4rs - This library took heavy inspiration from his c# library for sending force feedback inputs to the glove via named pipes. I would have been very lost without him.
19+
* https://github.com/Hydr4bytes/OpenGlovesLib - his library linked here.
20+
*
21+
* -------------------------------------------------
22+
*/
23+
24+
namespace GloveInputLib
25+
{
26+
//Struct InputData is a struct that contains all of the button, finger, and linear inputs. This is what's sent to the driver via the named pipe.
27+
[StructLayout(LayoutKind.Sequential)]
28+
public unsafe struct InputData
29+
{
30+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
31+
public float[] flexion; //range: 0 -> 1
32+
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
33+
public float[] splay; //range: -1 -> 1
34+
public float joyX; //range: -1 -> 1
35+
public float joyY; //range: -1 -> 1
36+
[MarshalAs(UnmanagedType.I1)]
37+
public bool joyButton;
38+
[MarshalAs(UnmanagedType.I1)]
39+
public bool trgButton;
40+
[MarshalAs(UnmanagedType.I1)]
41+
public bool aButton;
42+
[MarshalAs(UnmanagedType.I1)]
43+
public bool bButton;
44+
[MarshalAs(UnmanagedType.I1)]
45+
public bool grab;
46+
[MarshalAs(UnmanagedType.I1)]
47+
public bool pinch;
48+
[MarshalAs(UnmanagedType.I1)]
49+
public bool menu;
50+
[MarshalAs(UnmanagedType.I1)]
51+
public bool calibrate;
52+
public float trgValue;//range: 0 -> 1
53+
54+
//constructor that uses a 1d array for flexion.
55+
public InputData(float[] flexion, float[] splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool menu, bool calibrate, float trgValue)
56+
{
57+
this.flexion = flexion;
58+
this.splay = splay;
59+
this.joyX = joyX;
60+
this.joyY = joyY;
61+
this.joyButton = joyButton;
62+
this.trgButton = trgButton;
63+
this.aButton = aButton;
64+
this.bButton = bButton;
65+
this.grab = grab;
66+
this.pinch = pinch;
67+
this.menu = menu;
68+
this.calibrate = calibrate;
69+
this.trgValue = trgValue;
70+
}
71+
72+
//this constructor is for if you want to instead use a 2d array for the flexion. it's an array of 5 arrays of 4 floats. (float[5,4] flexion). each finger is represented by an array. each float in the array represents a joint.
73+
public InputData(float[,] flexion, float[] splay, float joyX, float joyY, bool joyButton, bool trgButton, bool aButton, bool bButton, bool grab, bool pinch, bool menu, bool calibrate, float trgValue)
74+
{
75+
this.flexion = new float[20];
76+
//nested for loops to turn the 2d array to a 1d array.
77+
int flexIndex = 0;
78+
for (int finger = 0; finger < 5; finger++)
79+
{
80+
for (int joint = 0; joint < 4; joint++)
81+
{
82+
this.flexion[flexIndex++] = flexion[finger, joint];
83+
}
84+
}
85+
this.splay = splay;
86+
this.joyX = joyX;
87+
this.joyY = joyY;
88+
this.joyButton = joyButton;
89+
this.trgButton = trgButton;
90+
this.aButton = aButton;
91+
this.bButton = bButton;
92+
this.grab = grab;
93+
this.pinch = pinch;
94+
this.menu = menu;
95+
this.calibrate = calibrate;
96+
this.trgValue = trgValue;
97+
}
98+
99+
//default constructor that sets all booleon values to false and all float values to 0.
100+
public InputData()
101+
{
102+
flexion = new float[20] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
103+
splay = new float[5] { 0, 0, 0, 0, 0 };
104+
joyX = 0;
105+
joyY = 0;
106+
joyButton = false;
107+
trgButton = false;
108+
aButton = false;
109+
bButton = false;
110+
grab = false;
111+
pinch = false;
112+
menu = false;
113+
calibrate = false;
114+
trgValue = 0;
115+
}
116+
}
117+
118+
119+
//The GloveInputLink class is used for actually sending inputs to
120+
public class GloveInputLink
121+
{
122+
private NamedPipeClientStream pipe;
123+
124+
//Handness is an enum used to pass what hand the GloveInputLink object will write to
125+
public enum Handness
126+
{
127+
Left,
128+
Right
129+
}
130+
131+
//Constructor. takes handness parameter to tell it to write to specific hand.
132+
public GloveInputLink(Handness handness)
133+
{
134+
string hand = handness == Handness.Right ? "right" : "left";
135+
pipe = new NamedPipeClientStream(".", $"vrapplication\\input\\glove\\v2\\{hand}", PipeDirection.Out);
136+
//connect to the pipe
137+
Console.WriteLine($"Connecting to {hand} hand pipe...");
138+
try
139+
{
140+
//try to connect to the pipe, timeout after 5 seconds
141+
pipe.Connect(5000);
142+
}
143+
catch (Exception e)
144+
{
145+
//if an error is thrown log the message
146+
Console.WriteLine(e.Message);
147+
}
148+
if (pipe.IsConnected)
149+
Console.WriteLine($"Connected! CanWrite:{pipe.CanWrite}");
150+
else
151+
Console.WriteLine("Connection failed");
152+
}
153+
154+
//set all input values to default.
155+
public void Relax()
156+
{
157+
Write(new InputData());
158+
}
159+
160+
//send values to the driver.
161+
public void Write(InputData input)
162+
{
163+
if (!pipe.IsConnected) return;
164+
165+
int size = Marshal.SizeOf(input);
166+
//Console.WriteLine(size);
167+
byte[] arr = new byte[size];
168+
169+
IntPtr ptr = Marshal.AllocHGlobal(size);
170+
Marshal.StructureToPtr(input, ptr, true);
171+
Marshal.Copy(ptr, arr, 0, size);
172+
Marshal.FreeHGlobal(ptr);
173+
174+
pipe.Write(arr, 0, size);
175+
}
176+
}
177+
}

opengloves-osc/Program.cs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+

2+
using GloveInputLib;
3+
using Rug.Osc;
4+
5+
public class Program
6+
{
7+
8+
static OscAddressManager m_Listener = default!;
9+
static OscReceiver receiver = default!;
10+
static Thread thread = default!;
11+
static InputData input;
12+
static GloveInputLink inputLink = default!;
13+
static void Main(string[] args)
14+
{
15+
16+
inputLink = new GloveInputLink(GloveInputLink.Handness.Left);
17+
18+
float[] flextion = new float[20] { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
19+
20+
float[] splay = new float[5] { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };
21+
22+
23+
input = new InputData(
24+
flextion,
25+
splay,
26+
0,
27+
0,
28+
false,
29+
false,
30+
false,
31+
false,
32+
false,
33+
false,
34+
false,
35+
false,
36+
0
37+
);
38+
39+
40+
41+
int port = 9007;
42+
receiver = new OscReceiver(port);
43+
44+
receiver.Connect();
45+
46+
m_Listener = new OscAddressManager();
47+
48+
m_Listener.Attach("/input/Horizontal", f_joyX);
49+
m_Listener.Attach("/input/Vertical", f_joyY);
50+
m_Listener.Attach("/button/trigger", f_trgButton);
51+
m_Listener.Attach("/button/a", f_aButton);
52+
m_Listener.Attach("/button/b", msg => { input.bButton = Convert.ToBoolean(msg[0]); send(); });
53+
m_Listener.Attach("/button/joy", msg => { input.joyButton = Convert.ToBoolean(msg[0]); send(); });
54+
m_Listener.Attach("/button/grab", f_grab);
55+
m_Listener.Attach("/button/menu", f_menu);
56+
try
57+
{
58+
while (receiver.State != OscSocketState.Closed)
59+
{
60+
if (receiver.State == OscSocketState.Connected)
61+
{
62+
OscPacket packet = receiver.Receive();
63+
64+
switch (m_Listener.ShouldInvoke(packet))
65+
{
66+
case OscPacketInvokeAction.Invoke:
67+
68+
if (m_Listener.Invoke(packet))
69+
{
70+
Console.WriteLine("Unhandled packet: {0}",packet);
71+
}
72+
break;
73+
case OscPacketInvokeAction.DontInvoke:
74+
Console.WriteLine("Cannot invoke");
75+
Console.WriteLine(packet.ToString());
76+
break;
77+
case OscPacketInvokeAction.HasError:
78+
Console.WriteLine("Error reading osc packet, " + packet.Error);
79+
Console.WriteLine(packet.ErrorMessage);
80+
break;
81+
case OscPacketInvokeAction.Pospone:
82+
Console.WriteLine("Postponed bundle");
83+
Console.WriteLine(packet.ToString());
84+
break;
85+
default:
86+
break;
87+
}
88+
89+
}
90+
}
91+
}
92+
catch (Exception ex)
93+
{
94+
Console.WriteLine("Exception in listen loop");
95+
Console.WriteLine(ex.Message);
96+
}
97+
98+
receiver.Close();
99+
100+
}
101+
102+
static void f_joyX(OscMessage message)
103+
{
104+
float x = (float)message[0];
105+
input.joyX = x; send();
106+
}
107+
static void f_joyY(OscMessage message)
108+
{
109+
float val = (float)message[0];
110+
input.joyY = val; send();
111+
}
112+
static void f_grab(OscMessage message)
113+
{
114+
bool val = Convert.ToBoolean(message[0]);
115+
input.grab = val; send();
116+
}
117+
static void f_aButton(OscMessage message)
118+
{
119+
Console.WriteLine(message);
120+
bool val = Convert.ToBoolean(message[0]);
121+
input.aButton = val;
122+
Console.WriteLine("abutton == {0}",input.aButton.ToString() ?? "null");
123+
send();
124+
}
125+
static void f_bButton(OscMessage message)
126+
{
127+
bool val = Convert.ToBoolean(message[0]);
128+
input.bButton = val; send();
129+
}
130+
131+
static void f_menu(OscMessage message)
132+
{
133+
bool val = Convert.ToBoolean(message[0]);
134+
input.menu = val; send();
135+
}
136+
137+
static void f_trgButton(OscMessage message)
138+
{
139+
bool val = Convert.ToBoolean(message[0]);
140+
input.trgButton = val;
141+
send();
142+
}
143+
144+
private static void send()
145+
{
146+
inputLink.Write(input);
147+
}
148+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<RootNamespace>opengloves_osc</RootNamespace>
7+
<ImplicitUsings>enable</ImplicitUsings>
8+
<Nullable>enable</Nullable>
9+
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="Rug.Osc" Version="1.2.5" />
14+
</ItemGroup>
15+
16+
</Project>

0 commit comments

Comments
 (0)