Skip to content

Commit

Permalink
feat(pointers): [WASM] Add support for the mouse wheel event
Browse files Browse the repository at this point in the history
  • Loading branch information
dr1rrb committed Apr 16, 2020
1 parent 69943cf commit 57ccc39
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/Uno.UI.Wasm/WasmScripts/Uno.UI.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,8 @@ declare namespace Uno.UI {
* @param evt
*/
private pointerEventExtractor;
private _wheelLineSize;
private readonly WheelLineSize;
/**
* keyboard event extractor to be used with registerEventOnView
* @param evt
Expand Down
52 changes: 50 additions & 2 deletions src/Uno.UI.Wasm/WasmScripts/Uno.UI.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ var Uno;
this.loadingElementId = loadingElementId;
this.allActiveElementsById = {};
this.uiElementRegistrations = {};
this._wheelLineSize = undefined;
this.initDom();
}
/**
Expand Down Expand Up @@ -1026,7 +1027,53 @@ var Uno;
}
src = src.parentElement;
}
return `${evt.pointerId};${evt.clientX};${evt.clientY};${(evt.ctrlKey ? "1" : "0")};${(evt.shiftKey ? "1" : "0")};${evt.buttons};${evt.button};${evt.pointerType};${srcHandle};${evt.timeStamp};${evt.pressure}`;
let pointerId, pointerType, pressure;
let wheelDeltaX, wheelDeltaY;
if (evt instanceof WheelEvent) {
pointerId = evt.mozInputSource ? 0 : 1; // Try to match the mouse pointer ID 0 for FF, 1 for others
pointerType = "mouse";
pressure = 0.5; // like WinUI
wheelDeltaX = evt.deltaX;
wheelDeltaY = evt.deltaY;
switch (evt.deltaMode) {
case WheelEvent.DOM_DELTA_LINE: // Actually this is supported only by FF
wheelDeltaX *= this.WheelLineSize;
wheelDeltaY *= this.WheelLineSize;
break;
case WheelEvent.DOM_DELTA_PAGE:
wheelDeltaX *= document.documentElement.clientWidth;
wheelDeltaY *= document.documentElement.clientHeight;
break;
}
}
else {
pointerId = evt.pointerId;
pointerType = evt.pointerType;
pressure = evt.pressure;
wheelDeltaX = 0;
wheelDeltaY = 0;
}
return `${pointerId};${evt.clientX};${evt.clientY};${(evt.ctrlKey ? "1" : "0")};${(evt.shiftKey ? "1" : "0")};${evt.buttons};${evt.button};${pointerType};${srcHandle};${evt.timeStamp};${pressure};${wheelDeltaX};${wheelDeltaY}`;
}
get WheelLineSize() {
// In web browsers, scroll might happen by pixels, line or page.
// But WinUI works only with pixels, so we have to convert it before send the value to the managed code.
// The issue is that there is no easy way get the "size of a line", instead we have to determine the CSS "line-height"
// defined in the browser settings.
// https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
if (this._wheelLineSize == undefined) {
const el = document.createElement('div');
el.style.fontSize = 'initial';
el.style.display = 'none';
document.body.appendChild(el);
const fontSize = window.getComputedStyle(el).fontSize;
document.body.removeChild(el);
this._wheelLineSize = fontSize ? parseInt(fontSize) : 16; /* 16 = The current common default font size */
// Based on observations, even if the even reports 3 lines (the settings of windows),
// the browser will actually scroll of about 6 lines of text.
this._wheelLineSize *= 2.0;
}
return this._wheelLineSize;
}
/**
* keyboard event extractor to be used with registerEventOnView
Expand Down Expand Up @@ -1707,8 +1754,9 @@ var Uno;
}
})(UI = Uno.UI || (Uno.UI = {}));
})(Uno || (Uno = {}));
// Ensure the "Uno" namespace is availablle globally
// Ensure the "Uno" namespace is available globally
window.Uno = Uno;
window.Windows = Windows;
/* TSBindingsGenerator Generated code -- this code is regenerated on each build */
class StorageFolderMakePersistentParams {
static unmarshal(pData) {
Expand Down
56 changes: 54 additions & 2 deletions src/Uno.UI.Wasm/ts/WindowManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,7 @@ namespace Uno.UI {
* pointer event extractor to be used with registerEventOnView
* @param evt
*/
private pointerEventExtractor(evt: PointerEvent): string {
private pointerEventExtractor(evt: PointerEvent|WheelEvent): string {
if (!evt) {
return "";
}
Expand All @@ -954,7 +954,59 @@ namespace Uno.UI {
src = src.parentElement;
}

return `${evt.pointerId};${evt.clientX};${evt.clientY};${(evt.ctrlKey ? "1" : "0")};${(evt.shiftKey ? "1" : "0")};${evt.buttons};${evt.button};${evt.pointerType};${srcHandle};${evt.timeStamp};${evt.pressure}`;
let pointerId: number, pointerType: string, pressure: number;
let wheelDeltaX: number, wheelDeltaY: number;
if (evt instanceof WheelEvent) {
pointerId = (evt as any).mozInputSource ? 0 : 1; // Try to match the mouse pointer ID 0 for FF, 1 for others
pointerType = "mouse";
pressure = 0.5; // like WinUI
wheelDeltaX = evt.deltaX;
wheelDeltaY = evt.deltaY;

switch (evt.deltaMode) {
case WheelEvent.DOM_DELTA_LINE: // Actually this is supported only by FF
wheelDeltaX *= this.WheelLineSize;
wheelDeltaY *= this.WheelLineSize;
break;
case WheelEvent.DOM_DELTA_PAGE:
wheelDeltaX *= document.documentElement.clientWidth;
wheelDeltaY *= document.documentElement.clientHeight;
break;
}
} else {
pointerId = evt.pointerId;
pointerType = evt.pointerType;
pressure = evt.pressure;
wheelDeltaX = 0;
wheelDeltaY = 0;
}

return `${pointerId};${evt.clientX};${evt.clientY};${(evt.ctrlKey ? "1" : "0")};${(evt.shiftKey ? "1" : "0")};${evt.buttons};${evt.button};${pointerType};${srcHandle};${evt.timeStamp};${pressure};${wheelDeltaX};${wheelDeltaY}`;
}

private _wheelLineSize : number = undefined;
private get WheelLineSize(): number {
// In web browsers, scroll might happen by pixels, line or page.
// But WinUI works only with pixels, so we have to convert it before send the value to the managed code.
// The issue is that there is no easy way get the "size of a line", instead we have to determine the CSS "line-height"
// defined in the browser settings.
// https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line
if (this._wheelLineSize == undefined) {
const el = document.createElement('div');
el.style.fontSize = 'initial';
el.style.display = 'none';
document.body.appendChild(el);
const fontSize = window.getComputedStyle(el).fontSize;
document.body.removeChild(el);

this._wheelLineSize = fontSize ? parseInt(fontSize) : 16; /* 16 = The current common default font size */

// Based on observations, even if the even reports 3 lines (the settings of windows),
// the browser will actually scroll of about 6 lines of text.
this._wheelLineSize *= 2.0;
}

return this._wheelLineSize;
}

/**
Expand Down
11 changes: 11 additions & 0 deletions src/Uno.UI/UI/Xaml/Input/PointerRoutedEventArgs.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ partial class PointerRoutedEventArgs
private readonly WindowManagerInterop.HtmlPointerButtonsState _buttons;
private readonly WindowManagerInterop.HtmlPointerButtonUpdate _buttonUpdate;
private readonly double _pressure;
private readonly (bool isWheel, double deltaX, double deltaY) _wheel;

internal PointerRoutedEventArgs(
double timestamp,
Expand All @@ -27,6 +28,7 @@ internal PointerRoutedEventArgs(
WindowManagerInterop.HtmlPointerButtonUpdate buttonUpdate,
VirtualKeyModifiers keys,
double pressure,
(bool isWheel, double deltaX, double deltaY) wheel,
UIElement source,
bool canBubbleNatively)
: this()
Expand All @@ -36,6 +38,7 @@ internal PointerRoutedEventArgs(
_buttons = buttons;
_buttonUpdate = buttonUpdate;
_pressure = pressure;
_wheel = wheel;

FrameId = ToFrameId(timestamp);
Pointer = new Pointer(pointerId, pointerType, isInContact, isInRange: true);
Expand Down Expand Up @@ -90,6 +93,14 @@ private PointerPointProperties GetProperties()
break;
}

if (_wheel.isWheel)
{
props.IsHorizontalMouseWheel = _wheel.deltaX != 0;
props.MouseWheelDelta = (int)(props.IsHorizontalMouseWheel
? _wheel.deltaX
: _wheel.deltaY);
}

props.PointerUpdateKind = ToUpdateKind(_buttonUpdate, props);

return props;
Expand Down
2 changes: 2 additions & 0 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,8 @@ private bool SetOver(PointerRoutedEventArgs args, bool isOver, bool muteEvent =
/// </remarks>
internal bool IsPressed(Pointer pointer) => _pressedPointers.Contains(pointer.PointerId);

private bool IsPressed(uint pointerId) => _pressedPointers.Contains(pointerId);

private bool SetPressed(PointerRoutedEventArgs args, bool isPressed, bool muteEvent = false)
{
var wasPressed = IsPressed(args.Pointer);
Expand Down
13 changes: 10 additions & 3 deletions src/Uno.UI/UI/Xaml/UIElement.Pointers.wasm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public partial class UIElement : DependencyObject
// Ref:
// https://www.w3.org/TR/pointerevents/
// https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent

private static readonly Dictionary<RoutedEvent, (string domEventName, EventArgsParser argsParser, RoutedEventHandlerWithHandled handler)> _pointerHandlers
= new Dictionary<RoutedEvent, (string, EventArgsParser, RoutedEventHandlerWithHandled)>
Expand All @@ -33,6 +34,8 @@ public partial class UIElement : DependencyObject

{PointerMovedEvent, ("pointermove", PayloadToMovedPointerArgs, (snd, args) => ((UIElement)snd).OnNativePointerMove((PointerRoutedEventArgs)args))},
{PointerCanceledEvent, ("pointercancel", PayloadToCancelledPointerArgs, (snd, args) => ((UIElement)snd).OnNativePointerCancel((PointerRoutedEventArgs)args, isSwallowedBySystem: true))}, //https://www.w3.org/TR/pointerevents/#the-pointercancel-event

{ PointerWheelChangedEvent, ("wheel", PayloadToPointerWheelArgs, (snd, args) => false) }
};

partial void OnGestureRecognizerInitialized(GestureRecognizer recognizer)
Expand Down Expand Up @@ -105,11 +108,12 @@ private void AddPointerHandlerCore(RoutedEvent routedEvent)
private static PointerRoutedEventArgs PayloadToReleasedPointerArgs(object snd, string payload) => PayloadToPointerArgs(snd, payload, isInContact: true);
private static PointerRoutedEventArgs PayloadToExitedPointerArgs(object snd, string payload) => PayloadToPointerArgs(snd, payload, isInContact: false, canBubble: false);
private static PointerRoutedEventArgs PayloadToCancelledPointerArgs(object snd, string payload) => PayloadToPointerArgs(snd, payload, isInContact: false);
private static PointerRoutedEventArgs PayloadToPointerWheelArgs(object snd, string payload) => PayloadToPointerArgs(snd, payload, isInContact: null /* maybe */, isWheel: true);

private static PointerRoutedEventArgs PayloadToPointerArgs(object snd, string payload, bool isInContact, bool canBubble = true)
private static PointerRoutedEventArgs PayloadToPointerArgs(object snd, string payload, bool? isInContact, bool isWheel = false, bool canBubble = true)
{
var parts = payload?.Split(';');
if (parts?.Length != 11)
if (parts?.Length != 13)
{
return null;
}
Expand All @@ -125,6 +129,8 @@ private static PointerRoutedEventArgs PayloadToPointerArgs(object snd, string pa
var srcHandle = int.Parse(parts[8], CultureInfo.InvariantCulture);
var timestamp = double.Parse(parts[9], CultureInfo.InvariantCulture);
var pressure = double.Parse(parts[10], CultureInfo.InvariantCulture);
var wheelDeltaX = double.Parse(parts[11], CultureInfo.InvariantCulture);
var wheelDeltaY = double.Parse(parts[12], CultureInfo.InvariantCulture);

var src = GetElementFromHandle(srcHandle) ?? (UIElement)snd;
var position = new Point(x, y);
Expand All @@ -138,11 +144,12 @@ private static PointerRoutedEventArgs PayloadToPointerArgs(object snd, string pa
pointerId,
pointerType,
position,
isInContact,
isInContact ?? ((UIElement)snd).IsPressed(pointerId),
(WindowManagerInterop.HtmlPointerButtonsState)buttons,
(WindowManagerInterop.HtmlPointerButtonUpdate)buttonUpdate,
keyModifiers,
pressure,
(isWheel, wheelDeltaX, wheelDeltaY),
src,
canBubble);
}
Expand Down
3 changes: 1 addition & 2 deletions src/Uno.UWP/UI/Input/PointerPointProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ internal PointerPointProperties()
public float YTilt { get; internal set; } = 0f;
#endif

[global::Uno.NotImplemented]
public int MouseWheelDelta => 0;
public int MouseWheelDelta { get; internal set; }

/// <inheritdoc />
public override string ToString()
Expand Down

0 comments on commit 57ccc39

Please sign in to comment.