mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-01-11 04:45:43 +00:00
[Linux] Fixed poll() in libinput event loop
This commit is contained in:
parent
67727d2e9b
commit
468a8518cb
|
@ -51,7 +51,7 @@ namespace OpenTK.Platform.Linux
|
||||||
Out = 0x04,
|
Out = 0x04,
|
||||||
Error = 0x08,
|
Error = 0x08,
|
||||||
Hup = 0x10,
|
Hup = 0x10,
|
||||||
Nval = 0x20,
|
Invalid = 0x20,
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|
|
@ -90,7 +90,9 @@ namespace OpenTK.Platform.Linux
|
||||||
public MouseState State;
|
public MouseState State;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static readonly object Sync = new object();
|
||||||
static readonly Key[] KeyMap = Evdev.KeyMap;
|
static readonly Key[] KeyMap = Evdev.KeyMap;
|
||||||
|
static long DeviceFDCount;
|
||||||
DeviceCollection<KeyboardDevice> Keyboards = new DeviceCollection<KeyboardDevice>();
|
DeviceCollection<KeyboardDevice> Keyboards = new DeviceCollection<KeyboardDevice>();
|
||||||
DeviceCollection<MouseDevice> Mice = new DeviceCollection<MouseDevice>();
|
DeviceCollection<MouseDevice> Mice = new DeviceCollection<MouseDevice>();
|
||||||
|
|
||||||
|
@ -105,35 +107,33 @@ namespace OpenTK.Platform.Linux
|
||||||
public LinuxInput()
|
public LinuxInput()
|
||||||
{
|
{
|
||||||
Debug.Print("[Linux] Initializing {0}", GetType().Name);
|
Debug.Print("[Linux] Initializing {0}", GetType().Name);
|
||||||
|
Debug.Indent();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Semaphore ready = new Semaphore(0, 1);
|
||||||
input_thread = new Thread(InputThreadLoop);
|
input_thread = new Thread(InputThreadLoop);
|
||||||
input_thread.IsBackground = true;
|
input_thread.IsBackground = true;
|
||||||
|
input_thread.Start(ready);
|
||||||
|
|
||||||
// Todo: add static path fallback when udev is not installed.
|
// Wait until the input thread is ready.
|
||||||
udev = Udev.New();
|
// Note: it would be nicer if we could avoid this.
|
||||||
if (udev == IntPtr.Zero)
|
// however we need to marshal errors back to the caller
|
||||||
|
// as exceptions.
|
||||||
|
// Todo: in a future version, we should add an "Application" object
|
||||||
|
// to handle all communication with the OS (including event processing.)
|
||||||
|
// Once we do that, we can remove all separate input threads.
|
||||||
|
ready.WaitOne();
|
||||||
|
if (exit != 0)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("[Input] Udev.New() failed.");
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
input_context = LibInput.CreateContext(input_interface,
|
finally
|
||||||
IntPtr.Zero, udev, "seat0");
|
|
||||||
if (input_context == IntPtr.Zero)
|
|
||||||
{
|
{
|
||||||
throw new NotSupportedException(
|
Debug.Print("Initialization {0}", exit == 0 ?
|
||||||
String.Format("[Input] LibInput.CreateContext({0:x}) failed.", udev));
|
"complete" : "failed");
|
||||||
|
Debug.Unindent();
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = LibInput.GetFD(input_context);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException(
|
|
||||||
String.Format("[Input] LibInput.GetFD({0:x}) failed.", input_context));
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessEvents(input_context);
|
|
||||||
LibInput.Resume(input_context);
|
|
||||||
//input_thread.Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Private Members
|
#region Private Members
|
||||||
|
@ -142,7 +142,16 @@ namespace OpenTK.Platform.Linux
|
||||||
static void CloseRestrictedHandler(int fd, IntPtr data)
|
static void CloseRestrictedHandler(int fd, IntPtr data)
|
||||||
{
|
{
|
||||||
Debug.Print("[Input] Closing fd {0}", fd);
|
Debug.Print("[Input] Closing fd {0}", fd);
|
||||||
Libc.close(fd);
|
int ret = Libc.close(fd);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Failed to close fd {0}. Error: {1}", fd, ret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Interlocked.Decrement(ref DeviceFDCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static OpenRestrictedCallback OpenRestricted = OpenRestrictedHandler;
|
static OpenRestrictedCallback OpenRestricted = OpenRestrictedHandler;
|
||||||
|
@ -152,30 +161,89 @@ namespace OpenTK.Platform.Linux
|
||||||
Debug.Print("[Input] Opening '{0}' with flags {1}. fd:{2}",
|
Debug.Print("[Input] Opening '{0}' with flags {1}. fd:{2}",
|
||||||
Marshal.PtrToStringAnsi(path), (OpenFlags)flags, fd);
|
Marshal.PtrToStringAnsi(path), (OpenFlags)flags, fd);
|
||||||
|
|
||||||
|
if (fd >= 0)
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref DeviceFDCount);
|
||||||
|
}
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputThreadLoop()
|
void InputThreadLoop(object semaphore)
|
||||||
{
|
{
|
||||||
|
Debug.Print("[Input] Running on thread {0}", Thread.CurrentThread.ManagedThreadId);
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
// Inform the parent thread that initialization has completed successfully
|
||||||
|
(semaphore as Semaphore).Release();
|
||||||
|
Debug.Print("[Input] Released main thread.", input_context);
|
||||||
|
|
||||||
|
// Use a blocking poll for input messages, in order to reduce CPU usage
|
||||||
PollFD poll_fd = new PollFD();
|
PollFD poll_fd = new PollFD();
|
||||||
poll_fd.fd = fd;
|
poll_fd.fd = fd;
|
||||||
poll_fd.events = PollFlags.In;
|
poll_fd.events = PollFlags.In;
|
||||||
|
Debug.Print("[Input] Created PollFD({0}, {1})", poll_fd.fd, poll_fd.events);
|
||||||
|
|
||||||
|
Debug.Print("[Input] Entering input loop.", poll_fd.fd, poll_fd.events);
|
||||||
while (Interlocked.Read(ref exit) == 0)
|
while (Interlocked.Read(ref exit) == 0)
|
||||||
{
|
{
|
||||||
int ret = Libc.poll(ref poll_fd, 1, -1);
|
int ret = Libc.poll(ref poll_fd, 1, -1);
|
||||||
if (ret > 0 && (poll_fd.revents & PollFlags.In) != 0)
|
if (ret > 0 && (poll_fd.revents & (PollFlags.In | PollFlags.Pri)) != 0)
|
||||||
{
|
{
|
||||||
ProcessEvents(input_context);
|
ProcessEvents(input_context);
|
||||||
}
|
}
|
||||||
else if (ret < 0)
|
|
||||||
|
if ((poll_fd.revents & (PollFlags.Hup | PollFlags.Error | PollFlags.Invalid)) != 0)
|
||||||
{
|
{
|
||||||
// An error has occurred
|
// An error has occurred
|
||||||
Debug.Print("[Input] Exiting input thread {0} [ret:{1} events:{2}]",
|
Debug.Print("[Input] Exiting input thread {0} due to error [ret:{1} events:{2}]",
|
||||||
input_thread.ManagedThreadId, ret, poll_fd.revents);
|
input_thread.ManagedThreadId, ret, poll_fd.revents);
|
||||||
Interlocked.Increment(ref exit);
|
Interlocked.Increment(ref exit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Debug.Print("[Input] Exited input loop.", poll_fd.fd, poll_fd.events);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Setup()
|
||||||
|
{
|
||||||
|
// Todo: add static path fallback when udev is not installed.
|
||||||
|
udev = Udev.New();
|
||||||
|
if (udev == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] Udev.New() failed.");
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] Udev.New() = {0:x}", udev);
|
||||||
|
|
||||||
|
input_context = LibInput.CreateContext(input_interface, IntPtr.Zero, udev, "seat0");
|
||||||
|
if (input_context == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] LibInput.CreateContext({0:x}) failed.", udev);
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] LibInput.CreateContext({0:x}) = {1:x}", udev, input_context);
|
||||||
|
|
||||||
|
fd = LibInput.GetFD(input_context);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Input] LibInput.GetFD({0:x}) failed.", input_context);
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Debug.Print("[Input] LibInput.GetFD({0:x}) = {1}.", input_context, fd);
|
||||||
|
|
||||||
|
ProcessEvents(input_context);
|
||||||
|
LibInput.Resume(input_context);
|
||||||
|
Debug.Print("[Input] LibInput.Resume({0:x})", input_context);
|
||||||
|
|
||||||
|
if (Interlocked.Read(ref DeviceFDCount) <= 0)
|
||||||
|
{
|
||||||
|
Debug.Print("[Error] Failed to open any input devices.");
|
||||||
|
Debug.Print("[Error] Ensure that you have access to '/dev/input/event*'.");
|
||||||
|
Interlocked.Increment(ref exit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessEvents(IntPtr input_context)
|
void ProcessEvents(IntPtr input_context)
|
||||||
|
@ -201,6 +269,9 @@ namespace OpenTK.Platform.Linux
|
||||||
IntPtr device = LibInput.GetDevice(pevent);
|
IntPtr device = LibInput.GetDevice(pevent);
|
||||||
InputEventType type = LibInput.GetEventType(pevent);
|
InputEventType type = LibInput.GetEventType(pevent);
|
||||||
Debug.Print(type.ToString());
|
Debug.Print(type.ToString());
|
||||||
|
|
||||||
|
lock (Sync)
|
||||||
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case InputEventType.DeviceAdded:
|
case InputEventType.DeviceAdded:
|
||||||
|
@ -215,6 +286,7 @@ namespace OpenTK.Platform.Linux
|
||||||
HandleKeyboard(input_context, device, LibInput.GetKeyboardEvent(pevent));
|
HandleKeyboard(input_context, device, LibInput.GetKeyboardEvent(pevent));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LibInput.DestroyEvent(pevent);
|
LibInput.DestroyEvent(pevent);
|
||||||
}
|
}
|
||||||
|
@ -281,7 +353,8 @@ namespace OpenTK.Platform.Linux
|
||||||
|
|
||||||
KeyboardState IKeyboardDriver2.GetState()
|
KeyboardState IKeyboardDriver2.GetState()
|
||||||
{
|
{
|
||||||
ProcessEvents(input_context);
|
lock (Sync)
|
||||||
|
{
|
||||||
KeyboardState state = new KeyboardState();
|
KeyboardState state = new KeyboardState();
|
||||||
foreach (KeyboardDevice keyboard in Keyboards)
|
foreach (KeyboardDevice keyboard in Keyboards)
|
||||||
{
|
{
|
||||||
|
@ -289,10 +362,12 @@ namespace OpenTK.Platform.Linux
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
KeyboardState IKeyboardDriver2.GetState(int index)
|
KeyboardState IKeyboardDriver2.GetState(int index)
|
||||||
{
|
{
|
||||||
ProcessEvents(input_context);
|
lock (Sync)
|
||||||
|
{
|
||||||
KeyboardDevice device = Keyboards.FromIndex(index);
|
KeyboardDevice device = Keyboards.FromIndex(index);
|
||||||
if (device != null)
|
if (device != null)
|
||||||
{
|
{
|
||||||
|
@ -303,8 +378,11 @@ namespace OpenTK.Platform.Linux
|
||||||
return new KeyboardState();
|
return new KeyboardState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string IKeyboardDriver2.GetDeviceName(int index)
|
string IKeyboardDriver2.GetDeviceName(int index)
|
||||||
|
{
|
||||||
|
lock (Sync)
|
||||||
{
|
{
|
||||||
KeyboardDevice device = Keyboards.FromIndex(index);
|
KeyboardDevice device = Keyboards.FromIndex(index);
|
||||||
if (device != null)
|
if (device != null)
|
||||||
|
@ -316,6 +394,7 @@ namespace OpenTK.Platform.Linux
|
||||||
return String.Empty;
|
return String.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue