Skip to content
This repository was archived by the owner on Dec 3, 2024. It is now read-only.

Commit 9d709e7

Browse files
committed
Add mouse and keyboard visualisation
1 parent 59271f8 commit 9d709e7

14 files changed

+249
-9
lines changed

XOutput.App/Resources/Translations/English.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"Language": "Language",
1313
"ServerUrl": "Server URL",
1414
"AutoConnect": "Connect to server on start",
15-
"Connect": "Connect"
15+
"Connect": "Connect",
16+
"InvalidUriConnectionError": "Invalid address",
17+
"FailedToConnectToServerError": "Failed to connect to server"
1618
},
1719
"WindowsApiMouse": {
1820
"Title": "Windows API mouse",

XOutput.App/Resources/Translations/Hungarian.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
"Language": "Nyelv",
1313
"ServerUrl": "Server címe",
1414
"AutoConnect": "Kapcsolódás a szerverhez induláskor",
15-
"Connect": "Kapcsolódás"
15+
"Connect": "Kapcsolódás",
16+
"InvalidUriConnectionError": "Érvénytelen cím",
17+
"FailedToConnectToServerError": "Nem sikerült kapcsolódni a szerverhez"
1618
},
1719
"WindowsApiMouse": {
1820
"Title": "Windows API egér",

XOutput.App/UI/Component/Titled.xaml.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44

55
namespace XOutput.App.UI.Component
66
{
7-
[ContentPropertyAttribute("Control")]
7+
[ContentProperty("Control")]
88
public partial class Titled : UserControl
99
{
10-
public readonly static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(TitleProperty), typeof(string), typeof(Titled));
10+
public readonly static DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(Titled));
1111
public string Title
1212
{
1313
get => GetValue(TitleProperty) as string;
1414
set { SetValue(TitleProperty, value); }
1515
}
16-
public readonly static DependencyProperty ControlProperty = DependencyProperty.Register(nameof(ControlProperty), typeof(FrameworkElement), typeof(Titled));
16+
public readonly static DependencyProperty ControlProperty = DependencyProperty.Register(nameof(Control), typeof(FrameworkElement), typeof(Titled));
1717
public FrameworkElement Control
1818
{
1919
get => GetValue(ControlProperty) as FrameworkElement;

XOutput.App/UI/Converter/DynamicTranslationConverter.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@
66

77
namespace XOutput.App.UI.Converter
88
{
9+
/// <summary>
10+
/// Converts a text based on the language, and updates when the language changes.
11+
/// </summary>
12+
/// <example>
13+
/// <TextBlock>
14+
/// <TextBlock.Text>
15+
/// <MultiBinding Converter="{StaticResource DynamicTranslator}">
16+
/// <Binding Path="Translation.Language" />
17+
/// <Binding Path="Model.DynamicField" />
18+
/// </MultiBinding>
19+
/// </TextBox.Text>
20+
/// </TextBox>
21+
/// </example>
922
public class DynamicTranslationConverter : IMultiValueConverter
1023
{
1124
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)

XOutput.App/UI/Converter/TranslationConverter.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55

66
namespace XOutput.App.UI.Converter
77
{
8+
/// <summary>
9+
/// Converts a text based on the language, and updates when the language changes.
10+
/// </summary>
11+
/// <example>
12+
/// <TextBlock Text="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='Test.Key' />
13+
/// </example>
814
public class TranslationConverter : IValueConverter
915
{
1016
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

XOutput.App/UI/View/GeneralPanel.xaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@
1919
Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='General.AutoConnect'}"/>
2020
<Button Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='General.Connect'}"
2121
HorizontalAlignment="Left" Click="Connect_Click" Width="150"/>
22+
<TextBlock HorizontalAlignment="Left" Width="250">
23+
<TextBlock.Text>
24+
<MultiBinding Converter="{StaticResource DynamicTranslator}">
25+
<Binding Path="Translation.Language" />
26+
<Binding Path="Model.ConnectionErrorMessage" />
27+
</MultiBinding>
28+
</TextBlock.Text>
29+
</TextBlock>
30+
<TextBlock Text="{Binding Model.ServerVersion}" HorizontalAlignment="Left" Width="250"/>
2231
</StackPanel>
2332
</component:Titled>
2433
</StackPanel>

XOutput.App/UI/View/GeneralPanelModel.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ public string SelectedLanguage
2222
}
2323
}
2424

25+
private string connectionErrorMessage;
26+
public string ConnectionErrorMessage
27+
{
28+
get => connectionErrorMessage;
29+
set
30+
{
31+
if (connectionErrorMessage != value)
32+
{
33+
connectionErrorMessage = value;
34+
OnPropertyChanged(nameof(ConnectionErrorMessage));
35+
}
36+
}
37+
}
38+
2539
private string serverUrl;
2640
public string ServerUrl
2741
{
@@ -36,6 +50,20 @@ public string ServerUrl
3650
}
3751
}
3852

53+
private string serverVersion;
54+
public string ServerVersion
55+
{
56+
get => serverVersion;
57+
set
58+
{
59+
if (serverVersion != value)
60+
{
61+
serverVersion = value;
62+
OnPropertyChanged(nameof(ServerVersion));
63+
}
64+
}
65+
}
66+
3967
private bool autoConnect;
4068
public bool AutoConnect
4169
{

XOutput.App/UI/View/GeneralPanelViewModel.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.ComponentModel;
33
using System.Threading.Tasks;
4+
using System.Windows;
45
using XOutput.App.Configuration;
56
using XOutput.Configuration;
67
using XOutput.DependencyInjection;
@@ -47,8 +48,28 @@ private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
4748

4849
public async Task Connect()
4950
{
50-
var uri = new Uri($"http://{Model.ServerUrl}/api/");
51-
var x = await new InfoClient(new StaticHttpClientProvider(uri)).GetInfoAsync();
51+
Model.ConnectionErrorMessage = "";
52+
Model.ServerVersion = "";
53+
Uri uri;
54+
try
55+
{
56+
uri = new Uri($"http://{Model.ServerUrl}/api/");
57+
}
58+
catch (UriFormatException)
59+
{
60+
Model.ConnectionErrorMessage = "General.InvalidUriConnectionError";
61+
return;
62+
}
63+
try
64+
{
65+
var info = await new InfoClient(new StaticHttpClientProvider(uri)).GetInfoAsync();
66+
Model.ServerVersion = info.Version;
67+
}
68+
catch
69+
{
70+
Model.ConnectionErrorMessage = "General.FailedToConnectToServerError";
71+
return;
72+
}
5273
var appConfig = GetAppConfig();
5374
appConfig.AutoConnect = Model.AutoConnect;
5475
appConfig.ServerUrl = Model.ServerUrl;

XOutput.App/UI/View/WindowsApiKeyboardPanel.xaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,19 @@
99
<StackPanel>
1010
<TextBlock Text="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiKeyboard.Title'}" Margin="5"/>
1111
<CheckBox Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiKeyboard.Enabled'}" IsChecked="{Binding Model.Enabled}" Margin="5"/>
12+
<ItemsControl ItemsSource="{Binding Model.PressedButtons}">
13+
<ItemsControl.ItemsPanel>
14+
<ItemsPanelTemplate>
15+
<StackPanel Orientation="Horizontal"/>
16+
</ItemsPanelTemplate>
17+
</ItemsControl.ItemsPanel>
18+
<ItemsControl.ItemTemplate>
19+
<DataTemplate>
20+
<Border Background="LightGray" BorderBrush="Black">
21+
<TextBlock Text="{Binding}" Margin="3" />
22+
</Border>
23+
</DataTemplate>
24+
</ItemsControl.ItemTemplate>
25+
</ItemsControl>
1226
</StackPanel>
1327
</Grid>

XOutput.App/UI/View/WindowsApiKeyboardPanelModel.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using XOutput.DependencyInjection;
1+
using System.Collections.ObjectModel;
2+
using XOutput.App.Devices.Input.Keyboard;
3+
using XOutput.DependencyInjection;
24

35
namespace XOutput.App.UI.View
46
{
@@ -18,6 +20,9 @@ public bool Enabled
1820
}
1921
}
2022

23+
private readonly ObservableCollection<KeyboardButton> pressedButtons = new ObservableCollection<KeyboardButton>();
24+
public ObservableCollection<KeyboardButton> PressedButtons => pressedButtons;
25+
2126
[ResolverMethod]
2227
public WindowsApiKeyboardPanelModel()
2328
{

XOutput.App/UI/View/WindowsApiKeyboardPanelViewModel.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
using System.ComponentModel;
2+
using System.Linq;
3+
using System.Windows.Threading;
4+
using XOutput.App.Devices.Input;
25
using XOutput.App.Devices.Input.Keyboard;
36
using XOutput.DependencyInjection;
47

@@ -14,6 +17,8 @@ public WindowsApiKeyboardPanelViewModel(WindowsApiKeyboardPanelModel model, Keyb
1417
this.keyboardDeviceProvider = keyboardDeviceProvider;
1518
Model.Enabled = keyboardDeviceProvider.Enabled;
1619
Model.PropertyChanged += Model_PropertyChanged;
20+
var keyboardDevice = keyboardDeviceProvider.GetActiveDevices().First() as KeyboardDevice;
21+
keyboardDevice.InputChanged += KeyboardDevice_InputChanged;
1722
}
1823

1924
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -23,5 +28,23 @@ private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
2328
keyboardDeviceProvider.Enabled = Model.Enabled;
2429
}
2530
}
31+
private void KeyboardDevice_InputChanged(object sender, DeviceInputChangedEventArgs e)
32+
{
33+
App.Current.Dispatcher.Invoke(() => {
34+
foreach (var source in e.ChangedValues)
35+
{
36+
var keyboardButton = (KeyboardButton) source.Offset;
37+
bool pressed = source.GetValue() > 0.5;
38+
if (pressed && !Model.PressedButtons.Contains(keyboardButton))
39+
{
40+
Model.PressedButtons.Add(keyboardButton);
41+
}
42+
if (!pressed && Model.PressedButtons.Contains(keyboardButton))
43+
{
44+
Model.PressedButtons.Remove(keyboardButton);
45+
}
46+
}
47+
});
48+
}
2649
}
2750
}

XOutput.App/UI/View/WindowsApiMousePanel.xaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,26 @@
44
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
55
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
66
xmlns:local="clr-namespace:XOutput.App.UI.View"
7+
xmlns:component="clr-namespace:XOutput.App.UI.Component"
78
mc:Ignorable="d"
89
d:DataContext="{d:DesignInstance local:WindowsApiMousePanelViewModel, IsDesignTimeCreatable=False}">
910
<StackPanel>
1011
<TextBlock Text="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiMouse.Title'}" Margin="5"/>
1112
<CheckBox Content="{Binding Translation.Language, Converter={StaticResource Translator}, ConverterParameter='WindowsApiMouse.Enabled'}" IsChecked="{Binding Model.Enabled}" Margin="5"/>
13+
14+
<Grid>
15+
<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" />
16+
<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" />
17+
18+
<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" />
19+
<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" />
20+
21+
<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" />
22+
<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" />
23+
24+
<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" />
25+
<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" />
26+
<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" />
27+
</Grid>
1228
</StackPanel>
1329
</Grid>

XOutput.App/UI/View/WindowsApiMousePanelModel.cs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
using XOutput.DependencyInjection;
1+
using System.Collections.ObjectModel;
2+
using System.Windows;
3+
using XOutput.App.Devices.Input;
4+
using XOutput.App.Devices.Input.Mouse;
5+
using XOutput.DependencyInjection;
26

37
namespace XOutput.App.UI.View
48
{
@@ -17,6 +21,71 @@ public bool Enabled
1721
}
1822
}
1923

24+
private Visibility leftButtonVisibility = Visibility.Hidden;
25+
public Visibility LeftButtonVisibility
26+
{
27+
get => leftButtonVisibility;
28+
set
29+
{
30+
if (leftButtonVisibility != value) {
31+
leftButtonVisibility = value;
32+
OnPropertyChanged(nameof(LeftButtonVisibility));
33+
}
34+
}
35+
}
36+
37+
private Visibility rightButtonVisibility = Visibility.Hidden;
38+
public Visibility RightButtonVisibility
39+
{
40+
get => rightButtonVisibility;
41+
set
42+
{
43+
if (rightButtonVisibility != value) {
44+
rightButtonVisibility = value;
45+
OnPropertyChanged(nameof(RightButtonVisibility));
46+
}
47+
}
48+
}
49+
50+
private Visibility middleButtonVisibility = Visibility.Hidden;
51+
public Visibility MiddleButtonVisibility
52+
{
53+
get => middleButtonVisibility;
54+
set
55+
{
56+
if (middleButtonVisibility != value) {
57+
middleButtonVisibility = value;
58+
OnPropertyChanged(nameof(MiddleButtonVisibility));
59+
}
60+
}
61+
}
62+
63+
private Visibility x1ButtonVisibility = Visibility.Hidden;
64+
public Visibility X1ButtonVisibility
65+
{
66+
get => x1ButtonVisibility;
67+
set
68+
{
69+
if (x1ButtonVisibility != value) {
70+
x1ButtonVisibility = value;
71+
OnPropertyChanged(nameof(X1ButtonVisibility));
72+
}
73+
}
74+
}
75+
76+
private Visibility x2ButtonVisibility = Visibility.Hidden;
77+
public Visibility X2ButtonVisibility
78+
{
79+
get => x2ButtonVisibility;
80+
set
81+
{
82+
if (x2ButtonVisibility != value) {
83+
x2ButtonVisibility = value;
84+
OnPropertyChanged(nameof(X2ButtonVisibility));
85+
}
86+
}
87+
}
88+
2089
[ResolverMethod]
2190
public WindowsApiMousePanelModel()
2291
{

0 commit comments

Comments
 (0)