Skip to content

Commit acd36fb

Browse files
authored
Merge pull request #3239 from finetjul/1856-further-fix-key-events
fix(renderwindowinteractor): observe KeyPress events on RW container …
2 parents 74b3a79 + 1d9551c commit acd36fb

File tree

7 files changed

+132
-5
lines changed

7 files changed

+132
-5
lines changed

BREAKING_CHANGES.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
## From 32.x to 33
1+
## From 33.x to 34
22

33
- **vtkMapper**: many properties have moved to `vtkVolumeProperty`. The full list of changed methods is: `getAnisotropy`, `getComputeNormalFromOpacity`, `getFilterMode`, `getFilterModeAsString`, `getGlobalIlluminationReach`, `getIpScalarRange`, `getIpScalarRangeByReference`, `getLAOKernelRadius`, `getLAOKernelSize`, `getLocalAmbientOcclusion`, `getPreferSizeOverAccuracy`, `getVolumetricScatteringBlending`, `setAnisotropy`, `setAverageIPScalarRange`, `setComputeNormalFromOpacity`, `setFilterMode`, `setFilterModeToNormalized`, `setFilterModeToOff`, `setFilterModeToRaw`, `setGlobalIlluminationReach`, `setIpScalarRange`, `setIpScalarRangeFrom`, `setLAOKernelRadius`, `setLAOKernelSize`, `setLocalAmbientOcclusion`, `setPreferSizeOverAccuracy`, `setVolumetricScatteringBlending`.
4+
- **vtkRenderWindowInteractor**: KeyPress, KeyDown and KeyUp events are now observed on the container and no longer on the document. "tabIndex=0" is now automatically added on RWI containers to give focus on your render windows and catch key events. Check the KeyPressEvents example for usage.
45
- **vtkOpenGLTexture**: The public `create2D*` and `create3D*` methods used to have positional parameters. These methods now use named parameters via passing in an object record.
56

67
## From 31.x to 32
17.7 KB
Loading

Documentation/content/examples/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ This will allow you to see the some live code running in your browser. Just pick
326326
[![InteractorStyleTrackballCamera Example][InteractorStyleTrackballCamera]](./InteractorStyleTrackballCamera.html "InteractorStyleTrackballCamera")
327327
[![InteractorStyleUnicam Example][InteractorStyleUnicam]](./InteractorStyleUnicam.html "InteractorStyleUnicam")
328328
[![KeyboardCameraManipulator Example][KeyboardCameraManipulator]](./KeyboardCameraManipulator.html "KeyboardCameraManipulator")
329+
[![KeyPressEvents Example][KeyPressEvents]](./KeyPressEvents.html "KeyPressEvents")
329330
[![MouseRangeManipulator Example][MouseRangeManipulator]](./MouseRangeManipulator.html "MouseRangeManipulator")
330331
[![PiecewiseGaussianWidget Example][PiecewiseGaussianWidget]](./PiecewiseGaussianWidget.html "PiecewiseGaussianWidget")
331332
[![TimeStepBasedAnimationHandler Example][TimeStepBasedAnimationHandler]](./TimeStepBasedAnimationHandler.html "TimeStepBasedAnimationHandler")
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<style>
2+
#view-1:focus {
3+
outline: none; /* remove default */
4+
box-shadow: 0 0 20px 10px rgba(0, 255, 0, 0.6); /* red glow */
5+
z-index: 1; /* move forward (works only if position!=static) */
6+
position: relative;
7+
}
8+
#view-2:focus, #view-2:focus-visible {
9+
outline: none; /* remove default */
10+
}
11+
12+
input:focus {
13+
outline: none;
14+
border: 2px solid teal;
15+
box-shadow: 0 0 4px teal;
16+
}
17+
18+
/* Optional: Use focus-visible for keyboard-only styling */
19+
select:focus-visible {
20+
outline: 3px dashed orange;
21+
}
22+
</style>
23+
<h3>Click or press tab until you "focus" a render window, then type keys (e.g. r, w, s)</h3>
24+
<table>
25+
<tr>
26+
<td>Click with mouse then press space key:</td>
27+
<td>
28+
<input type="checkbox" id="checkboxTranslation" checked>
29+
</td>
30+
</tr>
31+
<tr>
32+
<td>Click then key up and down :</td>
33+
<td><input id='slider' type="range" min="0" max="255" step="1" value="255" style="width: 100px;"/></td>
34+
</tr>
35+
<tr>
36+
<td>Use key up and down to browse through:</td>
37+
<td>
38+
<select id="select">
39+
<option>One</option>
40+
<option>Two</option>
41+
<option selected="selected">Three</option>
42+
<option>Four</option>
43+
</select>
44+
</td>
45+
</tr>
46+
<tr>
47+
<td>
48+
<button id="buttonReset">Click and press space key</button>
49+
</td>
50+
</tr>
51+
</table>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import '@kitware/vtk.js/favicon';
2+
3+
// Load the rendering pieces we want to use (for both WebGL and WebGPU)
4+
import '@kitware/vtk.js/Rendering/Profiles/Geometry';
5+
6+
import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
7+
import vtkConeSource from '@kitware/vtk.js/Filters/Sources/ConeSource';
8+
import vtkGenericRenderWindow from '@kitware/vtk.js/Rendering/Misc/GenericRenderWindow';
9+
import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
10+
11+
import controlPanel from './controlPanel.html';
12+
13+
// ----------------------------------------------------------------------------
14+
// Standard rendering code setup
15+
// ----------------------------------------------------------------------------
16+
17+
const container = document.querySelector('body');
18+
const controlContainer = document.createElement('div');
19+
controlContainer.innerHTML = controlPanel;
20+
container.appendChild(controlContainer);
21+
22+
global.RWIs = [];
23+
24+
const logs = document.createElement('pre');
25+
26+
const cone = vtkConeSource.newInstance();
27+
28+
for (let i = 0; i < 3; ++i) {
29+
const elementParent = document.createElement('div');
30+
elementParent.style.width = '33%';
31+
elementParent.style.height = '300px';
32+
elementParent.style.display = 'inline-block';
33+
34+
const element = document.createElement('div');
35+
element.setAttribute('id', `view-${i}`);
36+
element.style.width = '100%';
37+
element.style.height = '100%';
38+
element.tabIndex = 0;
39+
elementParent.appendChild(element);
40+
41+
container.appendChild(elementParent);
42+
43+
const grw = vtkGenericRenderWindow.newInstance();
44+
45+
const color = [0, 0, 0];
46+
color[i % 3] = 1;
47+
grw.getRenderer().setBackground(color);
48+
49+
const mapper = vtkMapper.newInstance();
50+
mapper.setInputConnection(cone.getOutputPort());
51+
const actor = vtkActor.newInstance();
52+
actor.setMapper(mapper);
53+
grw.getRenderer().addActor(actor);
54+
grw.getRenderer().resetCamera();
55+
56+
grw.setContainer(element);
57+
grw.resize();
58+
59+
global.RWIs.push(grw.getInteractor());
60+
// Pick on mouse right click
61+
grw.getInteractor().onKeyDown((callData) => {
62+
logs.textContent += `Pressed ${callData.key} on RWI #${i}\n`;
63+
});
64+
}
65+
container.appendChild(logs);

Sources/Rendering/Core/RenderWindowInteractor/index.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,12 @@ export interface vtkRenderWindowInteractor extends vtkObject {
974974
/**
975975
* Add an HTMLElement as the new container for the interactor.
976976
* All events will be bound to this new container.
977+
*
978+
* container will gain the tabIndex=0 attribute to catch keyboard events.
979+
* container must have focus (manually via click or tab, or programmatically
980+
* via `.focus()`) to receive keypress events
981+
* Outline on focus can be customized with CSS :focus pseudo-class.
982+
*
977983
* Any old container will be removed along with its listeners.
978984
*/
979985
setContainer(container: Nullable<HTMLElement>): boolean;

Sources/Rendering/Core/RenderWindowInteractor/index.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,18 @@ function vtkRenderWindowInteractor(publicAPI, model) {
237237
});
238238
container.addEventListener('pointerup', publicAPI.handlePointerUp);
239239
container.addEventListener('pointercancel', publicAPI.handlePointerCancel);
240-
document.addEventListener('keypress', publicAPI.handleKeyPress);
241-
document.addEventListener('keydown', publicAPI.handleKeyDown);
240+
container.addEventListener('keypress', publicAPI.handleKeyPress);
241+
container.addEventListener('keydown', publicAPI.handleKeyDown);
242+
// Observe keyup on document in case the focus changes
243+
// between keydown and keyup.
242244
document.addEventListener('keyup', publicAPI.handleKeyUp);
243245

244246
document.addEventListener(
245247
'pointerlockchange',
246248
publicAPI.handlePointerLockChange
247249
);
248250

251+
container.tabIndex = 0; // to receive key events
249252
// using touchAction is more performant than preventDefault
250253
// in a touchstart handler.
251254
container.style.touchAction = 'none';
@@ -307,8 +310,8 @@ function vtkRenderWindowInteractor(publicAPI, model) {
307310
publicAPI.handlePointerCancel
308311
);
309312
}
310-
document.removeEventListener('keypress', publicAPI.handleKeyPress);
311-
document.removeEventListener('keydown', publicAPI.handleKeyDown);
313+
container.removeEventListener('keypress', publicAPI.handleKeyPress);
314+
container.removeEventListener('keydown', publicAPI.handleKeyDown);
312315
document.removeEventListener('keyup', publicAPI.handleKeyUp);
313316
document.removeEventListener(
314317
'pointerlockchange',

0 commit comments

Comments
 (0)