The mouse cursor is now confined to the display bounds.
#endregion
using System;
+using System.Diagnostics;
using OpenTK.Input;
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;
}
}
}
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);
#endregion
using System;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.Drawing;
using System.Runtime.InteropServices;
using System.Threading;
using OpenTK.Input;
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)
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);
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.
{
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)
using System.Drawing;
using System.Runtime.InteropServices;
using OpenTK.Graphics;
+using OpenTK.Input;
using OpenTK.Platform.Egl;
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,
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();
}
{
get
{
- return true;
+ return is_focused;
}
}