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