I am trying to create a custom forge viewer tool that only enables the box-selection extension while the shift key is pressed down. This works as expected on Mac devices but on Windows it enables the box-selection but never deactivates the box-selection once the shift key is released.
Both the handleKeyDown and handleKeyUp event handlers are triggered as expected on both platforms. So it seems to me an internal issue with the deactiveTool function. I tried debugging my way through this and I see there is some Mac specific logic in the functions but the root cause of the issue is beyond me.
Here is my custom box-selection tool.
/**
* Custom forge viewer tool to restrict box-selection to the shift key
* @param viewer Reference to the forge viewer instance
* @see {@link https://aps.autodesk.com/blog/custom-tools-forge-viewer | Forge Documentation}
*/
export const getCustomBoxSelectionTool = (viewer) => {
if (!viewer?.toolController) return null;
const customTool = {
active: false,
getName: () => 'custom-box-selection',
getNames: () => ['custom-box-selection'],
getPriority: () => 1, // Set priority in the tool chain
activate: () => {
customTool.active = true;
},
deactivate: () => {
customTool.active = false;
},
handleKeyDown: (event, keyCode) => {
// Prevent the default box-selection behaviour
if (event.key === 'Control' || keyCode === 17) {
viewer.toolController.deactivateTool('box-selection');
return true; // Stop propagation
}
// Enable new box-selection behaviour
if (event.key === 'Shift' || keyCode === 16) {
viewer.toolController.activateTool('box-selection');
}
return false; // Allow propagation
},
handleKeyUp: (event, keyCode) => {
// Disable box-selection after shift is released
if (event.key === 'Shift' || keyCode === 17) {
viewer.toolController.deactivateTool('box-selection');
}
return false; // Allow propagation
}
};
return customTool;
};
Note I added checks for the event.key and keyCode as that was a suggested difference between the two platforms but this has made no difference. Does anyone have any insights to this?
activateTool()
and deactivateTool()
works with counters, so if you call activateTool()
twice, a single call to deactivateTool()
will not deactivate it.
As I mentioned in a comment, one typo in your code is checking for keyCode == 17 // CTRL
instead of 16 // SHIFT
, so it should be
handleKeyUp: (event, keyCode) => {
// Disable box-selection after shift is released
if (event.key === 'Shift' || keyCode === 16) {
viewer.toolController.deactivateTool('box-selection');
}
return false; // Allow propagation
}
Another thing you can do is check if the box tool is already active before trying to activate it again and increase the counter.
handleKeyDown: (event, keyCode) => {
// Prevent the default box-selection behaviour
if (event.key === 'Control' || keyCode === 17) {
viewer.toolController.deactivateTool('box-selection');
return true; // Stop propagation
}
// Enable new box-selection behaviour
if (event.key === 'Shift' || keyCode === 16) {
// do not call activateTool mutiple times
const bsActive = viewer.toolController.getActiveTools().some(t => t.getName() === 'box-selection')
if (bsActive) return false;
viewer.toolController.activateTool('box-selection');
}
return false; // Allow propagation
},