Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ paths, fuzzy matching, the LSP client, the profiler.
A lifted finger hovers nothing: dvui puts the frame's `.position` event off every window, so a
hover look needs no touch check of its own. The native backend gives only fingers on the screen
touch buttons (`backend/src/touch_slots.zig`); a trackpad's fingers move the mouse.
The web backend does the same: a stylus touch (an Apple Pencil) is the mouse (`web/web.js`).
- **A cursor that must win asks with a priority.** `dvui.cursorSet` keeps the first asked in a
frame; `dvui.cursorSetPriority` the highest. Splits and a float's corner ask at `.resize`, a
carried view at `.drag`, so a hover cursor (a tab's hand) never takes their arrow. The cursor
Expand Down
48 changes: 41 additions & 7 deletions web/web.js
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,29 @@ export class Dvui {
}
}

/**
* An Apple Pencil on iPad Safari arrives as a TouchEvent whose touch has `touchType`
* "stylus" (a finger's is "direct"). It is a pen, not a finger, so it goes in as the mouse:
* motion to where it is, then the left button pressed or released. dvui then counts it as
* `.mouse` (`dvui.pointerKind()`), so what it last touched stays hovered after a lift and a
* canvas treats it as a pointer, not a pan; native excludes SDL's pen touches the same way.
* The touch handlers' `preventDefault` stops the browser's own mouse events following it.
*
* @param {TouchEvent} ev
* @param {Touch} touch
* @param {1 | 2 | 3} which 1 motion only, 2 press, 3 release (`add_event`'s mouse codes)
*/
stylusEvent(ev, touch, which) {
const rect = this.gl.canvas.getBoundingClientRect();
const x = (touch.clientX - rect.left) / (rect.right - rect.left) *
this.gl.drawingBufferWidth;
const y = (touch.clientY - rect.top) / (rect.bottom - rect.top) *
this.gl.drawingBufferHeight;
const mods = this.modCode(ev);
this.instance.exports.add_event(1, mods, 0, x, y);
if (which !== 1) this.instance.exports.add_event(which, 0, mods, 0, 0);
}

touchIndex(pointerId) {
let idx = this.touches.findIndex((e) => e[0] === pointerId);
if (idx < 0) {
Expand Down Expand Up @@ -1706,6 +1729,10 @@ export class Dvui {
let rect = this.gl.canvas.getBoundingClientRect();
for (let i = 0; i < ev.changedTouches.length; i++) {
let touch = ev.changedTouches[i];
if (touch.touchType === "stylus") {
this.stylusEvent(ev, touch, 2);
continue;
}
let x = (touch.clientX - rect.left) /
(rect.right - rect.left);
let y = (touch.clientY - rect.top) /
Expand All @@ -1721,12 +1748,16 @@ export class Dvui {
}
this.requestRender();
});
this.gl.canvas.addEventListener("touchend", (ev) => {
const touchEnd = (ev) => {
if (this.stopped) return;
ev.preventDefault();
let rect = this.gl.canvas.getBoundingClientRect();
for (let i = 0; i < ev.changedTouches.length; i++) {
let touch = ev.changedTouches[i];
if (touch.touchType === "stylus") {
this.stylusEvent(ev, touch, 3);
continue;
}
let x = (touch.clientX - rect.left) /
(rect.right - rect.left);
let y = (touch.clientY - rect.top) /
Expand All @@ -1746,13 +1777,21 @@ export class Dvui {
// https://stackoverflow.com/a/6837575
this.oskCheck();
this.requestRender();
});
};
this.gl.canvas.addEventListener("touchend", touchEnd);
// A cancelled touch (the system took it: a gesture, an alert) ends like a lifted one,
// or its button, or the pencil's mouse button, would stay held.
this.gl.canvas.addEventListener("touchcancel", touchEnd);
this.gl.canvas.addEventListener("touchmove", (ev) => {
if (this.stopped) return;
ev.preventDefault();
let rect = this.gl.canvas.getBoundingClientRect();
for (let i = 0; i < ev.changedTouches.length; i++) {
let touch = ev.changedTouches[i];
if (touch.touchType === "stylus") {
this.stylusEvent(ev, touch, 1);
continue;
}
let x = (touch.clientX - rect.left) /
(rect.right - rect.left);
let y = (touch.clientY - rect.top) /
Expand All @@ -1768,11 +1807,6 @@ export class Dvui {
}
this.requestRender();
});
//canvas.addEventListener("touchcancel", (ev) => {
// console.log(ev);
// this.requestRender();
//});

// start the first update
this.requestRender();
}
Expand Down
Loading