mirror of
https://github.com/Ryujinx/Opentk.git
synced 2025-03-27 05:35:13 +00:00
[Linux] Implemented INativeWindow keyboard/mouse events
The mouse cursor is now confined to the display bounds.
This commit is contained in:
parent
e61b39a1a1
commit
3881992bf7
|
@ -28,6 +28,7 @@
|
|||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace OpenTK.Platform.Linux
|
||||
|
@ -359,10 +360,9 @@ namespace OpenTK.Platform.Linux
|
|||
return MouseButton.Button8;
|
||||
case EvdevButton.BTN8:
|
||||
return MouseButton.Button9;
|
||||
case EvdevButton.BTN9:
|
||||
return MouseButton.LastButton;
|
||||
default:
|
||||
return MouseButton.LastButton;
|
||||
Debug.Print("[Input] Unknown EvdevButton {0}", button);
|
||||
return MouseButton.Left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -258,9 +258,8 @@ namespace OpenTK.Platform.Linux
|
|||
public Fixed24 DeltaY { get { return GetDY(@event); } }
|
||||
public Fixed24 X { get { return GetAbsX(@event); } }
|
||||
public Fixed24 Y { get { return GetAbsY(@event); } }
|
||||
// Are the following useful?
|
||||
//public Fixed24 TransformedX(int width) { return GetAbsXTransformed(@event, width); }
|
||||
//public Fixed24 TransformedY(int height) { return GetAbsXTransformed(@event, height); }
|
||||
public Fixed24 TransformedX(int width) { return GetAbsXTransformed(@event, width); }
|
||||
public Fixed24 TransformedY(int height) { return GetAbsYTransformed(@event, height); }
|
||||
|
||||
[DllImport(LibInput.lib, EntryPoint = "libinput_event_pointer_get_time", CallingConvention = CallingConvention.Cdecl)]
|
||||
static extern uint GetTime(IntPtr @event);
|
||||
|
|
|
@ -28,7 +28,9 @@
|
|||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using OpenTK.Input;
|
||||
|
@ -108,6 +110,9 @@ namespace OpenTK.Platform.Linux
|
|||
DeviceCollection<KeyboardDevice> Keyboards = new DeviceCollection<KeyboardDevice>();
|
||||
DeviceCollection<MouseDevice> Mice = new DeviceCollection<MouseDevice>();
|
||||
|
||||
// Todo: do we need to maintain the geometry of each display separately?
|
||||
Rectangle bounds;
|
||||
|
||||
// Global mouse cursor state
|
||||
Vector2 CursorPosition = Vector2.Zero;
|
||||
// Global mouse cursor offset (used for emulating SetPosition)
|
||||
|
@ -210,6 +215,12 @@ namespace OpenTK.Platform.Linux
|
|||
ret < 0 && !(error == ErrorNumber.Again || error == ErrorNumber.Interrupted) ||
|
||||
(poll_fd.revents & (PollFlags.Hup | PollFlags.Error | PollFlags.Invalid)) != 0;
|
||||
|
||||
// We need to query the desktop bounds in order to position the mouse cursor correctly.
|
||||
// This value will be used for the current bunch of input events. If a monitor changes
|
||||
// resolution in the meantime, we might be slightly off in our calculations - this error
|
||||
// will be corrected when the next bunch of input events arrives.
|
||||
UpdateDisplayBounds();
|
||||
|
||||
if (ret > 0 && (poll_fd.revents & (PollFlags.In | PollFlags.Pri)) != 0)
|
||||
{
|
||||
ProcessEvents(input_context);
|
||||
|
@ -225,6 +236,19 @@ namespace OpenTK.Platform.Linux
|
|||
Debug.Print("[Input] Exited input loop.", poll_fd.fd, poll_fd.events);
|
||||
}
|
||||
|
||||
void UpdateDisplayBounds()
|
||||
{
|
||||
bounds = Rectangle.Empty;
|
||||
for (DisplayIndex i = DisplayIndex.First; i < DisplayIndex.Sixth; i++)
|
||||
{
|
||||
DisplayDevice display = DisplayDevice.GetDisplay(i);
|
||||
if (display != null)
|
||||
{
|
||||
bounds = Rectangle.Union(bounds, display.Bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Setup()
|
||||
{
|
||||
// Todo: add static path fallback when udev is not installed.
|
||||
|
@ -425,16 +449,22 @@ namespace OpenTK.Platform.Linux
|
|||
{
|
||||
mouse.State.Position += delta;
|
||||
}
|
||||
|
||||
CursorPosition = new Vector2(
|
||||
MathHelper.Clamp(CursorPosition.X + delta.X, bounds.Left, bounds.Right),
|
||||
MathHelper.Clamp(CursorPosition.Y + delta.Y, bounds.Top, bounds.Bottom));
|
||||
}
|
||||
|
||||
void HandlePointerMotionAbsolute(MouseDevice mouse, PointerEvent e)
|
||||
{
|
||||
Vector2 position = new Vector2(e.X, e.Y);
|
||||
if (mouse != null)
|
||||
{
|
||||
mouse.State.Position = position;
|
||||
mouse.State.Position = new Vector2(e.X, e.Y);
|
||||
}
|
||||
CursorPosition = position; // update global cursor position
|
||||
|
||||
CursorPosition = new Vector2(
|
||||
e.TransformedX(bounds.Width),
|
||||
e.TransformedY(bounds.Height));
|
||||
}
|
||||
|
||||
static int GetId(IntPtr device)
|
||||
|
|
|
@ -32,6 +32,7 @@ using System.Diagnostics;
|
|||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using OpenTK.Platform.Egl;
|
||||
|
||||
namespace OpenTK.Platform.Linux
|
||||
|
@ -43,9 +44,13 @@ namespace OpenTK.Platform.Linux
|
|||
LinuxWindowInfo window;
|
||||
string title;
|
||||
Icon icon;
|
||||
bool exists;
|
||||
Rectangle bounds;
|
||||
Size client_size;
|
||||
bool exists;
|
||||
bool is_focused;
|
||||
|
||||
KeyboardState previous_keyboard;
|
||||
MouseState previous_mouse;
|
||||
|
||||
public LinuxNativeWindow(IntPtr display, IntPtr gbm, int fd,
|
||||
int x, int y, int width, int height, string title,
|
||||
|
@ -147,10 +152,83 @@ namespace OpenTK.Platform.Linux
|
|||
return SurfaceFormat.RGBA8888;
|
||||
}
|
||||
|
||||
KeyboardState ProcessKeyboard(KeyboardState keyboard)
|
||||
{
|
||||
for (Key i = 0; i < Key.LastKey; i++)
|
||||
{
|
||||
if (keyboard[i])
|
||||
{
|
||||
OnKeyDown(i, previous_keyboard[i]);
|
||||
// Todo: implement libxkb-common binding for text input
|
||||
}
|
||||
|
||||
if (!keyboard[i] && previous_keyboard[i])
|
||||
{
|
||||
OnKeyUp(i);
|
||||
}
|
||||
}
|
||||
return keyboard;
|
||||
}
|
||||
|
||||
MouseState ProcessMouse(MouseState mouse)
|
||||
{
|
||||
for (MouseButton i = 0; i < MouseButton.LastButton; i++)
|
||||
{
|
||||
if (mouse[i] && !previous_mouse[i])
|
||||
{
|
||||
OnMouseDown(i);
|
||||
}
|
||||
|
||||
if (!mouse[i] && previous_mouse[i])
|
||||
{
|
||||
OnMouseUp(i);
|
||||
}
|
||||
|
||||
if (mouse.Position != previous_mouse.Position)
|
||||
{
|
||||
OnMouseMove(mouse.X, mouse.Y);
|
||||
}
|
||||
|
||||
if (mouse.Scroll != previous_mouse.Scroll)
|
||||
{
|
||||
OnMouseWheel(mouse.Scroll.X, mouse.Scroll.Y);
|
||||
}
|
||||
|
||||
// Note: focus follows mouse. Literally.
|
||||
bool cursor_in = Bounds.Contains(new Point(mouse.X, mouse.Y));
|
||||
if (!cursor_in && Focused)
|
||||
{
|
||||
OnMouseLeave(EventArgs.Empty);
|
||||
SetFocus(false);
|
||||
}
|
||||
else if (cursor_in && !Focused)
|
||||
{
|
||||
OnMouseEnter(EventArgs.Empty);
|
||||
SetFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
return mouse;
|
||||
}
|
||||
|
||||
void SetFocus(bool focus)
|
||||
{
|
||||
if (is_focused != focus)
|
||||
{
|
||||
is_focused = focus;
|
||||
OnFocusedChanged(EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
#region INativeWindow Members
|
||||
|
||||
public override void ProcessEvents()
|
||||
{
|
||||
// Note: there is no event-based keyboard/mouse input available.
|
||||
// We will fake that by polling OpenTK.Input.
|
||||
previous_keyboard = ProcessKeyboard(Keyboard.GetState());
|
||||
previous_mouse = ProcessMouse(Mouse.GetCursorState());
|
||||
|
||||
base.ProcessEvents();
|
||||
}
|
||||
|
||||
|
@ -216,7 +294,7 @@ namespace OpenTK.Platform.Linux
|
|||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
return is_focused;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue