Skip to content

Commit

Permalink
🎉 Make it possible to disable marking mode and turbo mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Schneegans committed Oct 11, 2024
1 parent 9054780 commit 47ab926
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 68 deletions.
5 changes: 3 additions & 2 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ This changelog follows the rules of [Keep a Changelog](http://keepachangelog.com

- **Paste-Text Action!** You can now paste text into the currently focused window using the new "Paste Text" action. This uses your clipboard internally, so it can paste any text including special characters like emojis 🎊!
- **Support for base64 icons!** This allows you to directly embed base64 encoded images. This will be especially helpful for menus which are dynamically generated via some sort of API in the future. Use `"base64"` as the icon theme and provide the base64 encoded image as the `"icon"`. This will be a string starting with something like `"data:image/svg+xml;base64, ..."`. This even supports animated gifs!
- Added an option to the menu editor which **allows warping the mouse pointer to the center of the menu** when the menu is opened in centered mode. This allows to directly engage in turbo mode even if the menu is shown at the center of the screen.
- It is now possible to **change the fade-in and fade-out duration of the menu!** For now, it is only possible to change this via the `fadeInDuration` and `fadeOutDuration` properties in the `config.json` file. The values are given in milliseconds and default to 150ms and 200ms respectively. In the future, this will be exposed in the settings UI.
- An option to the menu editor which **allows warping the mouse pointer to the center of the menu** when the menu is opened in centered mode. This allows to directly engage in turbo mode even if the menu is shown at the center of the screen.
- The possibility to **change the fade-in and fade-out duration of the menu!** For now, it is only possible to change this via the `fadeInDuration` and `fadeOutDuration` properties in the `config.json` file. The values are given in milliseconds and default to 150ms and 200ms respectively. In the future, this will be exposed in the settings UI.
- The possibility to **disable Marking Mode and Turbo Mode** altogether. This can be useful if you never use these features and want to avoid accidental selections. For now, this can be done via the `enableMarkingMode` and `enableTurboMode` in your `config.json`. In the future, this will be exposed in the settings UI.
- Icon themes are now also loaded from `resources/app/.webpack/renderer/assets/icon-themes/` in the installation directory. This can be interesting if you are packaging icon themes using a package manager. However, as an end user, you should not put your icon themes there, as they might be overwritten during an update.
- Support for symbolic links in the `icon-themes` directory. You can now create a symbolic link to an icon theme in the `icon-themes` directory and Kando will load the icons from the linked directory.
- Several **translation updates**. Thanks to all the contributors!
Expand Down
2 changes: 2 additions & 0 deletions docs/config-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ Property | Default Value | Description
`zoomFactor` | `1.0` | The zoom factor of the menu. This can be used to scale the menu on high-resolution screens.
`fadeInDuration` | `150` | The duration of the fade-in animation in milliseconds. Set to `0` to disable the animation.
`fadeOutDuration` | `200` | The duration of the fade-out animation in milliseconds. Set to `0` to disable the animation. Some actions are only executed after the fade-out animation has finished, so reducing this value can make the menu much "snappier".
`enableMarkingMode` | `true` | If enabled, items can be selected by dragging the mouse over them.
`enableTurboMode` | `true` | If enabled, items can be selected by hovering over them while holding down a keyboard key.
`enableVersionCheck` | `true` | If set to `true`, Kando will check for new version regularly, and show a notification if a new version is available.

## The Menu Configuration: `menus.json`
Expand Down
9 changes: 9 additions & 0 deletions src/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -432,4 +432,13 @@ export interface IAppSettings {

/** The duration of the fade out animation in milliseconds. */
fadeOutDuration: number;

/** If enabled, items can be selected by dragging the mouse over them. */
enableMarkingMode: boolean;

/**
* If enabled, items can be selected by hovering over them while holding down a keyboard
* key.
*/
enableTurboMode: boolean;
}
2 changes: 2 additions & 0 deletions src/main/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ export class KandoApp {
zoomFactor: 1,
fadeInDuration: 150,
fadeOutDuration: 200,
enableMarkingMode: true,
enableTurboMode: true,
},
});

Expand Down
15 changes: 7 additions & 8 deletions src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ Promise.all([
const menu = new Menu(document.getElementById('kando-menu'), menuTheme, {
fadeInDuration: settings.fadeInDuration,
fadeOutDuration: settings.fadeOutDuration,
enableMarkingMode: settings.enableMarkingMode,
enableTurboMode: settings.enableTurboMode,
});
const editor = new Editor(document.getElementById('kando-editor'), info);

Expand All @@ -102,14 +104,11 @@ Promise.all([
document.getElementById('sidebar-show-new-version-button').classList.remove('d-none');
});

// Tell the menu about the current fade durations.
window.api.appSettings.onChange('fadeInDuration', (fadeInDuration) => {
menu.setFadeInDuration(fadeInDuration);
});

window.api.appSettings.onChange('fadeOutDuration', (fadeOutDuration) => {
menu.setFadeOutDuration(fadeOutDuration);
});
// Tell the menu about settings changes.
window.api.appSettings.onChange('fadeInDuration', (t) => menu.setFadeInDuration(t));
window.api.appSettings.onChange('fadeOutDuration', (t) => menu.setFadeOutDuration(t));
window.api.appSettings.onChange('enableMarkingMode', (b) => menu.enableMarkingMode(b));
window.api.appSettings.onChange('enableTurboMode', (b) => menu.enableTurboMode(b));

// Sometimes, the user may select an item too close to the edge of the screen. In this
// case, we can not open the menu directly under the pointer. To make sure that the
Expand Down
117 changes: 65 additions & 52 deletions src/renderer/menu/input-tracker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,22 @@ import { EventEmitter } from 'events';
import * as math from '../math';
import { IVec2 } from '../../common';

/**
* This is the threshold in pixels which is used to differentiate between a click and a
* drag. If the mouse is moved more than this threshold before the mouse button is
* released, the current mouse state is set to DRAGGING.
*/
const DRAG_THRESHOLD = 15;

/**
* This enum is used to store the logical state of the input device. This will be set to
* eClicked once a mouse button is pressed. If the mouse is moved more than a couple of
* pixels before the mouse button is released, it is set to eDragging. When the mouse
* button is released, it is set to eReleased.
* pixels before the mouse button is released, it is set to eMarkingMode. When the mouse
* button is released, it is set to eReleased. There is also the possibility of the "Turbo
* Mode" which allows the user to select items by moving the mouse while a key is
* pressed.
*
* At a higher level, Kando does not differentiate between mouse, touch and pen input.
* This enum is used for all input devices. There is even the possibility of the "Turbo
* Mode" which allows the user to select items by moving the mouse while a key is pressed.
* In this case, the pointer state will also be set to eDragging, even though the mouse
* button is not pressed.
* At a higher level, Kando does not differentiate between mouse, touch, gamepad, or pen
* input. This enum is used for all input devices.
*/
export enum InputState {
eReleased,
eClicked,
eDragging,
eMarkingMode,
eTurboMode,
}

/**
Expand All @@ -45,10 +38,8 @@ export enum InputState {
*
* This class is an EventEmitter. It emits the following events:
*
* @fires pointer-motion - This event is emitted whenever the mouse moves. This first
* argument is the absolute mouse position. The second argument is a boolean which is
* true if the mouse is currently dragging an item. This is also true in turbo mode,
* when the mouse is moved while a keyboard key is pressed.
* @fires pointer-motion - This event is emitted whenever the mouse moves. The absolute
* mouse position is passed as an argument.
*/
export class InputTracker extends EventEmitter {
/** See the documentation of the corresponding getters for more information. */
Expand All @@ -58,7 +49,6 @@ export class InputTracker extends EventEmitter {
private _angle = 0;
private _distance = 0;
private _deferredTurboMode = false;
private _turboMode = false;

/** The position where the mouse was when the user pressed a mouse button the last time. */
private clickPosition = { x: 0, y: 0 };
Expand All @@ -68,7 +58,7 @@ export class InputTracker extends EventEmitter {

/**
* This is set to true once a key is pressed. If the pointer is moved at least
* DRAG_THRESHOLD before the key is released, the turbo mode will be activated.
* this.dragThreshold before the key is released, the turbo mode will be activated.
*/
private anyKeyPressed = false;

Expand All @@ -81,23 +71,38 @@ export class InputTracker extends EventEmitter {
private ignoreMotionEvents = 0;

/**
* This returns true if the input state is set to eDragging even if no mouse button is
* pressed.
* This is the threshold in pixels which is used to differentiate between a click and a
* drag. If the mouse is moved more than this threshold before the mouse button is
* released, an item is dragged.
*/
public get turboMode() {
return this._turboMode;
}
public dragThreshold = 15;

/** If enabled, items can be selected by dragging the mouse over them. */
public enableMarkingMode = true;

/**
* If enabled, items can be selected by hovering over them while holding down a keyboard
* key.
*/
public enableTurboMode = true;

/**
* This will be set to eClicked once a mouse button is pressed. If the mouse is moved
* more than DRAG_THRESHOLD pixels before the mouse button is released, this is set to
* eDragging. When the mouse button is released, this is set to eReleased. It can also
* be set to eDragging if the mouse is moved while a key is pressed.
* more than this.dragThreshold pixels before the mouse button is released, this is set
* to eMarkingMode. When the mouse button is released, this is set to eReleased. It can
* also be set to eMarkingMode if the mouse is moved while a key is pressed.
*/
public get state() {
return this._state;
}

/** Returns true if we are in marking or in turbo mode. */
public get isDragging() {
return (
this._state === InputState.eMarkingMode || this._state === InputState.eTurboMode
);
}

/**
* The absolute mouse position is the position of the mouse in screen coordinates. It is
* always updated when the mouse moves.
Expand Down Expand Up @@ -138,7 +143,6 @@ export class InputTracker extends EventEmitter {
*/
public set deferredTurboMode(val: boolean) {
this._deferredTurboMode = val;
this._turboMode = false;
}

/**
Expand Down Expand Up @@ -169,45 +173,50 @@ export class InputTracker extends EventEmitter {
}

// If the mouse moved too much, the current mousedown - mouseup event is not
// considered to be a click anymore. Set the current mouse state to
// InputState.eDragging.
if (
this._state === InputState.eClicked &&
math.getDistance(this._absolutePosition, this.clickPosition) > DRAG_THRESHOLD
) {
this._state = InputState.eDragging;
// considered to be a click anymore. Instead, we are in marking mode.
const inClickZone =
this.clickPosition &&
math.getDistance(this._absolutePosition, this.clickPosition) < this.dragThreshold;

if (this._state === InputState.eClicked && !inClickZone) {
this._state = this.enableMarkingMode
? InputState.eMarkingMode
: InputState.eReleased;
}

// We check if the turbo mode should be activated. This is the case if any key is
// pressed and the mouse is moved more than DRAG_THRESHOLD since the last keydown
// pressed and the mouse is moved more than this.dragThreshold since the last keydown
// event. Also, the turbo mode is activated if any modifier key is pressed.
if (!this._deferredTurboMode && !this._turboMode) {
let shouldEnterTurboMode = false;
const canEnterTurboMode =
this.enableTurboMode &&
!this._deferredTurboMode &&
this.state !== InputState.eTurboMode;

if (canEnterTurboMode) {
if (this.anyKeyPressed) {
this._turboMode =
math.getDistance(this._absolutePosition, this.keydownPosition) > DRAG_THRESHOLD;
shouldEnterTurboMode =
math.getDistance(this._absolutePosition, this.keydownPosition) >
this.dragThreshold;
}

if (!this._turboMode) {
this._turboMode =
if (!shouldEnterTurboMode) {
shouldEnterTurboMode =
event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;
}
}

if (this.turboMode) {
this._state = InputState.eDragging;
if (shouldEnterTurboMode) {
this._state = InputState.eTurboMode;
} else if (
event instanceof MouseEvent &&
this._state === InputState.eDragging &&
this._state === InputState.eMarkingMode &&
event.buttons === 0
) {
this._state = InputState.eReleased;
}

this.emit(
'pointer-motion',
this._absolutePosition,
this._state === InputState.eDragging
);
this.emit('pointer-motion', this._absolutePosition);
}

/**
Expand Down Expand Up @@ -239,6 +248,7 @@ export class InputTracker extends EventEmitter {
*/
public onPointerUpEvent() {
this._state = InputState.eReleased;
this.clickPosition = null;
}

/**
Expand Down Expand Up @@ -270,7 +280,10 @@ export class InputTracker extends EventEmitter {
if (!stillAnyModifierPressed) {
this.anyKeyPressed = false;
this._deferredTurboMode = false;
this._turboMode = false;

if (this._state === InputState.eTurboMode) {
this._state = this.clickPosition ? InputState.eMarkingMode : InputState.eReleased;
}
}
}

Expand Down
Loading

0 comments on commit 47ab926

Please sign in to comment.