Skip to content

Commit

Permalink
v1
Browse files Browse the repository at this point in the history
  • Loading branch information
SteffanDonal committed Dec 7, 2022
1 parent 9ee6363 commit 7246168
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
*.swp
*.*~
project.lock.json
.DS_Store
*.pyc
nupkg/

# Visual Studio Code
.vscode

# Rider
.idea

# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates

# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
build/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
msbuild.log
msbuild.err
msbuild.wrn

# Visual Studio 2015
.vs/
20 changes: 20 additions & 0 deletions CursorMonitorShifter.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
</PropertyGroup>

<ItemGroup>
<RuntimeHostConfigurationOption Include="Switch.System.Windows.DoNotScaleForDpiChanges" Value="false" />
</ItemGroup>

</Project>
25 changes: 25 additions & 0 deletions CursorMonitorShifter.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.3.32929.385
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CursorMonitorShifter", "CursorMonitorShifter.csproj", "{EEBDF642-B06B-4C06-B5FA-01A3B7DB6D3F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EEBDF642-B06B-4C06-B5FA-01A3B7DB6D3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEBDF642-B06B-4C06-B5FA-01A3B7DB6D3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEBDF642-B06B-4C06-B5FA-01A3B7DB6D3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EEBDF642-B06B-4C06-B5FA-01A3B7DB6D3F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {77153D49-48B4-4280-B8BF-7E03496C1978}
EndGlobalSection
EndGlobal
60 changes: 60 additions & 0 deletions Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Numerics;

if (args.Length != 1) return;

var bias = Vector2.Zero;

switch (args[0])
{
case "left":
bias.X = -1;
break;

case "up":
bias.Y = -1;
break;

case "right":
bias.X = 1;
break;

case "down":
bias.Y = 1;
break;

default: return;
}

var mouseScreen = Screen.FromPoint(Cursor.Position);
var mouseScreenCenter = mouseScreen.GetCenter();

var candidateScreens = Screen.AllScreens
.Where(screen => screen.DeviceName != mouseScreen.DeviceName)
.Select(screen => new { Offset = screen.GetCenter() - mouseScreenCenter, Screen = screen })

// Ensure we only have screens that are in the direction we care about.
.Where(candidate => bias.X == 0
? Math.Sign(candidate.Offset.Y) == Math.Sign(bias.Y)
: Math.Sign(candidate.Offset.X) == Math.Sign(bias.X))
.ToList();

// No candidates, do nothing.
if (!candidateScreens.Any()) return;

var targetScreen = candidateScreens
.OrderBy(candidate => Math.Abs(candidate.Offset.X) + Math.Abs(candidate.Offset.Y))
.First().Screen;

var normalCursorPosition =
(new Vector2(Cursor.Position.X, Cursor.Position.Y) - new Vector2(mouseScreen.Bounds.X, mouseScreen.Bounds.Y))
/ new Vector2(mouseScreen.Bounds.Width, mouseScreen.Bounds.Height);

var newCursorPosition =
new Vector2(targetScreen.Bounds.X, targetScreen.Bounds.Y)
+ normalCursorPosition * new Vector2(targetScreen.Bounds.Width, targetScreen.Bounds.Height);

var newCursorPoint = new Point((int)newCursorPosition.X, (int)newCursorPosition.Y);

// We have to set it twice because of Windows bullshit.
Cursor.Position = newCursorPoint;
Cursor.Position = newCursorPoint;
16 changes: 16 additions & 0 deletions Properties/PublishProfiles/FolderProfile.pubxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net6.0-windows\win-x64\publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
</PropertyGroup>
</Project>
8 changes: 8 additions & 0 deletions Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"CursorMonitorShifter": {
"commandName": "Project",
"commandLineArgs": "down"
}
}
}
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Cursor Monitor Shifter

Teleports your mouse cursor between your connected displays. It's meant to be used in conjunction with either keyboard shortcuts or mouse gestures, and so allows for left, up, down or right commands to control which screen the cursor will move to.

CursorMonitorShifter makes a "best guess" as to whatever display is considered "the most left/up/right/down" and moves your cursor there. If there are no displays in the direction you wish to move, nothing happens. The cursor's position on the current display is scaled to match the destination display's resolution.

## Usage

```
.\CursorMonitorShifter.exe left
.\CursorMonitorShifter.exe up
.\CursorMonitorShifter.exe right
.\CursorMonitorShifter.exe down
```

1. Download the latest release, save it somewhere you won't lose it!
2. Setup macros in your favourite tool of choice to run CursorMonitorShifter, and pass a direction as an argument.
3. Enjoy!

### Logitech Options & Logi Options+

This dumb piece of software doesn't let you pass arguments to applications when using the "Open application" action. Here's a workaround for that problem:

1. Create a number of shortcuts to CursorMonitorShifter, however many directions you care about moving.
2. Rename them too!
3. Edit each shortcut's properties, and add the direction name at the end of the `Target` field.
IE.
```
D:\Applications\Tools\CursorMonitorShifter\CursorMonitorShifter.exe up
```
4. Go into Logitech and set your "Open application" action.
5. Enter in the full path to the shortcut for the direction you're binding, **without quotes**, and **without browsing**. W11 users may use the "Copy as path" context menu option, just so long as you **remove the quotes**.
6. Repeat steps 4-5 until everything's setup as you like.
7. Enjoy!
8 changes: 8 additions & 0 deletions ScreenExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Numerics;

internal static class ScreenExtensions
{
public static Vector2 GetCenter(this Screen screen) =>
new Vector2(screen.Bounds.Location.X, screen.Bounds.Location.Y) +
new Vector2(screen.Bounds.Size.Width, screen.Bounds.Height) / 2f;
}

0 comments on commit 7246168

Please sign in to comment.