Deliver the application's pointer input through the renderer's input port

The Cesium renderer now creates the input port and exposes it as
renderer.input. The input dispatcher becomes an adapter over the port:
one port listener per event type, fanned out to its subscribers with the
ownership check read once per event, keeping the legacy event shapes.

- Ctrl+wheel zoom is switched on through renderer.input.ctrlWheelZoom.
- A dispatcher made for a viewer with no port creates its own port with
  takeStock: false, which borrows the stock select and double-click
  follow only while they are suppressed.
- The stock actions see the press as it began: a click whose press
  started while select or follow was held off never runs them.
- A scene accepts one input port; cesiumInputOf(scene) returns it.
- Releasing one mouse button while another is held no longer gives the
  held button a click. Cesium still ends that press.
This commit is contained in:
Sameh Khamis committed 2026-11-05 19:22:43 -08:00
1 parent 1f2479d3ab
commit 24bc8fce7e
16 files changed
+427 -275

No files matched your search

+87 -13
View File
@@ -14,6 +14,9 @@
"src/data/scenePick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/input/sensorPick.js",
"src/data/infrastructureOverlayEntry.js",
"src/sources/infrastructureData.js",
@@ -884,7 +887,10 @@
"src/data/pickRegistry.js",
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -1143,7 +1149,10 @@
"src/data/pickRegistry.js",
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium", "vue", "pinia", "vue-i18n"]
},
@@ -1282,7 +1291,10 @@
"src/data/scenePick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium", "vue", "pinia", "vue-i18n"]
},
@@ -1376,6 +1388,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/render/cesium/internals.js"
],
"external": ["cesium"]
@@ -1448,7 +1463,10 @@
"src/input/sensorPick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -1533,7 +1551,10 @@
"src/data/pickRegistry.js",
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -1620,7 +1641,10 @@
"src/data/scenePick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -1665,7 +1689,10 @@
"src/data/scenePick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium", "satellite.js"]
},
@@ -1710,7 +1737,10 @@
"src/data/pickRegistry.js",
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -1768,7 +1798,10 @@
"src/data/scenePick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium", "@mapbox/vector-tile", "pbf"]
},
@@ -1916,6 +1949,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js"
],
"external": ["cesium"]
@@ -1986,7 +2022,10 @@
"src/data/pickRegistry.js",
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["hls.js", "cesium"]
},
@@ -2065,6 +2104,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js"
],
"external": ["cesium", "pbf", "@mapbox/vector-tile", "mapillary-js"]
@@ -2110,6 +2152,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js"
],
"external": ["cesium", "@mapbox/vector-tile", "pbf"]
@@ -2164,6 +2209,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/render/cesium/internals.js"
],
"external": ["cesium"]
@@ -2201,7 +2249,10 @@
"src/input/sensorPick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -3363,6 +3414,8 @@
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/input/router.js",
"src/queries/heights.js",
"src/render/cesium/internals.js",
"src/render/cesium/tileRequests.js"
@@ -3992,6 +4045,9 @@
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js",
"src/render/cesium/tileRequests.js",
"src/render/cesium/internals.js"
@@ -4104,6 +4160,9 @@
"modules": [
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/input/sensorPick.js",
"src/data/inputOwnership.js",
"src/data/pickRegistry.js",
@@ -4362,7 +4421,10 @@
"src/input/sensorPick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -4695,6 +4757,9 @@
"src/input/sensorPick.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js",
"src/render/cesium/internals.js"
],
@@ -4754,6 +4819,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js",
"src/render/cesium/internals.js"
],
@@ -4822,7 +4890,10 @@
"src/data/scenePick.js",
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js"
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js"
],
"external": ["cesium"]
},
@@ -4924,6 +4995,9 @@
"src/data/pickRegistry.js",
"src/input/dispatcher.js",
"src/render/cesium/cameraInput.js",
"src/render/cesium/input.js",
"src/render/cesium/ctrlWheelZoom.js",
"src/render/input/router.js",
"src/queries/heights.js"
],
"external": ["cesium"]
+22 -65
View File
@@ -263,39 +263,16 @@ try {
}),
);
// The viewer's OWN click actions, captured before the tool ever runs. Both
// must be absent while drawing and back — as the SAME functions — after.
await page.evaluate(() => {
const Cesium = window.__CESIUM__;
const stock = window.__godsEyeView.viewer.screenSpaceEventHandler;
window.__qaStock = {
click:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) || null,
double:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) ||
null,
// The viewer's own select and follow, which the input port runs: on before
// the tool runs, off while drawing, and on again after.
const stockActions = async () => {
const state = await drawState();
return {
clickOn: state.stockSingleClick,
doubleOn: state.stockDoubleClick,
};
});
const stockActions = () =>
page.evaluate(() => {
const Cesium = window.__CESIUM__;
const stock = window.__godsEyeView.viewer.screenSpaceEventHandler;
const live = {
click:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) || null,
double:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) ||
null,
};
return {
clickPresent: Boolean(live.click),
doublePresent: Boolean(live.double),
clickIsOriginal: live.click === window.__qaStock.click,
doubleIsOriginal: live.double === window.__qaStock.double,
hadClick: Boolean(window.__qaStock.click),
hadDouble: Boolean(window.__qaStock.double),
};
});
};
const beforeDraw = await stockActions();
// ── enable / disable cycles leave nothing behind ────────────────────────
const before = await drawState();
@@ -318,24 +295,21 @@ try {
`handler ${after.sceneHandler}, owner ${after.pointerOwner}, stock dblclick ${after.stockDoubleClick}`,
);
// ── the viewer's own click actions are borrowed, then given back ────────
// ── the viewer's own click actions are held off, then given back ───────
await page.click('#draw-toggle');
const duringDraw = await stockActions();
check(
"Cesium's own selecting click and tracking double-click are both borrowed while drawing",
duringDraw.clickPresent === false && duringDraw.doublePresent === false,
`click present ${duringDraw.clickPresent}, double present ${duringDraw.doublePresent} ` +
`(viewer had click ${duringDraw.hadClick}, double ${duringDraw.hadDouble})`,
"Cesium's own selecting click and tracking double-click are both off while drawing",
duringDraw.clickOn === false && duringDraw.doubleOn === false,
JSON.stringify({ beforeDraw, duringDraw }),
);
await page.click('#draw-toggle');
const afterDraw = await stockActions();
check(
'and both are restored as the SAME functions, not replacements',
afterDraw.clickPresent === duringDraw.hadClick &&
afterDraw.doublePresent === duringDraw.hadDouble &&
afterDraw.clickIsOriginal &&
afterDraw.doubleIsOriginal,
JSON.stringify(afterDraw),
'and both are back after',
afterDraw.clickOn === beforeDraw.clickOn &&
afterDraw.doubleOn === beforeDraw.doubleOn,
JSON.stringify({ beforeDraw, afterDraw }),
);
// ── a pin, finished with Enter ──────────────────────────────────────────
@@ -664,19 +638,6 @@ try {
document.getElementById('draw-toggle')?.getBoundingClientRect().width > 0,
{ timeout: 10_000 },
);
// The reload built a new page context: re-capture the viewer's own click
// actions so the identity comparisons below still mean something.
await page.evaluate(() => {
const Cesium = window.__CESIUM__;
const stock = window.__godsEyeView.viewer.screenSpaceEventHandler;
window.__qaStock = {
click:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) || null,
double:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) ||
null,
};
});
await page.evaluate((view) => {
const viewer = window.__godsEyeView.viewer;
viewer.camera.cancelFlight?.();
@@ -827,24 +788,20 @@ try {
const wasActive = tool.active;
await tool.destroy();
await new Promise((resolve) => setTimeout(resolve, 50));
const Cesium = window.__CESIUM__;
const viewer = window.__godsEyeView.viewer;
const stock = viewer.screenSpaceEventHandler;
let previews = 0;
for (let i = 0; i < viewer.dataSources.length; i += 1)
if (viewer.dataSources.get(i)?.name === 'gev-draw-preview') previews += 1;
const diagnostics = tool.diagnostics();
return {
wasActive,
diagnostics: tool.diagnostics(),
diagnostics,
previews,
dataSources: viewer.dataSources.length,
handleGone: window.__gevDrawTool === undefined,
clickRestored:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) ===
window.__qaStock.click,
doubleRestored:
stock.getInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK) ===
window.__qaStock.double,
// The viewer's own select and follow run again.
clickRestored: diagnostics.stockSingleClick,
doubleRestored: diagnostics.stockDoubleClick,
drawingClass: document.body.classList.contains('gev-drawing'),
};
});