Skip to content

Commit

Permalink
[Linux] Delay input device detection until a key is pressed
Browse files Browse the repository at this point in the history
  • Loading branch information
thefiddler committed Jul 18, 2014
1 parent 07d496d commit 00b5174
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 12 deletions.
12 changes: 10 additions & 2 deletions Source/OpenTK/Platform/DeviceCollection.cs
Expand Up @@ -77,14 +77,22 @@ public void Add(int id, T device)

public void Remove(int id)
{
if (!Map.ContainsKey(id))
if (!TryRemove(id))
{
Debug.Print("Invalid DeviceCollection<{0}> id: {1}", typeof(T).FullName, id);
return;
}
}

public bool TryRemove(int id)
{
if (!Map.ContainsKey(id))
{
return false;
}

Devices[Map[id]] = default(T);
Map.Remove(id);
return true;
}

public T FromIndex(int index)
Expand Down
48 changes: 38 additions & 10 deletions Source/OpenTK/Platform/Linux/LinuxInput.cs
Expand Up @@ -117,7 +117,6 @@ class KeyboardDevice : DeviceBase
public KeyboardDevice(IntPtr device, int id)
: base(device, id)
{
State.SetIsConnected(true);
}
}

Expand All @@ -128,13 +127,23 @@ class MouseDevice : DeviceBase
public MouseDevice(IntPtr device, int id)
: base(device, id)
{
State.SetIsConnected(true);
}
}

static readonly object Sync = new object();
static readonly Key[] KeyMap = Evdev.KeyMap;
static long DeviceFDCount;

// libinput returns various devices with keyboard/pointer even though
// they are not traditional keyboards/mice (for example "Integrated Camera"
// can be detected as a keyboard.)
// Since there is no API to retrieve actual device capabilities,
// we add all detected devices to a "candidate" list and promote them
// to an actual keyboard/mouse only when we receive a valid input event.
// This is far from optimal, but it appears to be the only viable solution
// unless a new API is added to libinput.
DeviceCollection<KeyboardDevice> KeyboardCandidates = new DeviceCollection<KeyboardDevice>();
DeviceCollection<MouseDevice> MouseCandidates = new DeviceCollection<MouseDevice>();
DeviceCollection<KeyboardDevice> Keyboards = new DeviceCollection<KeyboardDevice>();
DeviceCollection<MouseDevice> Mice = new DeviceCollection<MouseDevice>();

Expand Down Expand Up @@ -399,15 +408,15 @@ void HandleDeviceAdded(IntPtr context, IntPtr device)
if (LibInput.DeviceHasCapability(device, DeviceCapability.Keyboard))
{
KeyboardDevice keyboard = new KeyboardDevice(device, Keyboards.Count);
Keyboards.Add(keyboard.Id, keyboard);
KeyboardCandidates.Add(keyboard.Id, keyboard);
Debug.Print("[Input] Added keyboard device {0} '{1}' on '{2}' ('{3}')",
keyboard.Id, keyboard.Name, keyboard.LogicalSeatName, keyboard.PhysicalSeatName);
}

if (LibInput.DeviceHasCapability(device, DeviceCapability.Mouse))
{
MouseDevice mouse = new MouseDevice(device, Mice.Count);
Mice.Add(mouse.Id, mouse);
MouseCandidates.Add(mouse.Id, mouse);
Debug.Print("[Input] Added mouse device {0} '{1}' on '{2}' ('{3}')",
mouse.Id, mouse.Name, mouse.LogicalSeatName, mouse.PhysicalSeatName);
}
Expand All @@ -423,20 +432,25 @@ void HandleDeviceRemoved(IntPtr context, IntPtr device)
if (LibInput.DeviceHasCapability(device, DeviceCapability.Keyboard))
{
int id = GetId(device);
Keyboards.Remove(id);
Keyboards.TryRemove(id);
KeyboardCandidates.TryRemove(id);
}

if (LibInput.DeviceHasCapability(device, DeviceCapability.Mouse))
{
int id = GetId(device);
Mice.Remove(id);
Mice.TryRemove(id);
MouseCandidates.TryRemove(id);
}
}

void HandleKeyboard(KeyboardDevice device, KeyboardEvent e)
{
if (device != null)
{
device.State.SetIsConnected(true);
Debug.Print("[Input] Added keyboard {0}", device.Id);

Key key = Key.Unknown;
uint raw = e.Key;
if (raw >= 0 && raw < KeyMap.Length)
Expand All @@ -457,6 +471,8 @@ void HandlePointerAxis(MouseDevice mouse, PointerEvent e)
{
if (mouse != null)
{
mouse.State.SetIsConnected(true);

double value = e.AxisValue;
PointerAxis axis = e.Axis;
switch (axis)
Expand All @@ -480,6 +496,8 @@ void HandlePointerButton(MouseDevice mouse, PointerEvent e)
{
if (mouse != null)
{
mouse.State.SetIsConnected(true);

MouseButton button = Evdev.GetMouseButton(e.Button);
ButtonState state = e.ButtonState;
mouse.State[(MouseButton)button] = state == ButtonState.Pressed;
Expand All @@ -491,6 +509,7 @@ void HandlePointerMotion(MouseDevice mouse, PointerEvent e)
Vector2 delta = new Vector2((float)e.X, (float)e.Y);
if (mouse != null)
{
mouse.State.SetIsConnected(true);
mouse.State.Position += delta;
}

Expand All @@ -504,6 +523,7 @@ void HandlePointerMotionAbsolute(MouseDevice mouse, PointerEvent e)
{
if (mouse != null)
{
mouse.State.SetIsConnected(true);
mouse.State.Position = new Vector2(e.X, e.Y);
}

Expand All @@ -521,8 +541,12 @@ static int GetId(IntPtr device)
KeyboardDevice GetKeyboard(IntPtr device)
{
int id = GetId(device);
KeyboardDevice keyboard = Keyboards.FromHardwareId(id);
if (keyboard == null)
KeyboardDevice keyboard = KeyboardCandidates.FromHardwareId(id);
if (keyboard != null)
{
Keyboards.Add(id, keyboard);
}
else
{
Debug.Print("[Input] Keyboard {0} does not exist in device list.", id);
}
Expand All @@ -532,8 +556,12 @@ KeyboardDevice GetKeyboard(IntPtr device)
MouseDevice GetMouse(IntPtr device)
{
int id = GetId(device);
MouseDevice mouse = Mice.FromHardwareId(id);
if (mouse == null)
MouseDevice mouse = MouseCandidates.FromHardwareId(id);
if (mouse != null)
{
Mice.Add(id, mouse);
}
else
{
Debug.Print("[Input] Mouse {0} does not exist in device list.", id);
}
Expand Down

0 comments on commit 00b5174

Please sign in to comment.