Skip to content

Commit

Permalink
Add mouse and keyboard visualisation
Browse files Browse the repository at this point in the history
  • Loading branch information
csutorasa committed Nov 7, 2023
1 parent 59271f8 commit 9d709e7
Show file tree
Hide file tree
Showing 14 changed files with 249 additions and 9 deletions.
4 changes: 3 additions & 1 deletion XOutput.App/Resources/Translations/English.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"Language": "Language",
"ServerUrl": "Server URL",
"AutoConnect": "Connect to server on start",
"Connect": "Connect"
"Connect": "Connect",
"InvalidUriConnectionError": "Invalid address",
"FailedToConnectToServerError": "Failed to connect to server"
},
"WindowsApiMouse": {
"Title": "Windows API mouse",
Expand Down
4 changes: 3 additions & 1 deletion XOutput.App/Resources/Translations/Hungarian.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"Language": "Nyelv",
"ServerUrl": "Server címe",
"AutoConnect": "Kapcsolódás a szerverhez induláskor",
"Connect": "Kapcsolódás"
"Connect": "Kapcsolódás",
"InvalidUriConnectionError": "Érvénytelen cím",
"FailedToConnectToServerError": "Nem sikerült kapcsolódni a szerverhez"
},
"WindowsApiMouse": {
"Title": "Windows API egér",
Expand Down
6 changes: 3 additions & 3 deletions XOutput.App/UI/Component/Titled.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

namespace XOutput.App.UI.Component
{
[ContentPropertyAttribute("Control")]
[ContentProperty("Control")]
public partial class Titled : UserControl
{
public readonly static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(TitleProperty), typeof(string), typeof(Titled));
public readonly static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Titled));
public string Title
{
get => GetValue(TitleProperty) as string;
set { SetValue(TitleProperty, value); }
}
public readonly static DependencyProperty ControlProperty = DependencyProperty.Register(nameof(ControlProperty), typeof(FrameworkElement), typeof(Titled));
public readonly static DependencyProperty ControlProperty = DependencyProperty.Register(nameof(Control), typeof(FrameworkElement), typeof(Titled));
public FrameworkElement Control
{
get => GetValue(ControlProperty) as FrameworkElement;
Expand Down
13 changes: 13 additions & 0 deletions XOutput.App/UI/Converter/DynamicTranslationConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@

namespace XOutput.App.UI.Converter
{
/// <summary>
/// Converts a text based on the language, and updates when the language changes.
/// </summary>
/// <example>
/// <TextBlock>
/// <TextBlock.Text>
/// <MultiBinding Converter="{StaticResource DynamicTranslator}">
/// <Binding Path="Translation.Language" />
/// <Binding Path="Model.DynamicField" />
/// </MultiBinding>
/// </TextBox.Text>
/// </TextBox>
/// </example>
public class DynamicTranslationConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
Expand Down
6 changes: 6 additions & 0 deletions XOutput.App/UI/Converter/TranslationConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@

namespace XOutput.App.UI.Converter
{
/// <summary>
/// Converts a text based on the language, and updates when the language changes.
/// </summary>
/// <example>
/// <TextBlock Text="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='Test.Key' />
/// </example>
public class TranslationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
Expand Down
9 changes: 9 additions & 0 deletions XOutput.App/UI/View/GeneralPanel.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='General.AutoConnect'}"/>
<Button Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='General.Connect'}"
HorizontalAlignment="Left" Click="Connect_Click" Width="150"/>
<TextBlock HorizontalAlignment="Left" Width="250">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource DynamicTranslator}">
<Binding Path="Translation.Language" />
<Binding Path="Model.ConnectionErrorMessage" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Text="{Binding Model.ServerVersion}" HorizontalAlignment="Left" Width="250"/>
</StackPanel>
</component:Titled>
</StackPanel>
Expand Down
28 changes: 28 additions & 0 deletions XOutput.App/UI/View/GeneralPanelModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ public string SelectedLanguage
}
}

private string connectionErrorMessage;
public string ConnectionErrorMessage
{
get => connectionErrorMessage;
set
{
if (connectionErrorMessage != value)
{
connectionErrorMessage = value;
OnPropertyChanged(nameof(ConnectionErrorMessage));
}
}
}

private string serverUrl;
public string ServerUrl
{
Expand All @@ -36,6 +50,20 @@ public string ServerUrl
}
}

private string serverVersion;
public string ServerVersion
{
get => serverVersion;
set
{
if (serverVersion != value)
{
serverVersion = value;
OnPropertyChanged(nameof(ServerVersion));
}
}
}

private bool autoConnect;
public bool AutoConnect
{
Expand Down
25 changes: 23 additions & 2 deletions XOutput.App/UI/View/GeneralPanelViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows;
using XOutput.App.Configuration;
using XOutput.Configuration;
using XOutput.DependencyInjection;
Expand Down Expand Up @@ -47,8 +48,28 @@ private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)

public async Task Connect()
{
var uri = new Uri($"http://{Model.ServerUrl}/api/");
var x = await new InfoClient(new StaticHttpClientProvider(uri)).GetInfoAsync();
Model.ConnectionErrorMessage = "";
Model.ServerVersion = "";
Uri uri;
try
{
uri = new Uri($"http://{Model.ServerUrl}/api/");
}
catch (UriFormatException)
{
Model.ConnectionErrorMessage = "General.InvalidUriConnectionError";
return;
}
try
{
var info = await new InfoClient(new StaticHttpClientProvider(uri)).GetInfoAsync();
Model.ServerVersion = info.Version;
}
catch
{
Model.ConnectionErrorMessage = "General.FailedToConnectToServerError";
return;
}
var appConfig = GetAppConfig();
appConfig.AutoConnect = Model.AutoConnect;
appConfig.ServerUrl = Model.ServerUrl;
Expand Down
14 changes: 14 additions & 0 deletions XOutput.App/UI/View/WindowsApiKeyboardPanel.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,19 @@
<StackPanel>
<TextBlock Text="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiKeyboard.Title'}" Margin="5"/>
<CheckBox Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiKeyboard.Enabled'}" IsChecked="{Binding Model.Enabled}" Margin="5"/>
<ItemsControl ItemsSource="{Binding Model.PressedButtons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="LightGray" BorderBrush="Black">
<TextBlock Text="{Binding}" Margin="3" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
7 changes: 6 additions & 1 deletion XOutput.App/UI/View/WindowsApiKeyboardPanelModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using XOutput.DependencyInjection;
using System.Collections.ObjectModel;
using XOutput.App.Devices.Input.Keyboard;
using XOutput.DependencyInjection;

namespace XOutput.App.UI.View
{
Expand All @@ -18,6 +20,9 @@ public bool Enabled
}
}

private readonly ObservableCollection<KeyboardButton> pressedButtons = new ObservableCollection<KeyboardButton>();
public ObservableCollection<KeyboardButton> PressedButtons => pressedButtons;

[ResolverMethod]
public WindowsApiKeyboardPanelModel()
{
Expand Down
23 changes: 23 additions & 0 deletions XOutput.App/UI/View/WindowsApiKeyboardPanelViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.ComponentModel;
using System.Linq;
using System.Windows.Threading;
using XOutput.App.Devices.Input;
using XOutput.App.Devices.Input.Keyboard;
using XOutput.DependencyInjection;

Expand All @@ -14,6 +17,8 @@ public WindowsApiKeyboardPanelViewModel(WindowsApiKeyboardPanelModel model, Keyb
this.keyboardDeviceProvider = keyboardDeviceProvider;
Model.Enabled = keyboardDeviceProvider.Enabled;
Model.PropertyChanged += Model_PropertyChanged;
var keyboardDevice = keyboardDeviceProvider.GetActiveDevices().First() as KeyboardDevice;
keyboardDevice.InputChanged += KeyboardDevice_InputChanged;
}

private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
Expand All @@ -23,5 +28,23 @@ private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
keyboardDeviceProvider.Enabled = Model.Enabled;
}
}
private void KeyboardDevice_InputChanged(object sender, DeviceInputChangedEventArgs e)
{
App.Current.Dispatcher.Invoke(() => {
foreach (var source in e.ChangedValues)
{
var keyboardButton = (KeyboardButton) source.Offset;
bool pressed = source.GetValue() > 0.5;
if (pressed && !Model.PressedButtons.Contains(keyboardButton))
{
Model.PressedButtons.Add(keyboardButton);
}
if (!pressed && Model.PressedButtons.Contains(keyboardButton))
{
Model.PressedButtons.Remove(keyboardButton);
}
}
});
}
}
}
16 changes: 16 additions & 0 deletions XOutput.App/UI/View/WindowsApiMousePanel.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,26 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:XOutput.App.UI.View"
xmlns:component="clr-namespace:XOutput.App.UI.Component"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:WindowsApiMousePanelViewModel, IsDesignTimeCreatable=False}">
<StackPanel>
<TextBlock Text="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiMouse.Title'}" Margin="5"/>
<CheckBox Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiMouse.Enabled'}" IsChecked="{Binding Model.Enabled}" Margin="5"/>

<Grid>
<Path Stroke="Black" Fill="LightGray" Data="M 30,150 Q 10,150 10,110 Q 10,70 30,70 Q 50,70 50,110 Q 50,150 30,150" />
<Path Stroke="Black" Fill="LightGray" Data="M 25,240 Q 5,240 5,200 Q 5,160 25,160 Q 45,160 45,200 Q 45,240 25,240" />

<Path Visibility="{Binding Model.X2ButtonVisibility}" Stroke="Black" Fill="Red" Data="M 30,150 Q 10,150 10,110 Q 10,70 30,70 Q 50,70 50,110 Q 50,150 30,150" />
<Path Visibility="{Binding Model.X1ButtonVisibility}" Stroke="Black" Fill="Red" Data="M 25,240 Q 5,240 5,200 Q 5,160 25,160 Q 45,160 45,200 Q 45,240 25,240" />

<Path Stroke="Black" Fill="LightGray" Data="M 15,210 Q 15,10 115,10 L 165,10 Q 265,10 265,200 Q 265,410 165,410 L 115,410 Q 15,410, 15,210" />
<Path Stroke="Black" Fill="LightGray" Data="M 140,160 Q 120,160 120,110 Q 120,60 140,60 Q 160,60, 160,110 Q 160,160 140,160" />

<Path Visibility="{Binding Model.LeftButtonVisibility}" Stroke="Black" Fill="Red" Data="M 15,210 Q 15,10 115,10 L 115,10 L 115,190 L 15,210" />
<Path Visibility="{Binding Model.RightButtonVisibility}" Stroke="Black" Fill="Red" Data="M 265,210 Q 265,10 165,10 L 165,10 L 165,190 L 265,210" />
<Path Visibility="{Binding Model.MiddleButtonVisibility}" Stroke="Black" Fill="Red" Data="M 140,160 Q 120,160 120,110 Q 120,60 140,60 Q 160,60, 160,110 Q 160,160 140,160" />
</Grid>
</StackPanel>
</Grid>
71 changes: 70 additions & 1 deletion XOutput.App/UI/View/WindowsApiMousePanelModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using XOutput.DependencyInjection;
using System.Collections.ObjectModel;
using System.Windows;
using XOutput.App.Devices.Input;
using XOutput.App.Devices.Input.Mouse;
using XOutput.DependencyInjection;

namespace XOutput.App.UI.View
{
Expand All @@ -17,6 +21,71 @@ public bool Enabled
}
}

private Visibility leftButtonVisibility = Visibility.Hidden;
public Visibility LeftButtonVisibility
{
get => leftButtonVisibility;
set
{
if (leftButtonVisibility != value) {
leftButtonVisibility = value;
OnPropertyChanged(nameof(LeftButtonVisibility));
}
}
}

private Visibility rightButtonVisibility = Visibility.Hidden;
public Visibility RightButtonVisibility
{
get => rightButtonVisibility;
set
{
if (rightButtonVisibility != value) {
rightButtonVisibility = value;
OnPropertyChanged(nameof(RightButtonVisibility));
}
}
}

private Visibility middleButtonVisibility = Visibility.Hidden;
public Visibility MiddleButtonVisibility
{
get => middleButtonVisibility;
set
{
if (middleButtonVisibility != value) {
middleButtonVisibility = value;
OnPropertyChanged(nameof(MiddleButtonVisibility));
}
}
}

private Visibility x1ButtonVisibility = Visibility.Hidden;
public Visibility X1ButtonVisibility
{
get => x1ButtonVisibility;
set
{
if (x1ButtonVisibility != value) {
x1ButtonVisibility = value;
OnPropertyChanged(nameof(X1ButtonVisibility));
}
}
}

private Visibility x2ButtonVisibility = Visibility.Hidden;
public Visibility X2ButtonVisibility
{
get => x2ButtonVisibility;
set
{
if (x2ButtonVisibility != value) {
x2ButtonVisibility = value;
OnPropertyChanged(nameof(X2ButtonVisibility));
}
}
}

[ResolverMethod]
public WindowsApiMousePanelModel()
{
Expand Down
Loading

0 comments on commit 9d709e7

Please sign in to comment.