fix: ignore warps on modes and shake

This commit is contained in:
Virt 2024-08-25 22:58:55 +02:00
commit 55e8b316ce
14 changed files with 80 additions and 9 deletions

View file

@ -98,10 +98,10 @@ plugin:dynamic-cursors {
enabled = true
# sets the cursor behaviour, supports these values:
# tilt - tilt the cursor based on x-velocity
# rotate - rotate the cursor based on movement direction
# tilt - tilt the cursor based on x-velocity
# rotate - rotate the cursor based on movement direction
# stretch - stretch the cursor shape based on direction and velocity
# none - do not change the cursors behaviour
# none - do not change the cursors behaviour
mode = tilt
# minimum angle difference in degrees after which the shape is changed
@ -175,7 +175,7 @@ plugin:dynamic-cursors {
base = 4.0
# magnification increase per second when continuing to shake
speed = 4.0
# factor the speed is influenced by the current shake intensitiy
# how much the speed is influenced by the current shake intensitiy
influence = 0.0
# maximal magnification the cursor can reach
@ -209,7 +209,7 @@ shaperule = shape-name, mode (optional), property: value, property: value, ...
- `property: value`: At the end of the rule follow zero or more property-value pairs. These are config values that will be overridden if this rule is active. Only config values from the sections `rotate`, `tilt`, `stretch` as seen above can be used.
Here are a few example rules to get you started:
```
```ini
plugin:dynamic-cursors {
# apply a 90° offset in rotate mode to the text shape
shaperule = text, rotate:offset: 90
@ -225,12 +225,12 @@ plugin:dynamic-cursors {
### ipc
This plugin can expose cursor shake events via IPC. This behaviour must be explicitly enabled via the `plugin:dynamic-cursors:shake:ipc` option, as it will spam the socket quite a bit during a shake. These events will appear on [Hyprland's event socket](https://wiki.hyprland.org/IPC/#xdg_runtime_dirhyprhissocket2sock).
The following events with the described arguments are available, when ipc is enabled:
The following events with the described arguments are available, when IPC is enabled:
- `shakestart`: fired when a shake is detected.
- `shakeupdate`: fired on frame during the shake, has arguments `x,y,trail,diagonal,zoom`:
- `x`, `y` are the current cursor position.
- `trail` and `diagonal` are two values indicating the distance the mouse travelled, and the diagonal this movement was within for the last second. Their quotient `trail / diagonal` indicates how intense the shaking is.
- `zoom` is the current cursor magnification level, as currently shown by this plugin, as customized in the shake configuration.
- `trail` and `diagonal` are two floats, the first indicating the distance the mouse travelled, and second the diagonal this movement was within. Their quotient `trail / diagonal` indicates how intense the shaking is.
- `zoom` is the current cursor magnification level, as currently shown by this plugin, depending on the shake configuration. It is also interpolated smoothly.
- `shakeend`: fired when a shake has ended (after the `timeout`)
If you only want the IPC events and not the plugin actually changing the cursor size, you can set the properties `base` to `1`, `speed`, `influence` and `timeout` to `0` in the `plugin:dynamic-cursors:shake` section such that the cursor is not magified during the shake.
@ -260,6 +260,8 @@ To work on this plugin, you can clone this repository and use the Makefile to bu
make load
```
In some cases when working in a nest, nothing will happen with the plugin loaded. This is because the mouse input is handled differently in a wayland nest. In these cases, set `plugin:dynamic-cursors:ignore_warps` to `false`, to disable warp ignoring, which should fix the issue.
If you want to debug hardware cursors, this plugin also has an additional configuration option, `plugin:dynamic-cursors:hw_debug` which when true will show where the whole cursor buffer is, and also shows when it is updated.
Also make sure you disable the plugin on your host session, otherwise your cursor will be rotated twice.

View file

@ -9,6 +9,7 @@
#define CONFIG_MODE "mode"
#define CONFIG_THRESHOLD "threshold"
#define CONFIG_HW_DEBUG "hw_debug"
#define CONFIG_IGNORE_WARPS "ignore_warps"
#define CONFIG_SHAKE "shake:enabled"
#define CONFIG_SHAKE_NEAREST "shake:nearest"

View file

@ -154,8 +154,10 @@ SP<Aquamarine::IBuffer> CDynamicCursors::renderHardware(CPointerManager* pointer
Debug::log(TRACE, "hardware cursor too big! {} > {}", pointers->currentCursorImage.size, maxSize);
return nullptr;
}
} else
} else {
maxSize = targetSize;
if (maxSize.x < 16 || maxSize.y < 16) maxSize = {16, 16}; // fix some annoying crashes in nest
}
if (!state->monitor->cursorSwapchain || maxSize != state->monitor->cursorSwapchain->currentOptions().size || state->monitor->cursorSwapchain->currentOptions().length != 3) {
@ -317,6 +319,9 @@ bool CDynamicCursors::setHardware(CPointerManager* pointers, SP<CPointerManager:
Handles cursor move events.
*/
void CDynamicCursors::onCursorMoved(CPointerManager* pointers) {
static auto* const* PSHAKE = (Hyprlang::INT* const*) getConfig(CONFIG_SHAKE);
static auto* const* PIGNORE_WARPS = (Hyprlang::INT* const*) getConfig(CONFIG_IGNORE_WARPS);
if (!pointers->hasCursor())
return;
@ -332,7 +337,18 @@ void CDynamicCursors::onCursorMoved(CPointerManager* pointers) {
m->output->moveCursor(CURSORPOS);
}
// ignore warp
if (!isMove && **PIGNORE_WARPS) {
auto mode = this->currentMode();
if (mode) mode->warp(lastPos, pointers->pointerPos);
if (**PSHAKE) shake.warp(lastPos, pointers->pointerPos);
}
calculate(MOVE);
isMove = false;
lastPos = pointers->pointerPos;
}
void CDynamicCursors::setShape(const std::string& shape) {
@ -426,3 +442,7 @@ void CDynamicCursors::calculate(EModeUpdate type) {
}
}
}
void CDynamicCursors::setMove() {
isMove = true;
}

View file

@ -35,12 +35,16 @@ class CDynamicCursors {
/* hook on setCursorSoftware */
void unsetShape();
/* hook on move, indicate that next onCursorMoved is actual move */
void setMove();
private:
SP<CEventLoopTimer> tick;
// current state of the cursor
SModeResult resultMode;
double resultShake;
Vector2D lastPos; // used for warp compensation
SModeResult resultShown;
@ -57,6 +61,9 @@ class CDynamicCursors {
// shake
CShake shake;
/* is set true if a genuine move is being performed, and will be reset to false after onCursorMoved */
bool isMove = false;
// calculates the current angle of the cursor, and changes the cursor shape
void calculate(EModeUpdate type);
};

View file

@ -67,6 +67,13 @@ void hkSetCursorSurface(void* thisptr, SP<CWLSurface> surf, const Vector2D& hots
(*(origSetCursorSurface)g_pSetCursorSurfaceHook->m_pOriginal)(thisptr, surf, hotspot);
}
typedef void (*origMove)(void*, const Vector2D&);
inline CFunctionHook* g_pMoveHook = nullptr;
void hkMove(void* thisptr, const Vector2D& deltaLogical) {
if (isEnabled()) g_pDynamicCursors->setMove();
(*(origMove)g_pMoveHook->m_pOriginal)(thisptr, deltaLogical);
}
/* hooks a function hook */
CFunctionHook* hook(std::string name, std::string object, void* function) {
auto names = HyprlandAPI::findFunctionsByName(PHANDLE, name);
@ -126,6 +133,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
addShapeConfig(CONFIG_ROTATE_OFFSET, 0.0f);
addConfig(CONFIG_HW_DEBUG, false);
addConfig(CONFIG_IGNORE_WARPS, true);
addRulesConfig();
finishConfig();
@ -140,6 +148,7 @@ APICALL EXPORT PLUGIN_DESCRIPTION_INFO PLUGIN_INIT(HANDLE handle) {
g_pRenderHWCursorBufferHook = hook("renderHWCursorBuffer", "CPointerManager", (void*) &hkRenderHWCursorBuffer);
g_pSetHWCursorBufferHook = hook("setHWCursorBuffer", "CPointerManager", (void*) &hkSetHWCursorBuffer);
g_pOnCursorMovedHook = hook("onCursorMoved", "CPointerManager", (void*) &hkOnCursorMoved);
g_pMoveHook = hook("moveER", "CPointerManager", (void*) &hkMove); // this `ER` makes it faster because `move` is very generic
g_pSetCursorFromNameHook = hook("setCursorFromName", "CCursorManager", (void*) &hkSetCursorFromName);
g_pSetCursorSurfaceHook = hook("setCursorSurface", "CCursorManager", (void*) &hkSetCursorSurface);

View file

@ -11,4 +11,6 @@ class IMode {
virtual EModeUpdate strategy() = 0;
/* updates the calculations and returns the new angle */
virtual SModeResult update(Vector2D pos) = 0;
/* called on warp, an update will be sent afterwards (probably) */
virtual void warp(Vector2D old, Vector2D pos) = 0;
};

View file

@ -45,3 +45,7 @@ SModeResult CModeRotate::update(Vector2D pos) {
return result;
}
void CModeRotate::warp(Vector2D old, Vector2D pos) {
end += (pos - old);
}

View file

@ -9,6 +9,7 @@ class CModeRotate : public IMode {
public:
virtual EModeUpdate strategy();
virtual SModeResult update(Vector2D pos);
virtual void warp(Vector2D old, Vector2D pos);
private:

View file

@ -40,3 +40,10 @@ SModeResult CModeStretch::update(Vector2D pos) {
return result;
}
void CModeStretch::warp(Vector2D old, Vector2D pos) {
auto delta = pos - old;
for (auto& sample : samples)
sample += delta;
}

View file

@ -6,6 +6,7 @@ class CModeStretch : public IMode {
public:
virtual EModeUpdate strategy();
virtual SModeResult update(Vector2D pos);
virtual void warp(Vector2D old, Vector2D pos);
private:

View file

@ -30,3 +30,10 @@ SModeResult CModeTilt::update(Vector2D pos) {
result.rotation = activation(function, limit, speed) * (PI / 3); // 120° in both directions
return result;
}
void CModeTilt::warp(Vector2D old, Vector2D pos) {
auto delta = pos - old;
for (auto& sample : samples)
sample += delta;
}

View file

@ -6,6 +6,7 @@ class CModeTilt : public IMode {
public:
virtual EModeUpdate strategy();
virtual SModeResult update(Vector2D pos);
virtual void warp(Vector2D old, Vector2D pos);
private:

View file

@ -111,3 +111,10 @@ double CShake::update(Vector2D pos) {
return this->zoom.value();
}
void CShake::warp(Vector2D old, Vector2D pos) {
auto delta = pos - old;
for (auto& sample : samples)
sample += delta;
}

View file

@ -16,6 +16,8 @@ class CShake {
/* calculates the new zoom factor for the current pos */
double update(Vector2D pos);
/* called when a cursor warp has happened (to avoid magnifying on warps) */
void warp(Vector2D old, Vector2D pos);
private:
/* tracks whether the current shake has already been announced in the ipc */