Skip to content

Instantly share code, notes, and snippets.

@cxx
Last active July 14, 2024 13:47
Show Gist options
  • Save cxx/7f3cbd24745fffae34fbcdfdae0a76a1 to your computer and use it in GitHub Desktop.
Save cxx/7f3cbd24745fffae34fbcdfdae0a76a1 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Presto Gestures
// @namespace https://x.com/cxx
// @version 0.1.2
// @description Opera-like mouse gestures with middle mouse button instead of right
// @match *://*/*
// @grant GM_openInTab
// @grant window.close
// ==/UserScript==
(function() {
"use strict";
const BTN_LEFT_MASK = 1;
const BTN_RIGHT_MASK = 2;
const BTN_MIDDLE_MASK = 4;
const BTN_BACK_MASK = 8;
const BTN_FORWARD_MASK = 16;
let gestureButtons = BTN_MIDDLE_MASK;
let threshold = 50;
let gestures = [
{ gesture: "L", action: () => history.back() },
{ gesture: "R", action: () => history.forward() },
{ gesture: "UL", action: goToParentDirectory },
{ gesture: "UD", action: () => location.reload() },
{ gesture: "U", action: () => stop() },
{ gesture: "D", action: () => GM_openInTab("about:newtab", false) },
{ gesture: "DU", action: () => GM_openInTab(location.toString()) },
{ gesture: "DR", action: () => close() }
];
function goToParentDirectory() {
const url = new URL(location.toString());
url.pathname = url.pathname.replace(/[^/]*\/?$/, "");
url.search = "";
url.hash = "";
location.assign(url.toString());
}
function initGesture(x, y) {
start = { x: x, y: y };
strokes = "";
}
function updateGesture(x, y) {
let direction;
const dx = x - start.x;
const dy = y - start.y;
if (Math.abs(dx) > Math.abs(dy))
direction = (dx < 0) ? "L" : "R";
else
direction = (dy < 0) ? "U" : "D";
if (strokes.endsWith(direction))
start = { x: x, y: y };
else if (Math.abs(dx) > threshold || Math.abs(dy) > threshold) {
start = { x: x, y: y };
strokes += direction;
}
}
function endGesture() {
const found = gestures.find((item) => item.gesture == strokes);
if (found)
found.action();
start = null;
strokes = "";
}
let start = null;
let strokes = "";
addEventListener("mousedown", (event) => {
if (event.buttons == gestureButtons)
initGesture(event.clientX, event.clientY);
});
addEventListener("mousemove", (event) => {
if (start)
updateGesture(event.clientX, event.clientY);
});
addEventListener("mouseup", (event) => {
if (strokes.length > 0) {
event.preventDefault();
event.stopPropagation();
}
}, true);
addEventListener("auxclick", (event) => {
if (strokes.length > 0) {
event.preventDefault();
event.stopPropagation();
}
endGesture();
}, true);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment