Compare commits

...

5 Commits

Author SHA1 Message Date
LeapwardKoex a68aa187c7 Add tooltips
.NET Core Desktop / build (Release) (push) Has been cancelled Details
Improve touch pannel button styling
Enforce aspect ratio resizing for touch panel and a minimum size
2025-04-07 22:00:06 +12:00
LeapwardKoex a2b63c607a Add translations for ring button size label
.NET Core Desktop / build (Release) (push) Has been cancelled Details
2025-04-06 10:23:54 +12:00
LeapwardKoex 76f39d5be8 Merge branch 'master' of https://github.com/Leapward-Koex/MaiTouchSensorEmulator 2025-04-06 10:04:16 +12:00
LeapwardKoex 643fb31505 Add support for large button setting, which extends the size of the ring buttons to fill the rendered area of the touch pannel
Re-write button handling to decrese latency and fix issues where some notes where not picked up during slide actions
2025-04-06 10:04:13 +12:00
LeapwardKoex df962b7304 Simplify button polygons and shrink gaps 2025-04-03 21:43:29 +13:00
14 changed files with 763 additions and 139 deletions

View File

@ -37,6 +37,9 @@
<setting name="UserSettingsUpgradeRequired" serializeAs="String">
<value>True</value>
</setting>
<setting name="IsLargeButtonsEnabled" serializeAs="String">
<value>False</value>
</setting>
</WpfMaiTouchEmulator.Properties.Settings>
</userSettings>
</configuration>

View File

@ -99,8 +99,8 @@
<Label x:Name="languageLabel" Content="{Binding LbLanguageDropdown}" d:Content="Language"/>
<ComboBox x:Name="languageSelector" ItemsSource="{Binding SupportedLanguages}" DisplayMemberPath="NativeName" SelectedItem="{Binding SelectedLanguage, Mode=TwoWay}"/>
<Separator Margin="0,6"/>
<CheckBox x:Name="debugMode" Content="{Binding LbDebugMode}" d:Content="Debug mode" IsChecked="{Binding Path=IsDebugEnabled}" Click="debugMode_Click" Cursor="" Focusable="False" ToolTip="Show the touchpad with translucency and show inputs highlighted" />
<CheckBox x:Name="largeButtons" Content="{Binding LbLargeButtons}" d:Content="LargeButtons" IsChecked="{Binding Path=IsLargeButtonsEnabled}" Click="largeButtons_Click" Cursor="" Focusable="False" ToolTip="{Binding LbLargeButtonsTT}" />
<CheckBox x:Name="debugMode" Content="{Binding LbDebugMode}" d:Content="Debug mode" IsChecked="{Binding Path=IsDebugEnabled}" Click="debugMode_Click" Cursor="" Focusable="False" ToolTip="{Binding LbDebugModeTT}" />
<CheckBox x:Name="automaticTouchPanelPositioning" d:Content="Automatic touch panel positioning" Content="{Binding LbAutoSensorPositioning}" IsChecked="{Binding Path=IsAutomaticPositioningEnabled}" Click="automaticTouchPanelPositioning_Click" ToolTip="{Binding LbAutoSensorPositioningTT}"/>
<CheckBox x:Name="automaticPortConnecting" d:Content="Automatic port connecting" Content="{Binding LbAutoPortConnecting}" IsChecked="{Binding Path=IsAutomaticPortConnectingEnabled}" Click="automaticPortConnecting_Click" ToolTip="{Binding LbAutoPortConnectingTT}"/>
<CheckBox x:Name="exitWithSinmai" Content="{Binding LbExitWithSinmai}" d:Content="Exit with Sinmai" IsChecked="{Binding IsExitWithSinmaiEnabled}" Click="exitWithSinmai_Click" ToolTip="{Binding LbExitWithSinmaiTT}"/>

View File

@ -30,6 +30,7 @@ public partial class MainWindow : Window
IsAutomaticPositioningEnabled = Properties.Settings.Default.IsAutomaticPositioningEnabled,
IsExitWithSinmaiEnabled = Properties.Settings.Default.IsExitWithSinmaiEnabled,
IsRingButtonEmulationEnabled = Properties.Settings.Default.IsRingButtonEmulationEnabled,
IsLargeButtonsEnabled = Properties.Settings.Default.IsLargeButtonsEnabled,
BorderColour = Properties.Settings.Default.BorderColour,
LbAppVersion = Assembly.GetEntryAssembly()?.GetName().Version?.ToString() ?? "1.0.0.0",
};
@ -82,8 +83,14 @@ public partial class MainWindow : Window
Logger.Info("Main window loaded, creating touch panel");
_touchPanel = new TouchPanel();
_touchPanel.onTouch = (value) => { buttonState.PressButton(value); };
_touchPanel.onRelease = (value) => { buttonState.ReleaseButton(value); };
_touchPanel.onTouch = (value) => {
buttonState.PressButton(value);
connector.SendTouchscreenState();
};
_touchPanel.onRelease = (value) => {
buttonState.ReleaseButton(value);
connector.SendTouchscreenState();
};
_touchPanel.onInitialReposition = () => { WindowState = WindowState.Minimized; };
_touchPanel.SetBorderMode((BorderSetting)Properties.Settings.Default.BorderSetting, dataContext.BorderColour);
_touchPanel.Show();
@ -91,6 +98,7 @@ public partial class MainWindow : Window
_touchPanel.DataContext = dataContext;
_touchPanel.SetDebugMode(dataContext.IsDebugEnabled);
_touchPanel.SetLargeButtonMode(dataContext.IsLargeButtonsEnabled);
if (Properties.Settings.Default.IsAutomaticPositioningEnabled)
{
_touchPanel.DragWindowHandle.Visibility = Visibility.Hidden;
@ -216,6 +224,16 @@ public partial class MainWindow : Window
_touchPanel?.SetDebugMode(dataContext.IsDebugEnabled);
}
private void largeButtons_Click(object sender, RoutedEventArgs e)
{
var dataContext = (MainWindowViewModel)DataContext;
var enabled = !dataContext.IsLargeButtonsEnabled;
dataContext.IsLargeButtonsEnabled = !enabled;
Properties.Settings.Default.IsLargeButtonsEnabled = dataContext.IsLargeButtonsEnabled;
Properties.Settings.Default.Save();
_touchPanel?.SetLargeButtonMode(dataContext.IsLargeButtonsEnabled);
}
private void automaticTouchPanelPositioning_Click(object sender, RoutedEventArgs e)
{
var dataContext = (MainWindowViewModel)DataContext;

View File

@ -36,6 +36,14 @@ public class MainWindowViewModel : INotifyPropertyChanged
{
get; set;
}
public string? LbLargeButtons
{
get; set;
}
public string? LbLargeButtonsTT
{
get; set;
}
public string? LbExitWithSinmai
{
get; set;
@ -204,6 +212,11 @@ public class MainWindowViewModel : INotifyPropertyChanged
get;
private set;
}
public string? LbDebugModeTT
{
get;
private set;
}
public string? LbAutoSensorPositioningTT
{
get;
@ -222,6 +235,7 @@ public class MainWindowViewModel : INotifyPropertyChanged
private bool _isAutomaticPortConnectingEnabled;
private bool _isDebugEnabled;
private bool _isLargeButtonsEnabled;
private bool _isAutomaticPositioningEnabled;
private bool _isExitWithSinmaiEnabled;
private CultureInfo _selectedLanguage;
@ -265,6 +279,16 @@ public class MainWindowViewModel : INotifyPropertyChanged
}
}
public bool IsLargeButtonsEnabled
{
get => _isLargeButtonsEnabled;
set
{
_isLargeButtonsEnabled = value;
OnPropertyChanged();
}
}
public bool IsAutomaticPositioningEnabled
{
get => _isAutomaticPositioningEnabled;
@ -349,6 +373,8 @@ public class MainWindowViewModel : INotifyPropertyChanged
LbConnectionStateNotConnected = resourceManager.GetString("lbConnectionStateNotConnected");
LbConnectToPort = resourceManager.GetString("lbConnectToPort");
LbDebugMode = resourceManager.GetString("lbDebugMode");
LbLargeButtons = resourceManager.GetString("lbLargeButtons");
LbLargeButtonsTT = resourceManager.GetString("lbLargeButtonsTT");
LbExitWithSinmai = resourceManager.GetString("lbExitWithSinmai");
LbEmulateRingButtons = resourceManager.GetString("lbEmulateRingButtons");
LbOpenLogFolder = resourceManager.GetString("LbOpenLogFolder");
@ -372,6 +398,7 @@ public class MainWindowViewModel : INotifyPropertyChanged
LbMenuCategoryHelp = resourceManager.GetString("lbMenuCategoryHelp");
LbMenuItemSetup = resourceManager.GetString("lbMenuItemSetup");
LbAutoPortConnectingTT = resourceManager.GetString("lbAutoPortConnectingTT");
LbDebugModeTT = resourceManager.GetString("lbDebugModeTT");
LbAutoSensorPositioningTT = resourceManager.GetString("lbAutoSensorPositioningTT");
LbExitWithSinmaiTT = resourceManager.GetString("lbExitWithSinmaiTT");
LbEmulateRingButtonsTT = resourceManager.GetString("lbEmulateRingButtonsTT");

View File

@ -182,7 +182,7 @@ internal class MaiTouchComConnector(MaiTouchSensorButtonStateManager buttonState
}
}
void SendTouchscreenState()
public void SendTouchscreenState()
{
if (_connected && _isActiveMode)
{

View File

@ -23,7 +23,6 @@ public enum TouchValue : long
B8 = 1 << 15, // 2^15
C1 = 1 << 16, // 2^16
C2 = 1 << 17, // 2^17
C3 = C1 | C2, // A special sensor used because center notes are hard to press using a windows touchscreen
D1 = 1 << 18, // 2^18
D2 = 1 << 19, // 2^19
D3 = 1 << 20, // 2^20
@ -50,24 +49,6 @@ internal class MaiTouchSensorButtonStateManager
public MaiTouchSensorButtonStateManager(Label buttonStateValue)
{
this.buttonStateValue = buttonStateValue;
SetupUpdateLoop();
}
private async Task SetupUpdateLoop()
{
string? lastButtonState = null;
while (true)
{
if (lastButtonState != buttonState.ToString())
{
lastButtonState = buttonState.ToString();
Application.Current.Dispatcher.Invoke(() =>
{
buttonStateValue.Content = lastButtonState;
});
}
await Task.Delay(16);
}
}
public void Reset()
@ -78,11 +59,21 @@ internal class MaiTouchSensorButtonStateManager
public void PressButton(TouchValue button)
{
buttonState |= (long)button;
Application.Current.Dispatcher.Invoke(() =>
{
buttonStateValue.Content = buttonState.ToString();
});
}
public void ReleaseButton(TouchValue button)
{
buttonState &= ~(long)button;
Application.Current.Dispatcher.Invoke(() =>
{
buttonStateValue.Content = buttonState.ToString();
});
}
public byte[] GetCurrentState()

View File

@ -12,7 +12,7 @@ namespace WpfMaiTouchEmulator.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.12.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@ -142,5 +142,17 @@ namespace WpfMaiTouchEmulator.Properties {
this["UserSettingsUpgradeRequired"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool IsLargeButtonsEnabled {
get {
return ((bool)(this["IsLargeButtonsEnabled"]));
}
set {
this["IsLargeButtonsEnabled"] = value;
}
}
}
}

View File

@ -32,5 +32,8 @@
<Setting Name="UserSettingsUpgradeRequired" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="IsLargeButtonsEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -195,6 +195,15 @@ namespace WpfMaiTouchEmulator.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Show the touchpad with translucency and show inputs highlighted.
/// </summary>
internal static string lbDebugModeTT {
get {
return ResourceManager.GetString("lbDebugModeTT", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Emulate ring buttons.
/// </summary>
@ -249,6 +258,24 @@ namespace WpfMaiTouchEmulator.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Extend ring button size.
/// </summary>
internal static string lbLargeButtons {
get {
return ResourceManager.GetString("lbLargeButtons", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Extends the ring button hitboxes to the edge of the window.
/// </summary>
internal static string lbLargeButtonsTT {
get {
return ResourceManager.GetString("lbLargeButtonsTT", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to List installed com ports.
/// </summary>

View File

@ -162,6 +162,9 @@
<data name="lbDebugMode" xml:space="preserve">
<value>デバッグモード</value>
</data>
<data name="lbDebugModeTT" xml:space="preserve">
<value>タッチパッドを半透明で表示し、入力をハイライト表示</value>
</data>
<data name="lbEmulateRingButtons" xml:space="preserve">
<value>リングボタンをエミュレートする</value>
</data>
@ -180,6 +183,12 @@
<data name="lbLanguageDropdown" xml:space="preserve">
<value>言語</value>
</data>
<data name="lbLargeButtons" xml:space="preserve">
<value>リングボタンのサイズを拡大</value>
</data>
<data name="lbLargeButtonsTT" xml:space="preserve">
<value>リングボタンのヒットボックスをウィンドウの端まで拡大</value>
</data>
<data name="lbListComPorts" xml:space="preserve">
<value>インストールされたCOMポートをリストアップ</value>
</data>

View File

@ -162,6 +162,9 @@
<data name="lbDebugMode" xml:space="preserve">
<value>Debug mode</value>
</data>
<data name="lbDebugModeTT" xml:space="preserve">
<value>Show the touchpad with translucency and show inputs highlighted</value>
</data>
<data name="lbEmulateRingButtons" xml:space="preserve">
<value>Emulate ring buttons</value>
</data>
@ -180,6 +183,12 @@
<data name="lbLanguageDropdown" xml:space="preserve">
<value>Language</value>
</data>
<data name="lbLargeButtons" xml:space="preserve">
<value>Extend ring button size</value>
</data>
<data name="lbLargeButtonsTT" xml:space="preserve">
<value>Extends the ring button hitboxes to the edge of the window</value>
</data>
<data name="lbListComPorts" xml:space="preserve">
<value>List installed com ports</value>
</data>

View File

@ -162,6 +162,9 @@
<data name="lbDebugMode" xml:space="preserve">
<value>调试模式</value>
</data>
<data name="lbDebugModeTT" xml:space="preserve">
<value>显示半透明的触控板并突出显示输入</value>
</data>
<data name="lbEmulateRingButtons" xml:space="preserve">
<value>模拟环形按钮</value>
</data>
@ -180,6 +183,12 @@
<data name="lbLanguageDropdown" xml:space="preserve">
<value>语言</value>
</data>
<data name="lbLargeButtons" xml:space="preserve">
<value>扩大环形按钮大小</value>
</data>
<data name="lbLargeButtonsTT" xml:space="preserve">
<value>将环形按钮的碰撞盒扩展到窗口边缘</value>
</data>
<data name="lbListComPorts" xml:space="preserve">
<value>列出已安装的COM端口</value>
</data>

View File

@ -9,16 +9,54 @@
ResizeMode="NoResize"
AllowsTransparency="True" WindowStyle="None" Background="Transparent"
>
<Window.Resources>
<Style x:Key="DraggableHandleStyle" TargetType="Border">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFEEEEEE" Offset="0"/>
<GradientStop Color="#FFCCCCCC" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Black" BlurRadius="5" ShadowDepth="2"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ResizeGripStyle" TargetType="Border">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#FFCCCCCC" Offset="0"/>
<GradientStop Color="#FFAAAAAA" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="Black" BlurRadius="5" ShadowDepth="2"/>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Border Background="#01000000">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border x:Name="DragWindowHandle" HorizontalAlignment="Left" VerticalAlignment="Top"
Height="50" Background="White" MouseLeftButtonDown="DragBar_MouseLeftButtonDown"
Cursor="SizeAll" Width="70">
<TextBlock FontSize="24" Text="{Binding LbTouchPanelDrag}" d:Text="Drag" />
<Border x:Name="DragWindowHandle"
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="50" Width="100"
Style="{StaticResource DraggableHandleStyle}"
MouseLeftButtonDown="DragBar_MouseLeftButtonDown"
Cursor="SizeAll">
<TextBlock FontSize="24" Text="{Binding LbTouchPanelDrag}"
VerticalAlignment="Center" HorizontalAlignment="Center" d:Text="Drag"/>
</Border>
<DockPanel VerticalAlignment="Bottom">
<Viewbox Stretch="Uniform" Opacity="1">
@ -27,48 +65,51 @@
Width="1440" VerticalAlignment="Bottom">
<Canvas x:Name="TouchCanvas" Width="1440" Height="1440" Margin="-10,-10,-10,-10">
<Polygon Canvas.Left="699" Canvas.Top="6" Points="0,0 39,0 111,5 113,6 111,24 80,243 77,243 63,229 56,221 23,188 16,194 -34,244 -36,244 -70,4 -70,3 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D1}" Fill="White" />
<Polygon Canvas.Left="825" Canvas.Top="13" Points="0,0 10,1 95,19 145,37 179,50 207,64 230,75 254,87 297,116 318,130 316,135 300,156 286,175 270,196 256,215 240,236 226,255 210,276 197,294 181,315 168,333 101,333 66,318 21,299 9,293 -35,249 -34,237 -1,4 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A1}" Fill="White" />
<Polygon Canvas.Left="1156" Canvas.Top="154" Points="0,0 8,6 21,18 32,27 45,39 56,48 69,60 77,67 86,77 93,85 105,99 116,111 125,122 130,128 118,138 102,150 85,163 68,176 47,192 30,205 13,218 -8,234 -25,247 -42,260 -62,275 -63,275 -63,255 -62,207 -61,193 -143,193 -141,189 -127,170 -111,149 -97,130 -81,109 -68,91 -52,70 -38,51 -22,30 -8,11 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D2}" Fill="White" />
<Polygon Canvas.Left="1295" Canvas.Top="294" Points="0,0 4,5 21,31 34,51 44,69 89,159 106,213 123,268 132,318 132,320 -116,354 -120,352 -164,308 -179,271 -195,232 -201,217 -201,151 -190,142 -171,128 -150,112 -131,98 -110,82 -91,68 -70,52 -51,38 -30,22 -11,8 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A2}" Fill="White" />
<Polygon Canvas.Left="1427" Canvas.Top="628" Points="0,0 3,0 5,30 8,90 7,116 4,174 3,183 -15,181 -235,150 -235,147 -216,128 -208,121 -182,95 -179,92 -187,85 -237,35 -237,34 -13,2 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D3}" Fill="White" />
<Polygon Canvas.Left="1176" Canvas.Top="791" Points="0,0 13,1 247,33 251,34 250,43 238,100 223,144 208,187 195,224 182,248 169,271 159,290 146,313 136,329 121,351 119,352 101,339 80,323 61,309 40,293 21,279 0,263 -19,249 -40,233 -59,219 -80,203 -82,202 -82,136 -67,99 -45,44 -38,37 -30,30" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A3}" Fill="White" />
<Polygon Canvas.Left="1094" Canvas.Top="1010" Points="0,0 4,2 20,14 33,24 54,40 75,56 95,71 113,85 129,97 146,110 167,126 188,142 193,146 191,150 179,163 168,175 159,185 147,198 136,210 132,215 124,222 111,234 99,245 87,256 77,265 67,274 63,272 51,256 41,243 28,226 18,213 5,196 -8,179 -18,166 -31,149 -41,136 -54,119 -67,102 -77,89 -81,83 1,83" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D4}" Fill="White" />
<Polygon Canvas.Left="927" Canvas.Top="1093" Points="0,0 67,0 81,18 95,37 111,58 126,78 142,99 154,115 170,136 184,155 194,168 210,189 219,201 214,205 189,221 172,232 150,246 136,254 108,268 85,279 72,285 10,307 -7,313 -98,333 -101,333 -103,324 -135,88 -135,82 -128,75 -121,67 -92,38 -56,23 -15,6" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A4}" Fill="White" />
<Polygon Canvas.Left="664" Canvas.Top="1190" Points="0,0 7,6 18,17 26,24 44,42 52,49 58,54 90,22 98,15 113,0 115,1 148,234 148,238 146,239 66,244 54,244 -35,238 -10,63 -1,1" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D5}" Fill="White" />
<Polygon Canvas.Left="448" Canvas.Top="1092" Points="0,0 66,0 112,19 156,37 164,44 202,82 197,121 168,331 167,334 153,332 106,323 1,288 -97,239 -135,214 -152,203 -151,199 -135,178 -120,158 -104,137 -88,116 -79,104 -63,83 -51,67 -35,46 -23,30 -7,9 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A5}" Fill="White" />
<Polygon Canvas.Left="347" Canvas.Top="1013" Points="0,0 2,0 2,74 1,80 46,79 84,79 82,83 69,100 56,117 43,134 30,151 17,168 4,185 -9,202 -22,219 -35,236 -48,253 -61,270 -64,270 -77,258 -85,251 -99,239 -111,228 -122,219 -135,207 -144,196 -156,183 -165,172 -177,159 -186,148 -191,142 -172,128 -153,114 -132,98 -118,88 -97,72 -79,59 -58,43 -39,29 -20,15 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D6}" Fill="White" />
<Polygon Canvas.Left="257" Canvas.Top="791" Points="0,0 9,0 52,43 65,73 83,116 91,135 91,202 73,216 54,230 36,244 17,258 -1,272 -20,286 -33,296 -54,312 -73,326 -91,340 -109,353 -111,353 -123,334 -135,316 -148,296 -182,228 -192,209 -201,190 -228,103 -233,85 -241,39 -241,34 -240,33 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A6}" Fill="White" />
<Polygon Canvas.Left="13" Canvas.Top="627" Points="0,0 24,3 238,33 232,40 223,50 203,70 196,78 183,91 185,95 240,150 240,151 139,165 7,183 0,183 -7,89 -1,1 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D7}" Fill="White" />
<Polygon Canvas.Left="145" Canvas.Top="295" Points="0,0 5,2 26,18 42,30 63,46 82,60 103,76 122,90 140,104 159,118 180,134 199,148 203,151 203,193 202,220 180,274 165,311 154,322 146,329 122,353 108,352 -130,320 -131,318 -123,274 -96,187 -87,157 -66,115 -55,92 -44,70 -30,48 -14,22 -2,3 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A7}" Fill="White" />
<Polygon Canvas.Left="283" Canvas.Top="155" Points="0,0 5,5 17,20 29,36 42,53 58,74 74,95 90,116 106,137 119,154 135,175 146,190 146,191 65,191 66,256 66,275 58,269 46,260 29,247 12,234 -5,221 -22,208 -39,195 -56,182 -73,169 -90,156 -107,143 -124,130 -128,126 -119,117 -112,109 -101,97 -94,89 -82,76 -75,68 -64,56 -52,45 -41,36 -29,25 -18,16 -5,4 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D8}" Fill="White" />
<Polygon Canvas.Left="613" Canvas.Top="13" Points="0,0 3,0 10,48 38,247 37,252 24,265 16,272 -8,296 -100,333 -165,333 -179,315 -192,298 -205,281 -218,264 -231,247 -244,230 -257,213 -270,196 -283,179 -296,162 -309,145 -317,134 -316,131 -300,121 -285,111 -265,98 -249,88 -165,46 -72,15 -9,2 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A8}" Fill="White" />
<Polygon Canvas.Left="620" Canvas.Top="6" Points="0,5 50,2 100,0 150,2 200,5 165,253 100,188 35,253" Tag="{x:Static local:TouchValue.D1}" Fill="White" />
<Polygon Canvas.Left="786" Canvas.Top="11" Points="150,28 245,65 360,133 208,338 145,338 49,297 0,249 35,0" Tag="{x:Static local:TouchValue.A1}" Fill="White" />
<Polygon Canvas.Left="995" Canvas.Top="144" Points="153,0 187,32 225,67 259,104 295,147 96,297 96,205 0,205" Tag="{x:Static local:TouchValue.D2}" Fill="White" />
<Polygon Canvas.Left="1091" Canvas.Top="292" Points="261,101 303,195 339,327 91,362 42,314 0,219 0,150 202,0" Tag="{x:Static local:TouchValue.A2}" Fill="White" />
<Polygon Canvas.Left="1182" Canvas.Top="620" Points="248,0 251,48 253,100 251,150 247,199 0,165 65,100 0,35" Tag="{x:Static local:TouchValue.D3}" Fill="White" />
<Polygon Canvas.Left="1092" Canvas.Top="786" Points="305,150 269,246 201,364 0,213 0,144 41,48 89,0 337,34" Tag="{x:Static local:TouchValue.A3}" Fill="White" />
<Polygon Canvas.Left="1000" Canvas.Top="1000" Points="292,151 260,187 225,225 188,259 151,291 0,92 92,92 92,0" Tag="{x:Static local:TouchValue.D4}" Fill="White" />
<Polygon Canvas.Left="786" Canvas.Top="1092" Points="260,259 167,301 37,335 0,83 48,35 144,0 212,0 364,200" Tag="{x:Static local:TouchValue.A4}" Fill="White" />
<Polygon Canvas.Left="621" Canvas.Top="1175" Points="199,252 151,255 99,257 49,255 0,252 34,0 99,65 164,0" Tag="{x:Static local:TouchValue.D5}" Fill="White" />
<Polygon Canvas.Left="291" Canvas.Top="1092" Points="104,259 197,301 327,335 363,83 316,35 220,0 152,0 0,201" Tag="{x:Static local:TouchValue.A5}" Fill="White" />
<Polygon Canvas.Left="150" Canvas.Top="1000" Points="140,292 104,260 66,225 32,188 0,151 199,0 199,92 291,92" Tag="{x:Static local:TouchValue.D6}" Fill="White" />
<Polygon Canvas.Left="16" Canvas.Top="785" Points="32,150 68,246 133,365 333,214 333,144 296,48 248,0 0,35" Tag="{x:Static local:TouchValue.A6}" Fill="White" />
<Polygon Canvas.Left="10" Canvas.Top="620" Points="5,199 2,151 0,99 2,49 6,0 253,34 188,99 253,164" Tag="{x:Static local:TouchValue.D7}" Fill="White" />
<Polygon Canvas.Left="16" Canvas.Top="291" Points="78,101 36,195 0,327 248,362 297,314 333,219 333,151 132,0" Tag="{x:Static local:TouchValue.A7}" Fill="White" />
<Polygon Canvas.Left="149" Canvas.Top="150" Points="0,140 32,104 67,66 104,32 145,0 298,199 200,199 200,291" Tag="{x:Static local:TouchValue.D8}" Fill="White" />
<Polygon Canvas.Left="295" Canvas.Top="11" Points="210,28 115,65 0,138 153,338 215,338 311,297 359,249 324,0" Tag="{x:Static local:TouchValue.A8}" Fill="White" />
<Polygon Canvas.Left="720" Canvas.Top="215" Points="0,0 4,2 48,46 56,53 97,94 91,101 2,190 -2,188 -10,181 -54,137 -62,130 -96,96 -94,92 -73,71 -65,64 -27,26 -19,19 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E1}" Fill="White" />
<Polygon Canvas.Left="801" Canvas.Top="347" Points="0,0 25,10 61,25 107,44 129,53 130,54 129,88 126,158 112,171 104,178 91,190 88,192 59,192 -7,191 -12,188 -23,177 -30,169 -38,161 -45,153 -53,145 -60,137 -69,128 -73,123 -73,105 -72,71 -33,32 -25,25 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B1}" Fill="White" />
<Polygon Canvas.Left="1070" Canvas.Top="361" Points="0,0 8,0 8,137 -127,137 -128,57 -128,1 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E2}" Fill="White" />
<Polygon Canvas.Left="938" Canvas.Top="513" Points="0,0 103,0 113,23 130,64 150,112 156,126 154,130 141,142 112,171 104,178 83,199 31,199 -19,149 -26,141 -36,131 -37,57 -37,35 -30,28 -22,21 -11,10 -3,3 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B2}" Fill="White" />
<Polygon Canvas.Left="1130" Canvas.Top="623" Points="0,0 4,2 45,43 53,50 97,94 91,101 2,190 -2,188 -10,181 -55,136 -63,129 -96,96 -94,92 -74,72 -66,65 -28,27 -20,20 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E3}" Fill="White" />
<Polygon Canvas.Left="968" Canvas.Top="726" Points="0,0 20,0 53,1 109,57 117,64 126,73 123,82 105,125 87,168 74,199 73,200 -31,200 -67,164 -67,123 -66,68 -51,53 -44,45 -5,6 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B3}" Fill="White" />
<Polygon Canvas.Left="1053" Canvas.Top="939" Points="0,0 25,0 25,137 -110,137 -111,57 -111,1 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E4}" Fill="White" />
<Polygon Canvas.Left="794" Canvas.Top="900" Points="0,0 97,0 133,36 134,68 134,138 124,143 88,158 48,175 10,191 6,190 -3,181 -11,174 -65,120 -66,112 -67,68 -4,5 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B4}" Fill="White" />
<Polygon Canvas.Left="720" Canvas.Top="1034" Points="0,0 4,2 97,95 91,102 2,191 -2,189 -35,156 -43,149 -87,105 -95,98 -97,95 -90,88 -82,81 -44,43 -36,36 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E5}" Fill="White" />
<Polygon Canvas.Left="550" Canvas.Top="899" Points="0,0 97,1 143,47 150,55 163,68 164,121 92,193 83,190 37,171 -4,154 -37,140 -37,101 -36,37 -24,25 -17,17 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B5}" Fill="White" />
<Polygon Canvas.Left="474" Canvas.Top="939" Points="0,0 25,0 25,137 -110,137 -111,53 -111,1 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E6}" Fill="White" />
<Polygon Canvas.Left="420" Canvas.Top="727" Points="0,0 52,0 119,67 119,162 109,172 102,180 82,200 -20,200 -38,158 -50,129 -68,86 -73,73 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B6}" Fill="White" />
<Polygon Canvas.Left="311" Canvas.Top="623" Points="0,0 4,2 61,59 69,66 97,94 91,101 2,190 -2,189 -51,140 -59,133 -96,96 -94,92 -71,69 -63,62 -25,24 -17,17 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E7}" Fill="White" />
<Polygon Canvas.Left="401" Canvas.Top="512" Points="0,0 102,0 124,22 132,29 140,37 140,69 139,130 133,138 101,170 94,178 72,200 20,201 -53,128 -50,119 -31,74 -12,29 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B7}" Fill="White" />
<Polygon Canvas.Left="491" Canvas.Top="361" Points="0,0 8,0 8,137 -127,137 -128,53 -128,1 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E8}" Fill="White" />
<Polygon Canvas.Left="640" Canvas.Top="348" Points="0,0 8,6 74,72 73,124 45,152 38,160 17,181 10,189 8,191 -90,191 -127,154 -126,50 -88,35 -20,8 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B8}" Fill="White" />
<Polygon Canvas.Left="607" Canvas.Top="195" Points="0,113 113,0 226,113 113,226" Tag="{x:Static local:TouchValue.E1}" Fill="White" />
<Polygon Canvas.Left="720" Canvas.Top="346" Points="0,78 78,0 209,55 209,165 180,195 70,195 0,130" Tag="{x:Static local:TouchValue.B1}" Fill="White" />
<Polygon Canvas.Left="930" Canvas.Top="350" Points="0,0 0,160 160,160, 160,0 0,0" Tag="{x:Static local:TouchValue.E2}" Fill="White" />
<Polygon Canvas.Left="900" Canvas.Top="511" Points="117,209 195,132 140,0 30,0 0,30 0,139 65,209" Tag="{x:Static local:TouchValue.B2}" Fill="White" />
<Polygon Canvas.Left="1020" Canvas.Top="607" Points="0,113 113,0 226,113 113,226" Tag="{x:Static local:TouchValue.E3}" Fill="White" />
<Polygon Canvas.Left="900" Canvas.Top="721" Points="120,0 198,78 140,208 30,208 0,180 0,71 65,0" Tag="{x:Static local:TouchValue.B3}" Fill="White" />
<Polygon Canvas.Left="930" Canvas.Top="930" Points="0,0 0,160 160,160, 160,0 0,0" Tag="{x:Static local:TouchValue.E4}" Fill="White" />
<Polygon Canvas.Left="721" Canvas.Top="901" Points="0,112 87,198 208,140 208,29 177,0 71,0 0,65" Tag="{x:Static local:TouchValue.B4}" Fill="White" />
<Polygon Canvas.Left="607" Canvas.Top="1013" Points="0,113 113,0 226,113 113,226" Tag="{x:Static local:TouchValue.E5}" Fill="White" />
<Polygon Canvas.Left="512" Canvas.Top="901" Points="208,112 121,198 0,140 0,29 31,0 137,0 208,65" Tag="{x:Static local:TouchValue.B5}" Fill="White" />
<Polygon Canvas.Left="350" Canvas.Top="930" Points="0,0 0,160 160,160, 160,0 0,0" Tag="{x:Static local:TouchValue.E6}" Fill="White" />
<Polygon Canvas.Left="349" Canvas.Top="721" Points="78,0 0,78 58,208 163,208 193,180 193,71 133,0" Tag="{x:Static local:TouchValue.B6}" Fill="White" />
<Polygon Canvas.Left="200" Canvas.Top="607" Points="0,113 113,0 226,113 113,226" Tag="{x:Static local:TouchValue.E7}" Fill="White" />
<Polygon Canvas.Left="345" Canvas.Top="511" Points="82,209 0,127 55,0 165,0 195,30 195,139 137,209" Tag="{x:Static local:TouchValue.B7}" Fill="White" />
<Polygon Canvas.Left="350" Canvas.Top="350" Points="0,0 0,160 160,160, 160,0 0,0" Tag="{x:Static local:TouchValue.E8}" Fill="White" />
<Polygon Canvas.Left="511" Canvas.Top="346" Points="209,78 131,0 0,55 0,165 29,195 139,195 209,130" Tag="{x:Static local:TouchValue.B8}" Fill="White" />
<Polygon Canvas.Left="728" Canvas.Top="583" Points="0,0 51,0 65,14 72,22 129,79 129,193 100,222 93,230 65,258 58,266 50,274 10,273 0,272 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.C1}" Fill="White" />
<Polygon Canvas.Left="662" Canvas.Top="583" Points="0,0 52,0 52,267 51,273 2,273 -78,193 -78,80 -47,49 -40,41 -5,6 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.C2}" Fill="White" />
<Polygon Canvas.Left="714" Canvas.Top="583" Points="0,0 14,0 14,273 0,273 0,0" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.C3}" Fill="White" />
<Polygon Canvas.Left="720" Canvas.Top="583" Points="0,0 60,0 140,80 140,200 60,280 0,280 0,0" Tag="{x:Static local:TouchValue.C1}" Fill="White" />
<Polygon Canvas.Left="579" Canvas.Top="583" Points="141,280 81,280 0,199 1,81 81,0 141,0 141,280" Tag="{x:Static local:TouchValue.C2}" Fill="White" />
<Border x:Name="ResizeGrip" Width="150" Height="90" Background="White" MouseDown="ResizeGrip_MouseDown" Canvas.Left="1290" Canvas.Top="1350" HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock FontSize="50" Text="{Binding LbTouchPanelResize}" d:Text="Resize" />
<Border x:Name="ResizeGrip" Width="150" Height="90"
Style="{StaticResource ResizeGripStyle}"
MouseDown="ResizeGrip_MouseDown"
Canvas.Left="1290" Canvas.Top="1350"
HorizontalAlignment="Center" VerticalAlignment="Top">
<TextBlock FontSize="50" Text="{Binding LbTouchPanelResize}"
VerticalAlignment="Center" HorizontalAlignment="Center" d:Text="Resize"/>
</Border>
</Canvas>

View File

@ -1,6 +1,7 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
@ -17,7 +18,7 @@ public partial class TouchPanel : Window
internal Action<TouchValue>? onRelease;
internal Action? onInitialReposition;
private readonly Dictionary<int, Polygon> activeTouches = [];
private readonly Dictionary<int, (Polygon polygon, Point lastPoint)> activeTouches = new();
private readonly TouchPanelPositionManager _positionManager;
private List<Polygon> buttons = [];
private bool isDebugEnabled = Properties.Settings.Default.IsDebugEnabled;
@ -36,30 +37,94 @@ public partial class TouchPanel : Window
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
public enum SizingEdge
{
Left = 1,
Right = 2,
Top = 3,
TopLeft = 4,
TopRight = 5,
Bottom = 6,
BottomLeft = 7,
BottomRight = 8
}
private const double FixedAspectRatio = 720.0 / 1280.0; // width / height
private const int MinWidth = 180;
private const int MinHeight = 320;
public TouchPanel()
{
InitializeComponent();
Topmost = true;
_positionManager = new TouchPanelPositionManager();
Loaded += Window_Loaded;
StateCheckLoop();
Touch.FrameReported += OnTouchFrameReported;
}
private async void StateCheckLoop()
protected override void OnSourceInitialized(EventArgs e)
{
while (true)
base.OnSourceInitialized(e);
var source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(WndProc);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_SIZING = 0x0214;
if (msg == WM_SIZING)
{
if (activeTouches.Count != 0 && !TouchesOver.Any())
{
await Task.Delay(100);
if (activeTouches.Count != 0 && !TouchesOver.Any())
{
DeselectAllItems();
}
}
await Task.Delay(100);
var rect = Marshal.PtrToStructure<RECT>(lParam);
var edge = (SizingEdge)wParam.ToInt32();
EnforceAspectRatio(ref rect, edge);
Marshal.StructureToPtr(rect, lParam, true);
handled = true;
}
return IntPtr.Zero;
}
private void EnforceAspectRatio(ref RECT rect, SizingEdge edge)
{
var currentWidth = rect.Right - rect.Left;
var currentHeight = rect.Bottom - rect.Top;
int newWidth, newHeight;
if (edge == SizingEdge.BottomRight)
{
newWidth = (int)(currentHeight * FixedAspectRatio);
newHeight = currentHeight;
}
else
{
newHeight = (int)(currentWidth / FixedAspectRatio);
newWidth = currentWidth;
}
// Enforce minimum size while keeping the aspect ratio.
if (newWidth < MinWidth)
{
newWidth = MinWidth;
newHeight = (int)(newWidth / FixedAspectRatio);
}
if (newHeight < MinHeight)
{
newHeight = MinHeight;
newWidth = (int)(newHeight * FixedAspectRatio);
}
rect.Right = rect.Left + newWidth;
rect.Bottom = rect.Top + newHeight;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
@ -99,83 +164,111 @@ public partial class TouchPanel : Window
{
if (e.LeftButton == MouseButtonState.Pressed)
{
ResizeWindow(ResizeDirection.BottomRight);
ResizeWindow(SizingEdge.BottomRight);
}
}
private void ResizeWindow(ResizeDirection direction)
private void ResizeWindow(SizingEdge edge)
{
ReleaseCapture();
SendMessage(new System.Windows.Interop.WindowInteropHelper(this).Handle,
0x112, // WM_SYSCOMMAND message
(IntPtr)(0xF000 + direction),
IntPtr.Zero);
SendMessage(new WindowInteropHelper(this).Handle, 0x112, (IntPtr)(0xF000 + (int)edge), IntPtr.Zero);
}
private void Element_TouchDown(object sender, TouchEventArgs e)
private void OnTouchFrameReported(object sender, TouchFrameEventArgs e)
{
// Cast the sender to a Border to ensure it's the correct element type.
if (sender is Polygon element)
var currentTouchPoints = e.GetTouchPoints(this);
var currentIds = new HashSet<int>();
foreach (var touch in currentTouchPoints)
{
// Highlight the element and add it to the active touches tracking.
HighlightElement(element, true);
var touchValue = (TouchValue)element.Tag;
if (isRingButtonEmulationEnabled && RingButtonEmulator.HasRingButtonMapping((TouchValue)element.Tag))
var id = touch.TouchDevice.Id;
// If the touch is released, process it as a TouchUp.
if (touch.Action == TouchAction.Up)
{
RingButtonEmulator.PressButton((TouchValue)element.Tag);
if (activeTouches.TryGetValue(id, out var touchInfo2))
{
if (activeTouches.Values.Count(v => v.polygon == touchInfo2.polygon) == 1)
{
HighlightElement(touchInfo2.polygon, false);
onRelease?.Invoke((TouchValue)touchInfo2.polygon.Tag);
if (isRingButtonEmulationEnabled)
{
RingButtonEmulator.ReleaseButton((TouchValue)touchInfo2.polygon.Tag);
}
}
activeTouches.Remove(id);
}
continue;
}
currentIds.Add(id);
// New touch (TouchDown)
if (!activeTouches.TryGetValue(id, out var touchInfo))
{
if (VisualTreeHelper.HitTest(this, touch.Position)?.VisualHit is Polygon polygon)
{
HighlightElement(polygon, true);
activeTouches[id] = (polygon, touch.Position);
onTouch?.Invoke((TouchValue)polygon.Tag);
if (isRingButtonEmulationEnabled && RingButtonEmulator.HasRingButtonMapping((TouchValue)polygon.Tag))
{
RingButtonEmulator.PressButton((TouchValue)polygon.Tag);
}
}
}
// Existing touch (TouchMove)
else
{
onTouch?.Invoke((TouchValue)element.Tag);
}
activeTouches[e.TouchDevice.Id] = element;
}
e.Handled = true;
}
var previousPosition = touchInfo.lastPoint;
var currentPosition = touch.Position;
var sampleCount = 10;
var changed = false;
private void Element_TouchMove(object sender, TouchEventArgs e)
{
// Attempt to find the element under the current touch point.
var touchPoint = e.GetTouchPoint(this).Position;
var hitTestResult = VisualTreeHelper.HitTest(this, touchPoint);
if (hitTestResult != null && hitTestResult.VisualHit is Polygon newElement)
{
// If this touch point is already tracking another element, unhighlight the previous one.
if (activeTouches.TryGetValue(e.TouchDevice.Id, out var previousElement) && previousElement != newElement)
{
Task.Delay(50)
.ContinueWith(t =>
for (var i = 1; i <= sampleCount; i++)
{
var t = (double)i / sampleCount;
var samplePoint = new Point(
previousPosition.X + (currentPosition.X - previousPosition.X) * t,
previousPosition.Y + (currentPosition.Y - previousPosition.Y) * t);
if (VisualTreeHelper.HitTest(this, samplePoint)?.VisualHit is Polygon polygon && polygon != touchInfo.polygon)
{
HighlightElement(previousElement, false);
Application.Current.Dispatcher.Invoke(() =>
if (activeTouches.Values.Count(v => v.polygon == touchInfo.polygon) == 1)
{
onRelease?.Invoke((TouchValue)previousElement.Tag);
});
});
HighlightElement(touchInfo.polygon, false);
onRelease?.Invoke((TouchValue)touchInfo.polygon.Tag);
}
HighlightElement(polygon, true);
onTouch?.Invoke((TouchValue)polygon.Tag);
activeTouches[id] = (polygon, samplePoint);
changed = true;
break;
}
}
if (!changed)
{
activeTouches[id] = (touchInfo.polygon, currentPosition);
}
}
// Highlight the new element and update the tracking.
HighlightElement(newElement, true);
onTouch?.Invoke((TouchValue)newElement.Tag);
activeTouches[e.TouchDevice.Id] = newElement;
}
e.Handled = true;
}
private void Element_TouchUp(object sender, TouchEventArgs e)
{
// When touch is lifted, unhighlight the associated element and remove it from tracking.
if (activeTouches.TryGetValue(e.TouchDevice.Id, out var element))
// Process any touches that might not be reported this frame.
var endedTouches = activeTouches.Keys.Except(currentIds).ToList();
foreach (var id in endedTouches)
{
HighlightElement(element, false);
RingButtonEmulator.ReleaseButton((TouchValue)element.Tag);
onRelease?.Invoke((TouchValue)element.Tag);
activeTouches.Remove(e.TouchDevice.Id);
var touchInfo = activeTouches[id];
if (activeTouches.Values.Count(v => v.polygon == touchInfo.polygon) == 1)
{
HighlightElement(touchInfo.polygon, false);
onRelease?.Invoke((TouchValue)touchInfo.polygon.Tag);
if (isRingButtonEmulationEnabled)
{
RingButtonEmulator.ReleaseButton((TouchValue)touchInfo.polygon.Tag);
}
}
activeTouches.Remove(id);
}
e.Handled = true;
}
private void DeselectAllItems()
@ -183,8 +276,8 @@ public partial class TouchPanel : Window
// Logic to deselect all items or the last touched item
foreach (var element in activeTouches.Values)
{
HighlightElement(element, false);
onRelease?.Invoke((TouchValue)element.Tag);
HighlightElement(element.polygon, false);
onRelease?.Invoke((TouchValue)element.polygon.Tag);
}
activeTouches.Clear();
RingButtonEmulator.ReleaseAllButtons();
@ -199,6 +292,388 @@ public partial class TouchPanel : Window
});
}
public void SetLargeButtonMode(bool enabled)
{
TouchValue[] ringButtonsValues = {
TouchValue.A1,
TouchValue.A2,
TouchValue.A3,
TouchValue.A4,
TouchValue.A5,
TouchValue.A6,
TouchValue.A7,
TouchValue.A8,
TouchValue.D1,
TouchValue.D2,
TouchValue.D3,
TouchValue.D4,
TouchValue.D5,
TouchValue.D6,
TouchValue.D7,
TouchValue.D8,
};
var a1 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A1);
var a2 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A2);
var a3 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A3);
var a4 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A4);
var a5 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A5);
var a6 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A6);
var a7 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A7);
var a8 = buttons.First(button => (TouchValue)button.Tag == TouchValue.A8);
var d1 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D1);
var d2 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D2);
var d3 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D3);
var d4 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D4);
var d5 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D5);
var d6 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D6);
var d7 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D7);
var d8 = buttons.First(button => (TouchValue)button.Tag == TouchValue.D8);
if (enabled)
{
d1.Points = new PointCollection
{
new Point(-5, -50),
new Point(205, -50),
new Point(165, 253),
new Point(100, 188),
new Point(35, 253),
};
a1.Points = new PointCollection
{
new Point(495, -50),
new Point(208, 338),
new Point(145, 338),
new Point(49, 297),
new Point(0, 249),
new Point(42, -55),
};
d2.Points = new PointCollection
{
new Point(290, -182),
new Point(500, -180),
new Point(500, -5),
new Point(96, 297),
new Point(96, 205),
new Point(0, 205),
};
a2.Points = new PointCollection
{
new Point(405, 317),
new Point(91, 362),
new Point(42, 314),
new Point(0, 219),
new Point(0, 150),
new Point(405, -150),
};
d3.Points = new PointCollection
{
new Point(315, -10),
new Point(315, 208),
new Point(0, 165),
new Point(65, 100),
new Point(0, 35),
};
a3.Points = new PointCollection
{
new Point(406, 520),
new Point(0, 213),
new Point(0, 144),
new Point(41, 48),
new Point(89, 0),
new Point(406, 43),
};
d4.Points = new PointCollection
{
new Point(500, 309),
new Point(500, 491),
new Point(305, 491),
new Point(0, 92),
new Point(92, 92),
new Point(92, 0),
};
a4.Points = new PointCollection
{
new Point(45, 400),
new Point(0, 83),
new Point(48, 35),
new Point(144, 0),
new Point(212, 0),
new Point(515, 400),
};
d5.Points = new PointCollection
{
new Point(208, 317),
new Point(-10, 317),
new Point(34, 0),
new Point(99, 65),
new Point(164, 0),
};
a5.Points = new PointCollection
{
new Point(317, 400),
new Point(363, 83),
new Point(316, 35),
new Point(220, 0),
new Point(152, 0),
new Point(-150, 400),
};
d6.Points = new PointCollection
{
new Point(-10, 492),
new Point(-200, 492),
new Point(-200, 295),
new Point(199, 0),
new Point(199, 92),
new Point(291, 92),
};
a6.Points = new PointCollection
{
new Point(-67, 505),
new Point(333, 214),
new Point(333, 144),
new Point(296, 48),
new Point(248, 0),
new Point(-67, 45),
};
d7.Points = new PointCollection
{
new Point(-60, 207),
new Point(-60, -7),
new Point(253, 34),
new Point(188, 99),
new Point(253, 164),
};
a7.Points = new PointCollection
{
new Point(-65, 320),
new Point(248, 362),
new Point(297, 314),
new Point(333, 219),
new Point(333, 151),
new Point(-65, -150),
};
d8.Points = new PointCollection
{
new Point(-195, -10),
new Point(-195, -195),
new Point(-5, -195),
new Point(298, 199),
new Point(200, 199),
new Point(200, 291),
};
a8.Points = new PointCollection
{
new Point(-148, -55),
new Point(153, 338),
new Point(215, 338),
new Point(311, 297),
new Point(359, 249),
new Point(318, -55),
};
}
else
{
d1.Points = new PointCollection
{
new Point(0, 5),
new Point(50, 2),
new Point(100, 0),
new Point(150, 2),
new Point(200, 5),
new Point(165, 253),
new Point(100, 188),
new Point(35, 253),
};
a1.Points = new PointCollection
{
new Point(150, 28),
new Point(245, 65),
new Point(360, 133),
new Point(208, 338),
new Point(145, 338),
new Point(49, 297),
new Point(0, 249),
new Point(35, 0),
};
d2.Points = new PointCollection
{
new Point(153, 0),
new Point(187, 32),
new Point(225, 67),
new Point(259, 104),
new Point(295, 147),
new Point(96, 297),
new Point(96, 205),
new Point(0, 205),
};
a2.Points = new PointCollection
{
new Point(261, 101),
new Point(303, 195),
new Point(339, 327),
new Point(91, 362),
new Point(42, 314),
new Point(0, 219),
new Point(0, 150),
new Point(202, 0),
};
d3.Points = new PointCollection
{
new Point(248, 0),
new Point(251, 48),
new Point(253, 100),
new Point(251, 150),
new Point(247, 199),
new Point(0, 165),
new Point(65, 100),
new Point(0, 35),
};
a3.Points = new PointCollection
{
new Point(305, 150),
new Point(269, 246),
new Point(201, 364),
new Point(0, 213),
new Point(0, 144),
new Point(41, 48),
new Point(89, 0),
new Point(337, 34),
};
d4.Points = new PointCollection
{
new Point(292, 151),
new Point(260, 187),
new Point(225, 225),
new Point(188, 259),
new Point(151, 291),
new Point(0, 92),
new Point(92, 92),
new Point(92, 0),
};
a4.Points = new PointCollection
{
new Point(260, 259),
new Point(167, 301),
new Point(37, 335),
new Point(0, 83),
new Point(48, 35),
new Point(144, 0),
new Point(212, 0),
new Point(364, 200),
};
d5.Points = new PointCollection
{
new Point(199, 252),
new Point(151, 255),
new Point(99, 257),
new Point(49, 255),
new Point(0, 252),
new Point(34, 0),
new Point(99, 65),
new Point(164, 0),
};
a5.Points = new PointCollection
{
new Point(104, 259),
new Point(197, 301),
new Point(327, 335),
new Point(363, 83),
new Point(316, 35),
new Point(220, 0),
new Point(152, 0),
new Point(0, 201),
};
d6.Points = new PointCollection
{
new Point(140, 292),
new Point(104, 260),
new Point(66, 225),
new Point(32, 188),
new Point(0, 151),
new Point(199, 0),
new Point(199, 92),
new Point(291, 92),
};
a6.Points = new PointCollection
{
new Point(32, 150),
new Point(68, 246),
new Point(133, 365),
new Point(333, 214),
new Point(333, 144),
new Point(296, 48),
new Point(248, 0),
new Point(0, 35),
};
d7.Points = new PointCollection
{
new Point(5, 199),
new Point(2, 151),
new Point(0, 99),
new Point(2, 49),
new Point(6, 0),
new Point(253, 34),
new Point(188, 99),
new Point(253, 164),
};
a7.Points = new PointCollection
{
new Point(78, 101),
new Point(36, 195),
new Point(0, 327),
new Point(248, 362),
new Point(297, 314),
new Point(333, 219),
new Point(333, 151),
new Point(132, 0),
};
d8.Points = new PointCollection
{
new Point(0, 140),
new Point(32, 104),
new Point(67, 66),
new Point(104, 32),
new Point(145, 0),
new Point(298, 199),
new Point(200, 199),
new Point(200, 291),
};
a8.Points = new PointCollection
{
new Point(210, 28),
new Point(115, 65),
new Point(0, 138),
new Point(153, 338),
new Point(215, 338),
new Point(311, 297),
new Point(359, 249),
new Point(324, 0),
};
}
}
public void SetBorderMode(BorderSetting borderSetting, string borderColour)
{
if (borderSetting == BorderSetting.Rainbow)