diff --git a/BUILD.md b/BUILD.md
new file mode 100644
index 00000000..2dfa3ebe
--- /dev/null
+++ b/BUILD.md
@@ -0,0 +1,115 @@
+# Building LittleBigMouse
+
+LittleBigMouse is a mixed .NET and native Windows project. The main UI is an
+Avalonia .NET application, and the mouse hook is a native C++ executable.
+
+## Prerequisites
+
+- Windows 10 or Windows 11, x64
+- Git
+- Visual Studio 2022, or Visual Studio Build Tools 2022
+- .NET 8 SDK, or a newer .NET SDK that can build `net8.0` projects
+- Visual Studio workloads/components:
+ - `.NET desktop development`
+ - `Desktop development with C++`
+ - MSVC v143 C++ build tools
+ - Windows 10 or Windows 11 SDK
+
+## Clone
+
+Clone the repository with submodules:
+
+```powershell
+git clone --recurse-submodules https://github.com/thomcuddihy/LittleBigMouse.git
+cd LittleBigMouse
+```
+
+If the repository was cloned without submodules, initialize them before
+building:
+
+```powershell
+git submodule update --init --recursive
+```
+
+## Build With Visual Studio
+
+1. Open `LittleBigMouse.sln` in Visual Studio 2022.
+2. Select the `Release` configuration and `x64` platform.
+3. Restore NuGet packages when Visual Studio prompts, or run `Restore NuGet Packages`.
+4. Build `LittleBigMouse.Hook`.
+5. Build `LittleBigMouse.Ui.Avalonia`.
+
+The primary development output is:
+
+```text
+LittleBigMouse.Ui\LittleBigMouse.Ui.Avalonia\bin\x64\Release\net8.0\LittleBigMouse.Ui.Avalonia.exe
+```
+
+The native hook output is:
+
+```text
+LittleBigMouse.Hook\bin\x64\Release\LittleBigMouse.Hook.exe
+```
+
+When running from the repository build folders, the UI locates the hook from the
+native project output path. If the UI starts but the hook does not, make sure
+`LittleBigMouse.Hook.exe` was built for the same configuration and platform.
+
+## Build From The Command Line
+
+Use a **Developer PowerShell for VS 2022** or **x64 Native Tools Command Prompt
+for VS 2022** so that MSBuild can find the Visual C++ toolchain and Windows SDK.
+
+Restore the .NET dependencies:
+
+```powershell
+dotnet restore LittleBigMouse.Ui\LittleBigMouse.Ui.Avalonia\LittleBigMouse.Ui.Avalonia.csproj
+```
+
+Build the native hook:
+
+```powershell
+msbuild LittleBigMouse.Hook\LittleBigMouse.Hook.vcxproj /m /p:Configuration=Release /p:Platform=x64
+```
+
+Build the Avalonia UI:
+
+```powershell
+dotnet build LittleBigMouse.Ui\LittleBigMouse.Ui.Avalonia\LittleBigMouse.Ui.Avalonia.csproj -c Release -p:Platform=x64 --no-restore
+```
+
+Run the app from:
+
+```powershell
+.\LittleBigMouse.Ui\LittleBigMouse.Ui.Avalonia\bin\x64\Release\net8.0\LittleBigMouse.Ui.Avalonia.exe
+```
+
+## Full Solution Builds
+
+Visual Studio can build the full solution when all optional project requirements
+are installed. For command-line builds, the two-step build above is the
+recommended path for producing the runnable application because it avoids mixing
+the native C++ project and SDK-style .NET projects through a single MSBuild
+invocation.
+
+If your command-line environment can resolve both Visual C++ and .NET SDK
+targets, a full solution build can be attempted with:
+
+```powershell
+msbuild LittleBigMouse.sln /restore /m /p:Configuration=Release /p:Platform=x64
+```
+
+## Troubleshooting
+
+- `Microsoft.Cpp.Default.props` is missing: install the Visual Studio C++
+ workload and run the build from a Visual Studio developer shell.
+- `The SDK 'Microsoft.NET.Sdk' specified could not be found`: install the .NET 8
+ SDK and confirm `dotnet --info` works in the current shell.
+- Output DLLs cannot be copied because they are in use: close
+ `LittleBigMouse.Ui.Avalonia.exe` and `LittleBigMouse.Hook.exe`, then rebuild.
+- The UI opens but the hook does not start: build `LittleBigMouse.Hook` for
+ `Release|x64` and confirm the hook executable exists in
+ `LittleBigMouse.Hook\bin\x64\Release`.
+- NuGet vulnerability warnings may appear during restore/build. These warnings
+ do not necessarily block compilation, but should be reviewed before shipping a
+ release.
diff --git a/HLab.Avalonia b/HLab.Avalonia
index cc49b761..fa652f24 160000
--- a/HLab.Avalonia
+++ b/HLab.Avalonia
@@ -1 +1 @@
-Subproject commit cc49b761c4a86b39b428ea5fd0f1c9a803182502
+Subproject commit fa652f2428d68fc6632d231dcf4ff995a8fdd998
diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj
index 41fbfe3d..a6c5dae3 100644
--- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj
+++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/LittleBigMouse.DisplayLayout.csproj
@@ -5,7 +5,7 @@
x64;x86;AnyCpu
Library
Debug;Release;ReleaseDebug
- 5.2.4.0
+ 5.2.6.0
diff --git a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs
index f9472721..905c8ed0 100644
--- a/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs
+++ b/LittleBigMouse.Core/LittleBigMouse.DisplayLayout/Monitors/Extensions/ZonesLayoutFactory.cs
@@ -46,8 +46,6 @@ public static ZonesLayout ComputeZones(this IMonitorsLayout layout)
}
}
- zones.Init();
-
zones.MaxTravelDistance = layout.Options.MaxTravelDistance;
zones.AdjustPointer = layout.Options.AdjustPointer;
@@ -60,7 +58,9 @@ public static ZonesLayout ComputeZones(this IMonitorsLayout layout)
zones.LoopX = layout.Options.LoopX;
zones.LoopY = layout.Options.LoopY;
+ zones.Init();
+
return zones;
}
-}
\ No newline at end of file
+}
diff --git a/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj b/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj
index af2cfa9d..e9ca9cea 100644
--- a/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj
+++ b/LittleBigMouse.Core/LittleBigMouse.Zones/LittleBigMouse.Zoning.csproj
@@ -5,7 +5,7 @@
enable
enable
AnyCPU;x64;x86
- 5.2.4.0
+ 5.2.6.0
diff --git a/LittleBigMouse.Hook/Engine/Zone.cpp b/LittleBigMouse.Hook/Engine/Zone.cpp
index 3efdb30c..2c76fa14 100644
--- a/LittleBigMouse.Hook/Engine/Zone.cpp
+++ b/LittleBigMouse.Hook/Engine/Zone.cpp
@@ -62,7 +62,7 @@ bool Zone::Contains(const geo::Point& mm) const
geo::Point Zone::InsidePixelsBounds(const geo::Point px) const
{
auto x = px.X();
- auto y = px.X();
+ auto y = px.Y();
if (x < _pixelsBounds.Left()) x = _pixelsBounds.Left();
else if (x > _pixelsBounds.Right() - 1) x = _pixelsBounds.Right() - 1;
@@ -155,7 +155,7 @@ std::vector> Reachable(const geo::Rect& source, const geo:
if(top >= bottom)
{
- auto start = geo::Rect(left, source.Top(), right, source.Height());
+ auto start = geo::Rect(left, source.Top(), right - left, source.Height());
auto dest = geo::Rect(left, target.Top(), right - left, target.Height());
return {start,dest};
}
diff --git a/LittleBigMouse.Hook/Engine/ZoneLink.h b/LittleBigMouse.Hook/Engine/ZoneLink.h
index 6bc12429..8b82690c 100644
--- a/LittleBigMouse.Hook/Engine/ZoneLink.h
+++ b/LittleBigMouse.Hook/Engine/ZoneLink.h
@@ -18,7 +18,7 @@ class ZoneLink
long TargetToPixel;
double BorderResistance;
- long BorderResistancePixel;
+ long BorderResistancePixel = 0;
//long SourceLengthPixel;
//long TargetLengthPixel;
diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj
index 76a4b690..b19e3c0a 100644
--- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj
+++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Layout.Avalonia/LittleBigMouse.Plugin.Layout.Avalonia.csproj
@@ -7,7 +7,7 @@
x64;x86;AnyCpu
true
preview
- 5.2.4.0
+ 5.2.6.0
diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj
index def3d1ae..6a353c11 100644
--- a/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj
+++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/LittleBigMouse.Plugin.Vcp.Avalonia.csproj
@@ -7,7 +7,7 @@
AnyCPU;x64;x86
preview
true
- 5.2.4.0
+ 5.2.6.0
diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Avalonia/LittleBigMouse.Plugins.Avalonia.csproj b/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Avalonia/LittleBigMouse.Plugins.Avalonia.csproj
index 9848f862..c01d4282 100644
--- a/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Avalonia/LittleBigMouse.Plugins.Avalonia.csproj
+++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Avalonia/LittleBigMouse.Plugins.Avalonia.csproj
@@ -4,7 +4,7 @@
net8.0
enable
x64;x86;AnyCpu
- 5.2.4.0
+ 5.2.6.0
true
diff --git a/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Core/LittleBigMouse.Plugins.csproj b/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Core/LittleBigMouse.Plugins.csproj
index 5f1d7578..75bf62f6 100644
--- a/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Core/LittleBigMouse.Plugins.csproj
+++ b/LittleBigMouse.Plugins/LittleBigMouse.Plugins.Core/LittleBigMouse.Plugins.csproj
@@ -5,7 +5,7 @@
enable
enable
x64;x86;AnyCpu
- 5.2.4.0
+ 5.2.6.0
diff --git a/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/LittleBigMouse.Ui.Avalonia.csproj b/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/LittleBigMouse.Ui.Avalonia.csproj
index 53824ca7..5d8bc24f 100644
--- a/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/LittleBigMouse.Ui.Avalonia.csproj
+++ b/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/LittleBigMouse.Ui.Avalonia.csproj
@@ -12,7 +12,7 @@
lbm.png
README.md
https://github.com/mgth/LittleBigMouse
- 5.2.4.0
+ 5.2.6.0
app.manifest
LittleBigMouse.Ui.Avalonia.Program
Little Big Mouse
diff --git a/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/Remote/LittleBigMouseClientService.cs b/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/Remote/LittleBigMouseClientService.cs
index fc781209..bdd56bfa 100644
--- a/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/Remote/LittleBigMouseClientService.cs
+++ b/LittleBigMouse.Ui/LittleBigMouse.Ui.Avalonia/Remote/LittleBigMouseClientService.cs
@@ -67,6 +67,7 @@ public LittleBigMouseClientService(ILayoutOptions options)
OnStateChanged(LittleBigMouseEvent.Connected);
};
+ LaunchDaemon();
_client.Listen();
}
@@ -96,7 +97,16 @@ public Task StartAsync(ZonesLayout zonesLayout, CancellationToken token = defaul
void CreateExcludedFile()
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
- var file = Path.Combine(path,"Mgth","LittleBigMouse","Excluded.txt");
+ var directory = Path.Combine(path,"Mgth","LittleBigMouse");
+ Directory.CreateDirectory(directory);
+
+ var file = Path.Combine(directory,"Excluded.txt");
+ if (Directory.Exists(file))
+ {
+ Debug.WriteLine($"Excluded path is a directory, skipping file setup : {file}");
+ return;
+ }
+
if(File.Exists(file))
{
// Riot games -> Riot Games (was misspelled in 5.0.4.0) TODO : remove in a version or two
@@ -128,18 +138,29 @@ public void LaunchDaemon()
}
var path = Assembly.GetEntryAssembly()?.Location;
- if (path is null) return;
+ if (path is null)
+ {
+ Debug.WriteLine("Unable to resolve entry assembly path for daemon launch");
+ return;
+ }
if (path.Contains(@"\bin\"))
{
// .\LittleBigMouse.Ui.Avalonia\bin\x64\Debug\net8.0\LittleBigMouse.Ui.Avalonia.dll
- // .\x64\Debug\LittleBigMouse.Hook.exe
+ // .\LittleBigMouse.Hook\bin\x64\Debug\LittleBigMouse.Hook.exe
path = path.Replace(@"\LittleBigMouse.Ui\LittleBigMouse.Ui.Avalonia\", @"\LittleBigMouse.Hook\");
path = path.Replace(@"\net8.0\", @"\");
}
- path = path.Replace(@"\LittleBigMouse.Ui.Avalonia.dll", @"\LittleBigMouse.Hook.exe");
+ var directory = Path.GetDirectoryName(path);
+ if (directory is null)
+ {
+ Debug.WriteLine($"Hook directory is null for path : {path}");
+ return;
+ }
+
+ path = Path.Combine(directory, "LittleBigMouse.Hook.exe");
if (!File.Exists(path))
{
@@ -147,13 +168,21 @@ public void LaunchDaemon()
return;
}
- CreateExcludedFile();
+ try
+ {
+ CreateExcludedFile();
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Failed to create excluded file : {ex}");
+ }
try
{
var startInfo = new ProcessStartInfo
{
FileName = path,
+ WorkingDirectory = directory,
//RedirectStandardOutput = true,
//RedirectStandardError = true,
@@ -175,9 +204,9 @@ public void LaunchDaemon()
Debug.WriteLine($"Started : {process.ProcessName} {process.Id}");
}
- catch (ExecutionEngineException ex)
+ catch (Exception ex)
{
-
+ Debug.WriteLine($"Failed to start daemon : {path} : {ex}");
}
}
@@ -230,4 +259,4 @@ async Task SendMessagesAsync(IEnumerable messages, CancellationT
[GeneratedRegex("(.*)")]
private static partial Regex PayloadRegex();
-}
\ No newline at end of file
+}
diff --git a/LittleBigMouse.Ui/LittleBigMouse.Ui.Core/LittleBigMouse.Ui.Core.csproj b/LittleBigMouse.Ui/LittleBigMouse.Ui.Core/LittleBigMouse.Ui.Core.csproj
index 574f8238..7e7e121b 100644
--- a/LittleBigMouse.Ui/LittleBigMouse.Ui.Core/LittleBigMouse.Ui.Core.csproj
+++ b/LittleBigMouse.Ui/LittleBigMouse.Ui.Core/LittleBigMouse.Ui.Core.csproj
@@ -6,7 +6,7 @@
enable
x64;x86;AnyCpu
preview
- 5.2.4.0
+ 5.2.6.0