diff --git a/README.md b/README.md
index 379813cb..d4ee37a4 100644
--- a/README.md
+++ b/README.md
@@ -88,19 +88,65 @@ acceleration involved. One just presses them.
* `Key_mouseBtnL`, `Key_mouseBtnM`, `Key_mouseBtnR`: The left, middle, and right
mouse buttons, respectively.
-### Warping
+## Warping
Warping is one of the most interesting features of the plugin, and is a feature
unique to Kaleidoscope, as far as we can tell. The warping keys position the
-mouse cursor within a quadrant of the screen on first press, and any subsequent
-taps will warp within the previously selected quadrant. For example, pressing
-the north-west warp key twice will first jump to the middle of the north-west
-quadrant of your screen, then select the north-west quadrant of that, and jump
-to the middle of it.
+mouse cursor within a sector of the screen on first press, and any subsequent
+taps will warp within the previously selected sector. For example, pressing the
+north-west warp key twice will first jump to the middle of the north-west
+sector of your screen, then select the north-west sector of that, and jump to
+the middle of it.
To stop warping, use any other mouse key, or hit the "warp end" key.
-The warping keys are the following:
+### Warp grid size
+
+The warp grid size determines how MouseKeys partitions the screen to select the
+next position to jump to when pressing a warp key. The plugin provides two grid
+sizes to choose from: a *2x2* grid that splits the screen into quadrants, and a
+*3x3* grid with nine cells similar to a navigation feature included with some
+speech recognition software. By default, the plugin splits the screen into the
+2x2 grid.
+
+To change the warp grid size, call the plugin's `setWarpGridSize()` method:
+
+```c++
+MouseKeys.setWarpGridSize(MOUSE_WARP_GRID_3X3);
+```
+
+#### 2x2 grid
+
+As described above, MouseKeys warps the pointer using a grid model that reflects
+locations on the screen. By default, the plugin uses a 2x2 grid. To understand
+how warping works, examine this diagram of a screen split into that 2x2 grid:
+
+ +-----------------------+-----------------------+
+ | | | |
+ | G | tab | |
+ | | | |
+ |-----------+-----------| tab |
+ | | | |
+ | B | esc | |
+ | | | |
+ +-----------------------+-----------------------+
+ | | |
+ | | |
+ | | |
+ | B | esc |
+ | | |
+ | | |
+ | | |
+ +-----------------------+-----------------------+
+
+Each quadrant is labed with a key that, when pressed, moves the mouse pointer
+to the center of that quadrant. With this layout, pressing G warps
+the pointer to the top-left quadant. Then, the plugin "zooms" into that sector
+with a smaller grid so that the next warp key pressed jumps the pointer more
+precisely within the sector. In this case, if we press esc next,
+the pointer warps to the bottom-right corner within that quadrant.
+
+The warping keys for the 2x2 grid are the following:
* `Key_mouseWarpNW`, `Key_mouseWarpNE`, `Key_mouseWarpSW`, `Key_mouseWarpSE`:
Warp towards the north-west, north-east, south-west, or south-east quadrants,
@@ -109,6 +155,64 @@ The warping keys are the following:
state. Using any of the warping keys after this will start from the whole
screen again.
+#### 3x3 grid
+
+A 3x3 warp grid assigns a key to each of nine sectors of the screen. The next
+diagram shows a screen with a key label that warps to each sector. As we can
+see, pressing W warps the pointer into the top-left sector, and
+pressing V warps to the bottom-right corner within that sector:
+
+ +-----------------+-----------------+-----------------+
+ | W | E | R | | |
+ |-----+-----+-----| | |
+ | S | D | F | E | R |
+ |-----+-----+-----| | |
+ | X | C | V | | |
+ +-----------------+-----------------+-----------------+
+ | | | |
+ | | | |
+ | S | D | F |
+ | | | |
+ | | | |
+ +-----------------+-----------------+-----------------+
+ | | | |
+ | | | |
+ | X | C | V |
+ | | | |
+ | | | |
+ +-----------------+-----------------+-----------------+
+
+To use a 3x3 warp grid, we may need to remap some keys. A suggested warp key
+mapping is shown below on the left side of a keyboard with a QWERTY layout:
+
+ W | E | R T A - End Warping (Key_mouseWarpEnd)
+ ---+---+--- W - Warp NW Sector (Key_mouseWarpNW)
+ A S | D | F G E - Warp N Sector (Key_mouseWarpN)
+ ---+---+--- R - Warp NE Sector (Key_mouseWarpNE)
+ X | C | V B S - Warp E Sector (Key_mouseWarpE)
+ D - Warp/Zoom Center (Key_mouseWarpIn)
+ F - Warp W Sector (Key_mouseWarpW)
+ K - Warp SE Sector (Key_mouseWarpSE)
+ C - Warp S Sector (Key_mouseWarpS)
+ V - Warp SW Sector (Key_mouseWarpSW)
+ T - Right Click (Key_mouseBtnR)
+ G - Left Click (Key_mouseBtnL)
+ B - Middle Click (Key_mouseBtnM)
+
+This example layout replaces the default directional mouse keys and sets the
+warp keys in a comfortable position for a warp-only configuration. Of course,
+a Kaleidoscope user may retain the directional keys and map the warp keys
+elsewhere according to his or her liking.
+
+A 3x3 warp grid layout contains all of the keys from the 2x2 grid layout with
+the following additions:
+
+* `Key_mouseWarpN`, `Key_mouseWarpE`, `Key_mouseWarpS`, `Key_mouseWarpW`:
+ Warp towards the north, east, south, and west sectors, respectively.
+* `Key_mouseWarpIn`: Warp to the center sector of the grid. The plugin will
+ continue to "zoom" into center of the current cell with each consecutive
+ press of this key.
+
## Plugin methods
The plugin provides a `MouseKeys` object, with the following methods and
@@ -137,3 +241,8 @@ properties available:
> scrolling speed. The former, `.wheelSpeed`, controls the amount of ticks the
> wheel shall scroll, and defaults to 1. The second, `.wheelDelay`, controls the
> delay between two scroll events, and defaults to 50 milliseconds.
+
+### `.setWarpGridSize`
+
+> This method changes the size of the grid used for [warping](#warping). The
+> following are valid sizes: `MOUSE_WARP_GRID_2X2`, `MOUSE_WARP_GRID_3X3`
diff --git a/src/Kaleidoscope-MouseKeys.cpp b/src/Kaleidoscope-MouseKeys.cpp
index 4455dde4..6da6090b 100644
--- a/src/Kaleidoscope-MouseKeys.cpp
+++ b/src/Kaleidoscope-MouseKeys.cpp
@@ -19,6 +19,10 @@ uint32_t MouseKeys_::accelEndTime;
uint32_t MouseKeys_::endTime;
uint32_t MouseKeys_::wheelEndTime;
+void MouseKeys_::setWarpGridSize(uint8_t grid_size) {
+ MouseWrapper.warp_grid_size = grid_size;
+}
+
void MouseKeys_::scrollWheel(uint8_t keyCode) {
if (millis() < wheelEndTime)
return;
@@ -102,10 +106,10 @@ Key MouseKeys_::eventHandlerHook(Key mappedKey, byte row, byte col, uint8_t keyS
}
} else if (keyToggledOn(keyState)) {
if (mappedKey.keyCode & KEY_MOUSE_WARP && mappedKey.flags & IS_MOUSE_KEY) {
- // we don't pass in the left and up values because those are the
- // default, "no-op" conditionals
MouseWrapper.warp(((mappedKey.keyCode & KEY_MOUSE_WARP_END) ? WARP_END : 0x00) |
+ ((mappedKey.keyCode & KEY_MOUSE_UP) ? WARP_UP : 0x00) |
((mappedKey.keyCode & KEY_MOUSE_DOWN) ? WARP_DOWN : 0x00) |
+ ((mappedKey.keyCode & KEY_MOUSE_LEFT) ? WARP_LEFT : 0x00) |
((mappedKey.keyCode & KEY_MOUSE_RIGHT) ? WARP_RIGHT : 0x00));
}
}
diff --git a/src/Kaleidoscope-MouseKeys.h b/src/Kaleidoscope-MouseKeys.h
index 255a0888..78dbabe2 100644
--- a/src/Kaleidoscope-MouseKeys.h
+++ b/src/Kaleidoscope-MouseKeys.h
@@ -2,6 +2,7 @@
#include "Kaleidoscope.h"
#include "MouseKeyDefs.h"
+#include "MouseWarpModes.h"
class MouseKeys_ : public KaleidoscopePlugin {
public:
@@ -16,6 +17,8 @@ class MouseKeys_ : public KaleidoscopePlugin {
static uint8_t wheelSpeed;
static uint16_t wheelDelay;
+ static void setWarpGridSize(uint8_t grid_size);
+
private:
static uint8_t mouseMoveIntent;
static uint32_t endTime;
diff --git a/src/MouseKeyDefs.h b/src/MouseKeyDefs.h
index 2a10af25..5f66a5d4 100644
--- a/src/MouseKeyDefs.h
+++ b/src/MouseKeyDefs.h
@@ -20,8 +20,13 @@
#define Key_mouseWarpNW (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
+#define Key_mouseWarpN (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
#define Key_mouseWarpNE (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
+#define Key_mouseWarpW (Key) { KEY_MOUSE_WARP| KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
+#define Key_mouseWarpIn (Key) { KEY_MOUSE_WARP| KEY_MOUSE_UP | KEY_MOUSE_DOWN, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
+#define Key_mouseWarpE (Key) { KEY_MOUSE_WARP| KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
#define Key_mouseWarpSW (Key) { KEY_MOUSE_WARP| KEY_MOUSE_DOWN | KEY_MOUSE_LEFT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
+#define Key_mouseWarpS (Key) { KEY_MOUSE_WARP| KEY_MOUSE_DOWN, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
#define Key_mouseWarpSE (Key) { KEY_MOUSE_WARP| KEY_MOUSE_DOWN | KEY_MOUSE_RIGHT, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
#define Key_mouseWarpEnd (Key) { KEY_MOUSE_WARP| KEY_MOUSE_WARP_END, KEY_FLAGS|SYNTHETIC|IS_MOUSE_KEY }
diff --git a/src/MouseWarpModes.h b/src/MouseWarpModes.h
new file mode 100644
index 00000000..6f2b28a4
--- /dev/null
+++ b/src/MouseWarpModes.h
@@ -0,0 +1,10 @@
+#pragma once
+
+// Warp modes determine how the plugin jumps the mouse pointer to a screen
+// location when pressing a warp key.
+
+
+// Grid Based - the constant represents the number of cells in a row or column:
+
+#define MOUSE_WARP_GRID_2X2 2
+#define MOUSE_WARP_GRID_3X3 3
diff --git a/src/MouseWrapper.cpp b/src/MouseWrapper.cpp
index 9476a237..100367bb 100644
--- a/src/MouseWrapper.cpp
+++ b/src/MouseWrapper.cpp
@@ -5,6 +5,7 @@
#include "MouseWrapper.h"
#include "kaleidoscope/hid.h"
+uint8_t MouseWrapper_::warp_grid_size = MOUSE_WARP_GRID_2X2;
uint16_t MouseWrapper_::next_width;
uint16_t MouseWrapper_::next_height;
uint16_t MouseWrapper_::section_top;
@@ -59,21 +60,29 @@ void MouseWrapper_::warp(uint8_t warp_cmd) {
return;
}
- next_width = next_width / 2;
- next_height = next_height / 2;
+ next_width /= warp_grid_size;
+ next_height /= warp_grid_size;
- if (warp_cmd & WARP_UP) {
-// Serial.print(" - up ");
- } else if (warp_cmd & WARP_DOWN) {
-// Serial.print(" - down ");
- section_top = section_top + next_height;
+ // WARP_UP + WARP_DOWN means "zoom in" to center sector
+ if (warp_cmd & WARP_UP && warp_cmd & WARP_DOWN) {
+ section_left += next_width;
+ section_top += next_height;
+
+ warp_jump(section_left, section_top, next_height, next_width);
+
+ return;
+ }
+
+ if (warp_cmd & WARP_DOWN) {
+ section_top += next_height * (warp_grid_size - 1);
+ } else if (!(warp_cmd & WARP_UP)) {
+ section_top += next_height;
}
- if (warp_cmd & WARP_LEFT) {
- // Serial.print(" - left ");
- } else if (warp_cmd & WARP_RIGHT) {
- // Serial.print(" - right ");
- section_left = section_left + next_width;
+ if (warp_cmd & WARP_RIGHT) {
+ section_left += next_width * (warp_grid_size - 1);
+ } else if (!(warp_cmd & WARP_LEFT)) {
+ section_left += next_width;
}
warp_jump(section_left, section_top, next_height, next_width);
diff --git a/src/MouseWrapper.h b/src/MouseWrapper.h
index 732d2af7..8c6ee04f 100644
--- a/src/MouseWrapper.h
+++ b/src/MouseWrapper.h
@@ -1,6 +1,7 @@
#pragma once
#include "Arduino.h"
+#include "MouseWarpModes.h"
// Warping commands
@@ -32,6 +33,7 @@ class MouseWrapper_ {
static void release_button(uint8_t button);
static uint8_t accelStep;
static uint8_t speedLimit;
+ static uint8_t warp_grid_size;
private:
static uint16_t next_width;