提交 9c46f948 编写于 作者: A Alex Dima

Add a physical mouse wheel classifier with tests

上级 d73f9a6f
......@@ -31,6 +31,126 @@ export interface IOverviewRulerLayoutInfo {
insertBefore: HTMLElement;
}
class MouseWheelClassifierItem {
public timestamp: number;
public deltaX: number;
public deltaY: number;
public score: number;
constructor(timestamp: number, deltaX: number, deltaY: number) {
this.timestamp = timestamp;
this.deltaX = deltaX;
this.deltaY = deltaY;
this.score = 0;
}
}
export class MouseWheelClassifier {
private readonly _capacity: number;
private _memory: MouseWheelClassifierItem[];
private _front: number;
private _rear: number;
constructor() {
this._capacity = 5;
this._memory = [];
this._front = -1;
this._rear = -1;
}
// private isE
public isPhysicalMouseWheel(): boolean {
if (this._front === -1 && this._rear === -1) {
// no elements
return false;
}
// 0.5 * last + 0.25 * before last + 0.125 * before before last + ...
let remainingInfluence = 1;
let score = 0;
let iteration = 1;
let index = this._rear;
do {
const influence = (index === this._front ? remainingInfluence : Math.pow(2, -iteration));
remainingInfluence -= influence;
score += this._memory[index].score * influence;
if (index === this._front) {
break;
}
index = (this._capacity + index - 1) % this._capacity;
iteration++;
} while (true);
return (score <= 0.5);
}
public accept(timestamp: number, deltaX: number, deltaY: number): void {
const item = new MouseWheelClassifierItem(timestamp, deltaX, deltaY);
item.score = this._computeScore(item);
if (this._front === -1 && this._rear === -1) {
this._memory[0] = item;
this._front = 0;
this._rear = 0;
} else {
this._rear = (this._rear + 1) % this._capacity;
if (this._rear === this._front) {
// Drop oldest
this._front = (this._front + 1) % this._capacity;
}
this._memory[this._rear] = item;
// if ()
// if (this._front === this._rea)
}
// this._lastIndex = (this._lastIndex + 1) % this._capacity;
// if (this._firstIndex === this._lastIndex) {
// this._firstIndex = (this._firstIndex + 1) % this._capacity;
// }
// this._memory[this._lastIndex] = item;
}
/**
* A score between 0 and 1 for `item`.
* - a score towards 0 indicates that the source appears to be a physical mouse wheel
* - a score towards 1 indicates that the source appears to be a touchpad or magic mouse, etc.
*/
private _computeScore(item: MouseWheelClassifierItem): number {
if (Math.abs(item.deltaX) > 0 && Math.abs(item.deltaY) > 0) {
// both axes exercised => definitely not a physical mouse wheel
return 1;
}
let score: number = 0.5;
const prev = (this._front === -1 && this._rear === -1 ? null : this._memory[this._rear]);
if (prev) {
// const deltaT = item.timestamp - prev.timestamp;
// if (deltaT < 1000 / 30) {
// // sooner than X times per second => indicator that this is not a physical mouse wheel
// score += 0.25;
// }
// if (item.deltaX === prev.deltaX && item.deltaY === prev.deltaY) {
// // equal amplitude => indicator that this is a physical mouse wheel
// score -= 0.25;
// }
}
if (Math.abs(item.deltaX - Math.round(item.deltaX)) > 0 || Math.abs(item.deltaY - Math.round(item.deltaY)) > 0) {
// non-integer deltas => indicator that this is not a physical mouse wheel
score += 0.25;
}
return Math.min(Math.max(score, 0), 1);
}
}
export abstract class AbstractScrollableElement extends Widget {
private readonly _options: ScrollableElementResolvedOptions;
......@@ -216,6 +336,8 @@ export abstract class AbstractScrollableElement extends Widget {
private _onMouseWheel(e: StandardMouseWheelEvent): void {
const currentMouseWheelEventTime = Date.now();
// console.log(`${Date.now()}, ${e.deltaY}, ${e.deltaX}`);
if (e.deltaY || e.deltaX) {
let deltaY = e.deltaY * this._options.mouseWheelScrollSensitivity;
let deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { MouseWheelClassifier } from "vs/base/browser/ui/scrollbar/scrollableElement";
import * as assert from 'assert';
export type IMouseWheelEvent = [number, number, number];
suite('MouseWheelClassifier', () => {
test('Apple Magic Mouse', () => {
const testData: IMouseWheelEvent[] = [
[1503409622410, -0.025, 0],
[1503409622435, -0.175, 0],
[1503409622446, -0.225, 0],
[1503409622489, -0.65, 0],
[1503409622514, -1.225, 0],
[1503409622537, -1.025, 0],
[1503409622543, -0.55, 0],
[1503409622587, -0.75, 0],
[1503409622623, -1.45, 0],
[1503409622641, -1.325, 0],
[1503409622663, -0.6, 0],
[1503409622681, -1.125, 0],
[1503409622703, -0.5166666666666667, 0],
[1503409622721, -0.475, 0],
[1503409622822, -0.425, 0],
[1503409622871, -1.9916666666666667, 0],
[1503409622933, -0.7, 0],
[1503409622991, -0.725, 0],
[1503409623032, -0.45, 0],
[1503409623083, -0.25, 0],
[1503409623122, -0.4, 0],
[1503409623176, -0.2, 0],
[1503409623197, -0.225, 0],
[1503409623219, -0.05, 0],
[1503409623249, -0.1, 0],
[1503409623278, -0.1, 0],
[1503409623292, -0.025, 0],
[1503409623315, -0.025, 0],
[1503409623324, -0.05, 0],
[1503409623356, -0.025, 0],
[1503409623415, -0.025, 0],
[1503409623443, -0.05, 0],
[1503409623452, -0.025, 0],
];
const classifier = new MouseWheelClassifier();
for (let i = 0, len = testData.length; i < len; i++) {
const [timestamp, deltaY, deltaX] = testData[i];
classifier.accept(timestamp, deltaX, deltaY);
const actual = classifier.isPhysicalMouseWheel();
assert.equal(actual, false);
}
});
test('Apple Touch Pad', () => {
const testData: IMouseWheelEvent[] = [
[1503409780792, 0.025, 0],
[1503409780808, 0.175, -0.025],
[1503409780811, 0.35, -0.05],
[1503409780816, 0.55, -0.075],
[1503409780836, 0.825, -0.1],
[1503409780840, 0.725, -0.075],
[1503409780842, 1.5, -0.125],
[1503409780848, 1.1, -0.1],
[1503409780877, 2.05, -0.1],
[1503409780882, 3.9, 0],
[1503409780908, 3.825, 0],
[1503409780915, 3.65, 0],
[1503409780940, 3.45, 0],
[1503409780949, 3.25, 0],
[1503409780979, 3.075, 0],
[1503409780982, 2.9, 0],
[1503409781016, 2.75, 0],
[1503409781018, 2.625, 0],
[1503409781051, 2.5, 0],
[1503409781071, 2.4, 0],
[1503409781089, 2.3, 0],
[1503409781111, 2.175, 0],
[1503409781140, 3.975, 0],
[1503409781165, 1.8, 0],
[1503409781183, 3.3, 0],
[1503409781202, 1.475, 0],
[1503409781223, 1.375, 0],
[1503409781244, 1.275, 0],
[1503409781269, 2.25, 0],
[1503409781285, 1.025, 0],
[1503409781300, 0.925, 0],
[1503409781303, 0.875, 0],
[1503409781321, 0.8, 0],
[1503409781333, 0.725, 0],
[1503409781355, 0.65, 0],
[1503409781370, 0.6, 0],
[1503409781384, 0.55, 0],
[1503409781410, 0.5, 0],
[1503409781422, 0.475, 0],
[1503409781435, 0.425, 0],
[1503409781454, 0.4, 0],
[1503409781470, 0.35, 0],
[1503409781486, 0.325, 0],
[1503409781501, 0.3, 0],
[1503409781519, 0.275, 0],
[1503409781534, 0.25, 0],
[1503409781553, 0.225, 0],
[1503409781569, 0.2, 0],
[1503409781589, 0.2, 0],
[1503409781601, 0.175, 0],
[1503409781621, 0.15, 0],
[1503409781631, 0.15, 0],
[1503409781652, 0.125, 0],
[1503409781667, 0.125, 0],
[1503409781685, 0.125, 0],
[1503409781703, 0.1, 0],
[1503409781715, 0.1, 0],
[1503409781734, 0.1, 0],
[1503409781753, 0.075, 0],
[1503409781768, 0.075, 0],
[1503409781783, 0.075, 0],
[1503409781801, 0.075, 0],
[1503409781815, 0.05, 0],
[1503409781836, 0.05, 0],
[1503409781850, 0.05, 0],
[1503409781865, 0.05, 0],
[1503409781880, 0.05, 0],
[1503409781899, 0.025, 0],
[1503409781916, 0.025, 0],
[1503409781933, 0.025, 0],
[1503409781952, 0.025, 0],
[1503409781965, 0.025, 0],
[1503409781996, 0.025, 0],
[1503409782015, 0.025, 0],
[1503409782045, 0.025, 0],
];
const classifier = new MouseWheelClassifier();
for (let i = 0, len = testData.length; i < len; i++) {
const [timestamp, deltaY, deltaX] = testData[i];
classifier.accept(timestamp, deltaX, deltaY);
const actual = classifier.isPhysicalMouseWheel();
assert.equal(actual, false);
}
});
test('Apple Physical Mouse Wheel', () => {
const testData: IMouseWheelEvent[] = [
[1503409880776, -1, 0],
[1503409880791, -1, 0],
[1503409880810, -4, 0],
[1503409880820, -5, 0],
[1503409880848, -6, 0],
[1503409880876, -7, 0],
[1503409881319, -1, 0],
[1503409881387, -1, 0],
[1503409881407, -2, 0],
[1503409881443, -4, 0],
[1503409881444, -5, 0],
[1503409881470, -6, 0],
[1503409881496, -7, 0],
[1503409881812, -1, 0],
[1503409881829, -1, 0],
[1503409881850, -4, 0],
[1503409881871, -5, 0],
[1503409881896, -13, 0],
[1503409881914, -16, 0],
[1503409882551, -1, 0],
[1503409882589, -1, 0],
[1503409882625, -2, 0],
[1503409883035, -1, 0],
[1503409883098, -1, 0],
[1503409883143, -2, 0],
[1503409883217, -2, 0],
[1503409883270, -3, 0],
[1503409883388, -3, 0],
[1503409883531, -3, 0],
[1503409884095, -1, 0],
[1503409884122, -1, 0],
[1503409884160, -3, 0],
[1503409884208, -4, 0],
[1503409884292, -4, 0],
[1503409884447, -1, 0],
[1503409884788, -1, 0],
[1503409884835, -1, 0],
[1503409884898, -2, 0],
[1503409884965, -3, 0],
[1503409885085, -2, 0],
[1503409885552, -1, 0],
[1503409885619, -1, 0],
[1503409885670, -1, 0],
[1503409885733, -2, 0],
[1503409885784, -4, 0],
[1503409885916, -3, 0],
];
const classifier = new MouseWheelClassifier();
for (let i = 0, len = testData.length; i < len; i++) {
const [timestamp, deltaY, deltaX] = testData[i];
classifier.accept(timestamp, deltaX, deltaY);
const actual = classifier.isPhysicalMouseWheel();
assert.equal(actual, true);
}
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册