Browse Source

Merge pull request #9069 from workgroupengineering/features/Linux/Framebuffer/LibInput/Pointer

feat: Add support at Pointer Wheel
pull/9395/head
Max Katz 3 years ago
committed by GitHub
parent
commit
9a9ca64b43
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 110
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Pointer.cs
  2. 59
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs
  3. 53
      src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs

110
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.Pointer.cs

@ -0,0 +1,110 @@
using System;
using Avalonia.Input;
using Avalonia.Input.Raw;
using Avalonia.Logging;
using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
namespace Avalonia.LinuxFramebuffer.Input.LibInput;
public partial class LibInputBackend
{
private MouseDevice _mouse = new MouseDevice();
private Point _mousePosition;
private const string Pointer = LibInput + "/" + nameof(Pointer);
private void HandlePointer(IntPtr ev, LibInputEventType type)
{
var modifiers = RawInputModifiers.None; //TODO: support input modifiers
var pev = libinput_event_get_pointer_event(ev);
var info = _screen.ScaledSize;
var ts = libinput_event_pointer_get_time_usec(pev) / 1000;
switch (type)
{
case LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
_mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width),
libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height));
ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition,
modifiers));
break;
case LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON:
{
var button = (EvKey)libinput_event_pointer_get_button(pev);
var buttonState = libinput_event_pointer_get_button_state(pev);
RawPointerEventArgs evnt = button switch
{
EvKey.BTN_LEFT when buttonState == 1
=> new(_mouse, ts, _inputRoot, RawPointerEventType.LeftButtonDown, _mousePosition, modifiers),
EvKey.BTN_LEFT when buttonState == 0
=> new(_mouse, ts, _inputRoot, RawPointerEventType.LeftButtonUp, _mousePosition, modifiers),
EvKey.BTN_RIGHT when buttonState == 1
=> new(_mouse, ts, _inputRoot, RawPointerEventType.RightButtonUp, _mousePosition, modifiers),
EvKey.BTN_RIGHT when buttonState == 2
=> new(_mouse, ts, _inputRoot, RawPointerEventType.RightButtonDown, _mousePosition, modifiers),
EvKey.BTN_MIDDLE when buttonState == 1
=> new(_mouse, ts, _inputRoot, RawPointerEventType.MiddleButtonDown, _mousePosition, modifiers),
EvKey.BTN_MIDDLE when buttonState == 2
=> new(_mouse, ts, _inputRoot, RawPointerEventType.MiddleButtonUp, _mousePosition, modifiers),
_ => default,
};
if (evnt is not null)
{
ScheduleInput(evnt);
}
else
{
Logger.TryGet(LogEventLevel.Warning, Pointer)
?.Log(this, $"The button {button} is not associated");
}
}
break;
// Backward compatibility with low-res wheel
case LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS:
{
var sourceAxis = libinput_event_pointer_get_axis_source(pev);
switch (sourceAxis)
{
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
{
var value = libinput_event_pointer_get_axis_value_discrete(pev,
LibInputPointerAxis.LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
ScheduleInput(new RawMouseWheelEventArgs(_mouse
, ts
, _inputRoot
, _mousePosition
, new Vector(0, -value)
, modifiers));
}
break;
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
case LibInputPointerAxisSource.LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT:
default:
Logger.TryGet(LogEventLevel.Debug, Pointer)
?.Log(this, $"The pointer axis {sourceAxis} is not managed.");
break;
}
}
break;
// Hi-Res wheel
case LibInputEventType.LIBINPUT_EVENT_POINTER_SCROLL_WHEEL:
{
var value = new Vector(0,
-libinput_event_pointer_get_scroll_value_v120(pev,
LibInputPointerAxis.LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) / 120);
ScheduleInput(new RawMouseWheelEventArgs(_mouse
, ts
, _inputRoot
, _mousePosition
, value
, modifiers));
}
break;
default:
Logger.TryGet(LogEventLevel.Warning, Pointer)
?.Log(this, $"The pointer event {type} is not mapped.");
break;
}
}
}

59
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputBackend.cs

@ -4,18 +4,16 @@ using System.IO;
using System.Threading;
using Avalonia.Input;
using Avalonia.Input.Raw;
using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
using static Avalonia.LinuxFramebuffer.Input.LibInput.LibInputNativeUnsafeMethods;
namespace Avalonia.LinuxFramebuffer.Input.LibInput
{
public class LibInputBackend : IInputBackend
public partial class LibInputBackend : IInputBackend
{
private IScreenInfoProvider _screen;
private IInputRoot _inputRoot;
private readonly Queue<Action> _inputThreadActions = new Queue<Action>();
private TouchDevice _touch = new TouchDevice();
private MouseDevice _mouse = new MouseDevice();
private Point _mousePosition;
private const string LibInput = nameof(Avalonia.LinuxFramebuffer) + "/" + nameof(Avalonia.LinuxFramebuffer.Input) + "/" + nameof(LibInput);
private readonly RawEventGroupingThreadingHelper _inputQueue;
private Action<RawInputEventArgs> _onInput;
private Dictionary<int, Point> _pointers = new Dictionary<int, Point>();
@ -24,13 +22,13 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
{
var ctx = libinput_path_create_context();
_inputQueue = new(e => _onInput?.Invoke(e));
new Thread(()=>InputThread(ctx)).Start();
new Thread(() => InputThread(ctx)).Start();
}
private unsafe void InputThread(IntPtr ctx)
{
var fd = libinput_get_fd(ctx);
var timeval = stackalloc IntPtr[2];
@ -38,12 +36,11 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
libinput_path_add_device(ctx, f);
while (true)
{
IntPtr ev;
libinput_dispatch(ctx);
while ((ev = libinput_get_event(ctx)) != IntPtr.Zero)
{
var type = libinput_event_get_type(ev);
if (type >= LibInputEventType.LIBINPUT_EVENT_TOUCH_DOWN &&
type <= LibInputEventType.LIBINPUT_EVENT_TOUCH_CANCEL)
@ -52,12 +49,12 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
if (type >= LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION
&& type <= LibInputEventType.LIBINPUT_EVENT_POINTER_AXIS)
HandlePointer(ev, type);
libinput_event_destroy(ev);
libinput_dispatch(ctx);
}
pollfd pfd = new pollfd {fd = fd, events = 1};
pollfd pfd = new pollfd { fd = fd, events = 1 };
NativeUnsafeMethods.poll(&pfd, new IntPtr(1), 10);
}
}
@ -67,7 +64,7 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
private void HandleTouch(IntPtr ev, LibInputEventType type)
{
var tev = libinput_event_get_touch_event(ev);
if(tev == IntPtr.Zero)
if (tev == IntPtr.Zero)
return;
if (type < LibInputEventType.LIBINPUT_EVENT_TOUCH_FRAME)
{
@ -102,44 +99,6 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
}
}
private void HandlePointer(IntPtr ev, LibInputEventType type)
{
//TODO: support input modifiers
var pev = libinput_event_get_pointer_event(ev);
var info = _screen.ScaledSize;
var ts = libinput_event_pointer_get_time_usec(pev) / 1000;
if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE)
{
_mousePosition = new Point(libinput_event_pointer_get_absolute_x_transformed(pev, (int)info.Width),
libinput_event_pointer_get_absolute_y_transformed(pev, (int)info.Height));
ScheduleInput(new RawPointerEventArgs(_mouse, ts, _inputRoot, RawPointerEventType.Move, _mousePosition,
RawInputModifiers.None));
}
else if (type == LibInputEventType.LIBINPUT_EVENT_POINTER_BUTTON)
{
var button = (EvKey)libinput_event_pointer_get_button(pev);
var buttonState = libinput_event_pointer_get_button_state(pev);
var evnt = button == EvKey.BTN_LEFT ?
(buttonState == 1 ? RawPointerEventType.LeftButtonDown : RawPointerEventType.LeftButtonUp) :
button == EvKey.BTN_MIDDLE ?
(buttonState == 1 ? RawPointerEventType.MiddleButtonDown : RawPointerEventType.MiddleButtonUp) :
button == EvKey.BTN_RIGHT ?
(buttonState == 1 ?
RawPointerEventType.RightButtonDown :
RawPointerEventType.RightButtonUp) :
(RawPointerEventType)(-1);
if (evnt == (RawPointerEventType)(-1))
return;
ScheduleInput(
new RawPointerEventArgs(_mouse, ts, _inputRoot, evnt, _mousePosition, RawInputModifiers.None));
}
}
public void Initialize(IScreenInfoProvider screen, Action<RawInputEventArgs> onInput)
{
_screen = screen;

53
src/Linux/Avalonia.LinuxFramebuffer/Input/LibInput/LibInputNativeUnsafeMethods.cs

@ -77,6 +77,9 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
LIBINPUT_EVENT_POINTER_BUTTON,
LIBINPUT_EVENT_POINTER_AXIS,
LIBINPUT_EVENT_POINTER_SCROLL_WHEEL,
LIBINPUT_EVENT_POINTER_SCROLL_FINGER,
LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS,
LIBINPUT_EVENT_TOUCH_DOWN = 500,
LIBINPUT_EVENT_TOUCH_UP,
LIBINPUT_EVENT_TOUCH_MOTION,
@ -97,8 +100,38 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
LIBINPUT_EVENT_GESTURE_PINCH_END,
LIBINPUT_EVENT_SWITCH_TOGGLE = 900,
}
public enum LibInputPointerAxisSource
{
/**
* The event is caused by the rotation of a wheel.
**/
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL = 1,
/**
* The event is caused by the movement of one or more fingers on a device.
**/
LIBINPUT_POINTER_AXIS_SOURCE_FINGER,
/**
* The event is caused by the motion of some device.
**/
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS,
/**
* The event is caused by the tilting of a mouse wheel rather than
* its rotation. This method is commonly used on mice without
* separate horizontal scroll wheels.
* @deprecated This axis source is deprecated as of libinput 1.16.
* It was never used by any device before libinput 1.16. All wheel
* tilt devices use @ref LIBINPUT_POINTER_AXIS_SOURCE_WHEEL instead.
**/
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT,
};
public enum LibInputPointerAxis
{
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL = 0,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL = 1,
};
[DllImport(LibInput)]
public extern static void libinput_event_destroy(IntPtr ev);
@ -119,21 +152,29 @@ namespace Avalonia.LinuxFramebuffer.Input.LibInput
[DllImport(LibInput)]
public extern static IntPtr libinput_event_get_pointer_event(IntPtr ev);
[DllImport(LibInput)]
public extern static ulong libinput_event_pointer_get_time_usec(IntPtr ev);
[DllImport(LibInput)]
public extern static double libinput_event_pointer_get_absolute_x_transformed(IntPtr ev, int width);
[DllImport(LibInput)]
public extern static double libinput_event_pointer_get_absolute_y_transformed(IntPtr ev, int height);
[DllImport(LibInput)]
public extern static int libinput_event_pointer_get_button(IntPtr ev);
[DllImport(LibInput)]
public extern static int libinput_event_pointer_get_button_state(IntPtr ev);
[DllImport(LibInput)]
public extern static LibInputPointerAxisSource libinput_event_pointer_get_axis_source(IntPtr ev);
[DllImport((LibInput))]
public extern static double libinput_event_pointer_get_axis_value_discrete(IntPtr ev, LibInputPointerAxis axis);
[DllImport(LibInput)]
public extern static double libinput_event_pointer_get_scroll_value_v120(IntPtr ev, LibInputPointerAxis axis);
}
}

Loading…
Cancel
Save