Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
29 changes: 24 additions & 5 deletions src/annotator/draw-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export class DrawTool implements Destroyable {
/** Increment for keyboard movement (pixels) */
private readonly _keyboardMoveIncrement = 10;

/** Increment for keyboard movement with Shift (pixels) */
/** Increment for keyboard movement with Ctrl (Windows) or Cmd (Mac) (pixels) */
Comment thread
gmorador-tribu marked this conversation as resolved.
Outdated
private readonly _keyboardMoveIncrementLarge = 50;

/** Default size for rectangle when initialized via keyboard (pixels) */
Expand All @@ -129,6 +129,9 @@ export class DrawTool implements Destroyable {
/** Timeout ID for debouncing scroll events */
private _scrollDebounceTimeout?: number;

/** True when the current rect was created by keyboard; first mouse move clears it so user can draw with mouse. */
private _rectInitiatedByKeyboard: boolean = false;

/**
* @param root - Container in which the user can draw a shape. The drawing
* layer is positioned to fill the container using `position: absolute`.
Expand Down Expand Up @@ -232,10 +235,13 @@ export class DrawTool implements Destroyable {
this._waitingForSecondClick = false;
this._firstClickPoint = undefined;
this._hasMoved = false;
this._rectInitiatedByKeyboard = false;

this._surface.addEventListener('pointerdown', e => {
switch (this._tool) {
case 'rect':
// User is interacting with mouse; rect is no longer "keyboard-initiated"
this._rectInitiatedByKeyboard = false;
// If we're waiting for a second click, this is the second click
if (this._waitingForSecondClick && this._firstClickPoint) {
// Complete the rectangle with the second click
Expand Down Expand Up @@ -277,6 +283,16 @@ export class DrawTool implements Destroyable {
});

this._surface.addEventListener('pointermove', e => {
// If rect was created by keyboard, first mouse move clears it so user can draw selection with mouse
if (this._rectInitiatedByKeyboard && this._shape?.type === 'rect') {
this._shape = undefined;
this._rectInitiatedByKeyboard = false;
this._waitingForSecondClick = false;
this._firstClickPoint = undefined;
this._hasMoved = false;
this._renderSurface();
return;
}
Comment thread
gmorador-tribu marked this conversation as resolved.
if (!this._shape) {
return;
}
Expand Down Expand Up @@ -442,15 +458,16 @@ export class DrawTool implements Destroyable {
return;
}

// Arrow keys: Move or resize
// Arrow keys: Move or resize. Fast movement: Ctrl (Windows) or Cmd (Mac)
if (
['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.key)
) {
e.preventDefault();
e.stopPropagation();
const increment = e.shiftKey
? this._keyboardMoveIncrementLarge
: this._keyboardMoveIncrement;
const increment =
e.metaKey || e.ctrlKey
? this._keyboardMoveIncrementLarge
: this._keyboardMoveIncrement;
this._handleArrowKey(e.key, increment);
return;
}
Expand All @@ -471,6 +488,7 @@ export class DrawTool implements Destroyable {
this._waitingForSecondClick = false;
this._firstClickPoint = undefined;
this._hasMoved = false;
this._rectInitiatedByKeyboard = false;
this._deactivateKeyboardMode();
};

Expand Down Expand Up @@ -565,6 +583,7 @@ export class DrawTool implements Destroyable {
// Initialize shape at top-left corner of visible content area if it doesn't exist
if (!this._shape) {
this._updateRectanglePosition();
this._rectInitiatedByKeyboard = true;
}

// Set up scroll listener to update rectangle position when scrolling
Expand Down
8 changes: 6 additions & 2 deletions src/annotator/guest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1045,8 +1045,12 @@ export class Guest
this._hostRPC.call('activeToolChanged', tool);

// Draw the shape for the new annotation's region.
// Pass pending keyboard mode if set (from hotkey activation)
const initialMode = this._pendingKeyboardMode;
// Pass pending keyboard mode if set (from hotkey). For rect, default to
// 'move' so the rectangle appears on canvas when started via mouse (sidebar icon).
const initialMode =
tool === 'rect'
? (this._pendingKeyboardMode ?? 'move')
: this._pendingKeyboardMode;
Comment thread
gmorador-tribu marked this conversation as resolved.
Outdated
this._pendingKeyboardMode = undefined;
const shape = await this._drawTool.draw(tool, initialMode);

Expand Down
10 changes: 5 additions & 5 deletions src/annotator/test/draw-tool-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1057,14 +1057,14 @@ describe('DrawTool', () => {
assert.isNumber(shape.bottom);
});

it('Arrow keys with Shift use large increment for point', async () => {
it('Arrow keys with Ctrl use large increment for point', async () => {
const shapePromise = tool.draw('point', 'move');
await delay(0);

document.body.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'ArrowRight',
shiftKey: true,
ctrlKey: true,
bubbles: true,
}),
);
Expand All @@ -1079,15 +1079,15 @@ describe('DrawTool', () => {
assert.isNumber(shape.y);
});

it('Arrow keys with Shift use large increment', async () => {
it('Arrow keys with Ctrl use large increment', async () => {
const shapePromise = tool.draw('rect', 'move');
await delay(0);

// Move with Shift (large increment)
// Move with Ctrl (large increment; Cmd on Mac)
document.body.dispatchEvent(
new KeyboardEvent('keydown', {
key: 'ArrowRight',
shiftKey: true,
ctrlKey: true,
bubbles: true,
}),
);
Expand Down