Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Lock Your Mouse Cursor to a Specific Monitor with niri

lock-your-mouse-cursor-to-a-specific-monitor-with-niri.jpg

We'll go over how to do this without using external tools. It's handy for mirroring your screen or when playing video games.

Quick Jump:

We’ll do this with a 1 line command provided by niri. Even for games it’ll work without needing to use Gamescope. It’s also quite nice if you’re giving a presentation with a laptop and you have your laptop being mirrored to another display that’s being projected.

# Understanding Your Monitors

We’ll be running a command that sets one of your displays to have a specific position. Here’s my current monitor set up so you can see how the commands relate to that so you can adjust things for your set up.

// Set external display as the left monitor and have it get used as my main.
// This is a 3840 x 2160 monitor.
output "DP-1" {
    position x=0 y=0
    scale 1.0
    focus-at-startup
}

// Set external display to the right of the above 4k main monitor.
// This is a 2560 x 1440 monitor.
output "HDMI-A-2" {
    position x=3840 y=0
    scale 1.0
}

This is a typical side by side dual monitor set up.

# How to Lock Your Mouse to a Monitor

All of this is thanks to niri not allowing position gaps between your outputs. If a gap is detected, it will lock your mouse to the current / focused monitor.

The general strategy is to set a position that’s bigger than your monitor’s resolution. Feel free to adjust the commands below by adjusting the name and pixel values. If you have vertically oriented monitors you can set the first value to 0 (X) and set the 2nd value (Y) to a value that makes sense for what you’re doing.

The reason we use -- to split up the arguments below is only necessary to support negative values, otherwise niri will think -3840 is a flag. I wanted to include this syntax in case your set up needs negative numbers.

# Create no lock on my primary monitor.
# This is the default set up based on the above config.
niri msg output HDMI-A-2 position set -- 3840 0

# Create a hard lock on my primary 4k monitor.
# This creates a stone wall where the mouse cannot pass the right edge.
niri msg output HDMI-A-2 position set -- 9999 0

# Create a soft lock on my primary 4k monitor.
# This allows passing over but only if I move my mouse a little fast. The idea
# is to set 40, 60 or even 100 pixels more than your resolution, the higher
# the pixel amount the faster you need to move your mouse to jump over.
niri msg output HDMI-A-2 position set -- 3900 0

The nice thing about this is it also supports scaling. For example I record my videos at 300% scale so the font size is readable on video. Instead of using 3840 as the base I use 1280 which is 3840 / 3. Everything “just works”.

# General Purpose Toggle Script with niri Key Binds

We can go the extra mile and have a script you can call without any configuration, such as:

  • output-toggle-mouse-lock
  • output-toggle-mouse-lock --soft

It detects your focused output and then sets every other output to either 9999 or a relative +/- 60 pixels depending on your monitors’ orientation. It can acts as a toggle so it’s easy to use.

It also supports DEBUG=1 to show you the raw niri commands being run in case you need to troubleshoot it and it uses notify-send so you know the current status at a glance.

Here’s the niri key binds for both styles of locking:

Mod+Ctrl+M       hotkey-overlay-title="Toggle output mouse hard lock" { spawn "output-toggle-mouse-lock"; }
Mod+Ctrl+Shift+M hotkey-overlay-title="Toggle output mouse soft lock" { spawn "output-toggle-mouse-lock" "--soft"; }

If you’re using DotFriedRice you already have access to all of this. Here’s the script. The only dependency is jq since we need to parse niri msg commands in JSON.

I did the best I could to test multiple orientations with my dual monitor set up and it worked. I put DP-1 to the left and right of HDMI-A-2 as well as putting HDMI-A-2 above and below DP-1. I don’t have a third monitor to test.

The video below shows everything above.

# Demo Video

Timestamps

  • 0:34 – Identifying your monitors and positions
  • 1:22 – Taking a look at the command to run
  • 1:42 – Finding your outputs
  • 2:04 – Setting an unreachable position
  • 2:40 – Going back to normal
  • 3:01 – Creating a soft lock that’s velocity based
  • 4:17 – General purpose toggle script
  • 5:54 – Quick drive by of the script
  • 6:33 – The state file to keep track of your monitors
  • 7:39 – Toggling the script with a niri key bind

Will you be using this? Let me know below.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per year (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments