From 4473c8373e6c2aaa5f951fb09e0052b518319a7f Mon Sep 17 00:00:00 2001 From: "Stefanos A." Date: Tue, 14 Jan 2014 18:37:16 +0100 Subject: [PATCH] [X11] Implemented joystick hotplugging This is a work in progress. --- Source/OpenTK/Platform/X11/X11Joystick.cs | 168 +++++++++++++++------- 1 file changed, 118 insertions(+), 50 deletions(-) diff --git a/Source/OpenTK/Platform/X11/X11Joystick.cs b/Source/OpenTK/Platform/X11/X11Joystick.cs index cbab7099..e8870287 100644 --- a/Source/OpenTK/Platform/X11/X11Joystick.cs +++ b/Source/OpenTK/Platform/X11/X11Joystick.cs @@ -28,20 +28,29 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Runtime.InteropServices; using System.Text; using OpenTK.Input; namespace OpenTK.Platform.X11 { - struct X11JoyDetails { } + struct X11JoyDetails + { + public bool IsConnected; + } - sealed class X11Joystick : IJoystickDriver, IJoystickDriver2, IGamePadDriver + sealed class X11Joystick : IJoystickDriver2 { #region Fields - List sticks = new List(); - IList sticks_readonly; + readonly object sync = new object(); + + readonly FileSystemWatcher watcher = new FileSystemWatcher(JoystickPath); + readonly FileSystemWatcher watcher_legacy = new FileSystemWatcher(JoystickPathLegacy); + + readonly Dictionary index_to_stick = new Dictionary(); + List> sticks = new List>(); bool disposed; @@ -51,16 +60,29 @@ namespace OpenTK.Platform.X11 public X11Joystick() { - sticks_readonly = sticks.AsReadOnly(); + watcher.Created += JoystickAdded; + watcher.Deleted += JoystickRemoved; + watcher.EnableRaisingEvents = true; + watcher_legacy.Created += JoystickAdded; + watcher_legacy.Deleted += JoystickRemoved; + watcher_legacy.EnableRaisingEvents = true; + } + + #endregion + + #region Private Members + + void OpenJoysticks() + { int number = 0, max_sticks = 25; while (number < max_sticks) { - JoystickDevice stick = OpenJoystick(JoystickPath, number++); + JoystickDevice stick = OpenJoystick(JoystickPath, number++); if (stick != null) { //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})", - //number, stick.Axis.Count, stick.Button.Count, JoystickPath); + //number, stick.Axis.Count, stick.Button.Count, JoystickPath); sticks.Add(stick); } } @@ -68,30 +90,98 @@ namespace OpenTK.Platform.X11 number = 0; while (number < max_sticks) { - JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++); + JoystickDevice stick = OpenJoystick(JoystickPathLegacy, number++); if (stick != null) { //stick.Description = String.Format("USB Joystick {0} ({1} axes, {2} buttons, {3}{0})", - //number, stick.Axis.Count, stick.Button.Count, JoystickPathLegacy); + //number, stick.Axis.Count, stick.Button.Count, JoystickPathLegacy); sticks.Add(stick); } } } + int GetJoystickNumber(string path) + { + if (path.StartsWith("js")) + { + int num; + if (Int32.TryParse(path.Substring(2), out num)) + { + return num; + } + } + return -1; + } + + void JoystickAdded(object sender, FileSystemEventArgs e) + { + lock (sync) + { + string file = Path.GetFileName(e.FullPath); + int number = GetJoystickNumber(file); + if (number != -1) + { + JoystickDevice stick = OpenJoystick(e.FullPath, number); + + // Find the first disconnected joystick (if any) + int i; + for (i = 0; i < sticks.Count; i++) + { + if (!stick.Details.IsConnected) + { + break; + } + } + + // If no disconnected joystick exists, append a new slot + if (i == sticks.Count) + { + sticks.Add(stick); + } + else + { + sticks[i] = stick; + } + + // Map player index to joystick + index_to_stick.Add(index_to_stick.Count, i); + } + } + } + + void JoystickRemoved(object sender, FileSystemEventArgs e) + { + lock (sync) + { + string file = Path.GetFileName(e.FullPath); + int number = GetJoystickNumber(file); + if (number != -1) + { + // Find which joystick id matches this number + int i; + for (i = 0; i < sticks.Count; i++) + { + if (sticks[i].Id == number) + { + break; + } + } + + if (i == sticks.Count) + { + Debug.Print("[Evdev] Joystick id {0} does not exist.", number); + } + else + { + JoystickDevice stick = sticks[i]; + stick.Details.IsConnected = false; + } + } + } + } + #endregion - #region IJoystickDriver - - public int DeviceCount - { - get { return sticks.Count; } - } - - public IList Joysticks - { - get { Poll(); return sticks_readonly; } - } - public void Poll() { JoystickEvent e; @@ -123,13 +213,11 @@ namespace OpenTK.Platform.X11 } } - #endregion - #region Private Members JoystickDevice OpenJoystick(string base_path, int number) { - string path = base_path + number.ToString(); + string path = Path.Combine(base_path, "js" + number.ToString()); JoystickDevice stick = null; int fd = -1; @@ -159,6 +247,10 @@ namespace OpenTK.Platform.X11 UnsafeNativeMethods.ioctl(fd, JoystickIoctlCode.Name128, sb); stick.Description = sb.ToString(); + stick.Id = number; + + stick.Details.IsConnected = true; + Debug.Print("Found joystick on path {0}", path); } finally @@ -196,8 +288,8 @@ namespace OpenTK.Platform.X11 Name128 = (2u << 30) | (0x6A << 8) | (0x13 << 0) | (128 << 16) //JSIOCGNAME(128), which is _IOC(_IO_READ, 'j', 0x13, len) } - static readonly string JoystickPath = "/dev/input/js"; - static readonly string JoystickPathLegacy = "/dev/js"; + static readonly string JoystickPath = "/dev/input"; + static readonly string JoystickPathLegacy = "/dev"; [Flags] enum OpenFlags @@ -259,30 +351,6 @@ namespace OpenTK.Platform.X11 #endregion - #region IGamePadDriver Members - - public GamePadCapabilities GetCapabilities(int index) - { - return new GamePadCapabilities(); - } - - public GamePadState GetState(int index) - { - return new GamePadState(); - } - - public string GetName(int index) - { - return String.Empty; - } - - public bool SetVibration(int index, float left, float right) - { - return false; - } - - #endregion - #region IJoystickDriver2 Members JoystickState IJoystickDriver2.GetState(int index)