Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BrickController Windows application - experimental #116

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions BrickController2.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BrickController2.iOS", "Bri
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BrickController2", "BrickController2\BrickController2\BrickController2.csproj", "{852D9034-471A-42D0-8701-63D12E2EDACA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BrickController2.WinUI", "BrickController2\BrickController2.WinUI\BrickController2.WinUI.csproj", "{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
Expand All @@ -23,32 +27,66 @@ Global
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|ARM64.Build.0 = Debug|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|ARM64.Deploy.0 = Debug|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|x64.ActiveCfg = Debug|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|x64.Build.0 = Debug|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Debug|x64.Deploy.0 = Debug|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|Any CPU.Build.0 = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|Any CPU.Deploy.0 = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|ARM64.ActiveCfg = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|ARM64.Build.0 = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|ARM64.Deploy.0 = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|x64.ActiveCfg = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|x64.Build.0 = Release|Any CPU
{A82CFFAA-423D-473B-820C-174F7AE48B7E}.Release|x64.Deploy.0 = Release|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|ARM64.ActiveCfg = Debug|ARM64
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|ARM64.Build.0 = Debug|ARM64
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|ARM64.Deploy.0 = Debug|ARM64
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|x64.ActiveCfg = Debug|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|x64.Build.0 = Debug|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Debug|x64.Deploy.0 = Debug|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|Any CPU.Build.0 = Release|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|Any CPU.Deploy.0 = Release|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|ARM64.ActiveCfg = Release|ARM64
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|ARM64.Build.0 = Release|ARM64
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|ARM64.Deploy.0 = Release|ARM64
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|x64.ActiveCfg = Release|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|x64.Build.0 = Release|Any CPU
{E52D9D91-6F31-42E2-8261-D85AA62D39D1}.Release|x64.Deploy.0 = Release|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Debug|ARM64.Build.0 = Debug|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Debug|x64.ActiveCfg = Debug|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Debug|x64.Build.0 = Debug|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Release|Any CPU.Build.0 = Release|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Release|ARM64.ActiveCfg = Release|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Release|ARM64.Build.0 = Release|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Release|x64.ActiveCfg = Release|Any CPU
{852D9034-471A-42D0-8701-63D12E2EDACA}.Release|x64.Build.0 = Release|Any CPU
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|Any CPU.ActiveCfg = Debug|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|Any CPU.Build.0 = Debug|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|Any CPU.Deploy.0 = Debug|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|ARM64.ActiveCfg = Debug|ARM64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|ARM64.Build.0 = Debug|ARM64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|ARM64.Deploy.0 = Debug|ARM64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|x64.ActiveCfg = Debug|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|x64.Build.0 = Debug|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Debug|x64.Deploy.0 = Debug|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|Any CPU.ActiveCfg = Release|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|Any CPU.Build.0 = Release|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|Any CPU.Deploy.0 = Release|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|ARM64.ActiveCfg = Release|ARM64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|ARM64.Build.0 = Release|ARM64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|ARM64.Deploy.0 = Release|ARM64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|x64.ActiveCfg = Release|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|x64.Build.0 = Release|x64
{47060ECF-9DBD-424B-8CB7-0B0578DB6D7A}.Release|x64.Deploy.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
18 changes: 18 additions & 0 deletions BrickController2/BrickController2.WinUI/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<maui:MauiWinUIApplication
x:Class="BrickController2.Windows.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:maui="using:Microsoft.Maui"
xmlns:local="using:BrickController2.Windows" >
<maui:MauiWinUIApplication.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>
</maui:MauiWinUIApplication.Resources>
</maui:MauiWinUIApplication>


60 changes: 60 additions & 0 deletions BrickController2/BrickController2.WinUI/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Autofac;
using Autofac.Extensions.DependencyInjection;
using BrickController2.BusinessLogic.DI;
using BrickController2.CreationManagement.DI;
using BrickController2.Database.DI;
using BrickController2.DeviceManagement.DI;
using BrickController2.UI.Controls;
using BrickController2.UI.DI;
using BrickController2.UI.Pages;
using BrickController2.Windows.PlatformServices.DI;
using BrickController2.Windows.UI.CustomHandlers;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Hosting;
using Windows.Devices.Input;

namespace BrickController2.Windows;

/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : MauiWinUIApplication
{
public App()
{
InitializeComponent();
}
protected override MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<BrickController2.App>()
.ConfigureMauiHandlers(handlers =>
{
handlers
.AddHandler<ExtendedSlider, ExtendedSliderHandler>()
.AddHandler<PageBase, CustomPageHandler>()
;

// handle swipe if there is no touch screen
var capablitities = new TouchCapabilities();
if (capablitities.TouchPresent == 0)
{
handlers.AddHandler<SwipeView, CustomSwipeViewHandler>();
}
})
.ConfigureContainer(new AutofacServiceProviderFactory(), autofacBuilder =>
{
autofacBuilder.RegisterModule<PlatformServicesModule>();
autofacBuilder.RegisterModule<BusinessLogicModule>();
autofacBuilder.RegisterModule<DatabaseModule>();
autofacBuilder.RegisterModule<CreationManagementModule>();
autofacBuilder.RegisterModule<DeviceManagementModule>();
autofacBuilder.RegisterModule<UiModule>();
});

return builder.Build();
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<Platforms>x64;ARM64</Platforms>
<RuntimeIdentifiers>win10-x64;win10-arm64</RuntimeIdentifiers>
<PublishProfile>win10-$(Platform).pubxml</PublishProfile>

<ApplicationManifest>app.manifest</ApplicationManifest>
<RootNamespace>BrickController2.Windows</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>

<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<!-- We do not want XAML files to be processed as .NET MAUI XAML -->
<EnableDefaultMauiItems>false</EnableDefaultMauiItems>

</PropertyGroup>

<ItemGroup>
<PackageReference Include="Autofac" />
<PackageReference Include="Autofac.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Maui.Controls" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BrickController2\BrickController2.csproj" />
</ItemGroup>

<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>

<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Windows.Devices.Bluetooth.Advertisement;

namespace BrickController2.Windows.Extensions;

public static class AdvertismentExtensions
{
public static string GetLocalName(this BluetoothLEAdvertisementReceivedEventArgs args) => args.Advertisement.LocalName.TrimEnd();

public static bool IsValidDeviceName(this string deviceName) => !string.IsNullOrEmpty(deviceName);

public static bool CanCarryData(this BluetoothLEAdvertisementReceivedEventArgs args) =>
args.AdvertisementType == BluetoothLEAdvertisementType.ScanResponse ||
args.AdvertisementType == BluetoothLEAdvertisementType.ConnectableUndirected;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Windows.Gaming.Input;

namespace BrickController2.Windows.Extensions;

public static class ControllerExtensions
{
public static string GetDeviceId(this Gamepad gamepad) =>
// kinda hack
gamepad.User.NonRoamableId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
namespace BrickController2.Windows.Extensions;

public static class ConvertExtensions
{
public static string ToBluetoothAddressString(this ulong bluetoothAddress)
{
// 48bit physical BT address
var a = (byte)((bluetoothAddress >> 40) & 0xFF);
var b = (byte)((bluetoothAddress >> 32) & 0xFF);
var c = (byte)((bluetoothAddress >> 24) & 0xFF);
var d = (byte)((bluetoothAddress >> 16) & 0xFF);
var e = (byte)((bluetoothAddress >> 8) & 0xFF);
var f = (byte)(bluetoothAddress & 0xFF);

return $"{a:X2}:{b:X2}:{c:X2}:{d:X2}:{e:X2}:{f:X2}";
}

public static bool TryParseBluetoothAddressString(this string stringValue, out ulong bluetoothAddress)
{
bluetoothAddress = default;

if (string.IsNullOrEmpty(stringValue) || stringValue.Length != 17)
{
return false;
}

ulong value = 0;

for (int i = 1; i <= stringValue.Length; i++)
{
var ch = (uint)stringValue[i - 1];
if (i % 3 == 0)
{
if (ch != '-' && ch != ':')
{
// missing dash
return false;
}
}
else if (ch >= 0x30 && ch <= 0x39)
{
value = (value << 4) + ch - 0x30;
}
else if (ch >= 0x41 && ch <= 0x46)
{
value = (value << 4) + ch - 0x37;
}
else
{
// wrong character
return false;
}
}

bluetoothAddress = value;
return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using BrickController2.PlatformServices.GameController;
using System;
using System.Collections.Generic;
using Windows.Gaming.Input;

namespace BrickController2.Windows.Extensions;

internal static class GamepadReadingExtenions
{
public const float Zero = 0.0f;
public const float Positive = 1.0f;
public const float Negative = -1.0f;

public const float Delta = 0.05f;
public const float Limit = Positive - Delta;

public static IEnumerable<(string Name, GameControllerEventType EventType, float Value)> Enumerate(this GamepadReading readings)
{
// native axes
yield return GetAxis("X", readings.LeftThumbstickX, Positive);
yield return GetAxis("Y", readings.LeftThumbstickY, Negative);
yield return GetAxis("Brake", readings.LeftTrigger, Positive);
yield return GetAxis("Z", readings.RightThumbstickX, Positive);
yield return GetAxis("Rz", readings.RightThumbstickY, Negative);
yield return GetAxis("Gas", readings.RightTrigger, Positive);

// buttons treated as axis
yield return GetHybridButton(readings, GamepadButtons.DPadDown, GamepadButtons.DPadUp, "HatY");
yield return GetHybridButton(readings, GamepadButtons.DPadRight, GamepadButtons.DPadLeft, "HatX");

// get buttons
yield return GetButton(readings, GamepadButtons.A, "ButtonA");
yield return GetButton(readings, GamepadButtons.B, "ButtonB");
yield return GetButton(readings, GamepadButtons.X, "ButtonX");
yield return GetButton(readings, GamepadButtons.Y, "ButtonY");
yield return GetButton(readings, GamepadButtons.LeftShoulder, "ButtonL1");
yield return GetButton(readings, GamepadButtons.RightShoulder, "ButtonR1");
yield return GetButton(readings, GamepadButtons.Menu, "ButtonStart");
yield return GetButton(readings, GamepadButtons.View, "ButtonSelect");
yield return GetButton(readings, GamepadButtons.LeftThumbstick, "ButtonThumbl");
yield return GetButton(readings, GamepadButtons.RightThumbstick, "ButtonThumbr");

// TODO Home button - 0x40000000

//TODO
// GamepadButtons.Paddle1
// GamepadButtons.Paddle2
// GamepadButtons.Paddle3
// GamepadButtons.Paddle4
}

private static (string Name, GameControllerEventType Type, float value) GetHybridButton(this GamepadReading readings, GamepadButtons button, GamepadButtons opositeButton, string name)
{
// get primary button
if (readings.Buttons.HasFlag(button))
{
return new(name, GameControllerEventType.Axis, Positive);
}
if (readings.Buttons.HasFlag(opositeButton))
{
return new(name, GameControllerEventType.Axis, Negative);
}
return new(name, GameControllerEventType.Axis, Zero);
}

private static (string Name, GameControllerEventType Type, float value) GetButton(this GamepadReading readings, GamepadButtons button, string name)
{
// get primary button
if (readings.Buttons.HasFlag(button))
{
return new(name, GameControllerEventType.Button, Positive);
}
return new(name, GameControllerEventType.Button, Zero);
}

private static (string Name, GameControllerEventType Type, float value) GetAxis(string name, double value, float maxValue)
{
if (Math.Abs(value) < Delta)
{
return (name, GameControllerEventType.Axis, Zero);
}
if (value > 0.95)
{
return (name, GameControllerEventType.Axis, maxValue);
}
if (value < -0.95)
{
return (name, GameControllerEventType.Axis, -maxValue);
}
return (name, GameControllerEventType.Axis, maxValue * (float)value);
}
}
Loading