Add project files.
|
@ -0,0 +1,9 @@
|
||||||
|
<Application x:Class="WpfMaiTouchEmulator.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:WpfMaiTouchEmulator"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WpfMaiTouchEmulator;
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
|
@ -0,0 +1,147 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WpfMaiTouchEmulator;
|
||||||
|
internal class MaiTouchComConnector
|
||||||
|
{
|
||||||
|
private static SerialPort? serialPort;
|
||||||
|
private bool isActiveMode;
|
||||||
|
private readonly MaiTouchSensorButtonStateManager _buttonState;
|
||||||
|
|
||||||
|
public Action<string> OnConnectStatusChange
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
public Action<string> OnDataSent
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
public Action<string> OnDataRecieved
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MaiTouchComConnector(MaiTouchSensorButtonStateManager buttonState)
|
||||||
|
{
|
||||||
|
_buttonState = buttonState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task startLoopAsync()
|
||||||
|
{
|
||||||
|
string virtualPort = "COM23"; // Adjust as needed
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
// Use setupc.exe to create a virtual COM port pair
|
||||||
|
//StartProcessWithAdminRights("C:\\Program Files (x86)\\com0com\\setupc.exe", $"PortName=COM3 PortName=COM23");
|
||||||
|
|
||||||
|
serialPort = new SerialPort(virtualPort, 9600, Parity.None, 8, StopBits.One);
|
||||||
|
serialPort.DataReceived += SerialPort_DataReceived;
|
||||||
|
serialPort.Open();
|
||||||
|
Console.WriteLine("Serial port opened successfully.");
|
||||||
|
OnConnectStatusChange("Connected");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Simulate receiving a STAT packet
|
||||||
|
// Keep the program running to simulate active mode
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (isActiveMode)
|
||||||
|
{
|
||||||
|
SendTouchscreenState();
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error opening serial port: {ex.Message}");
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
MessageBox.Show(ex.Message, "Error connecting to COM port", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
OnConnectStatusChange("Not Connected");
|
||||||
|
// Close the serial port when done
|
||||||
|
if (serialPort.IsOpen)
|
||||||
|
{
|
||||||
|
serialPort.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use setupc.exe to remove the virtual COM port pair with administrator privileges
|
||||||
|
//StartProcessWithAdminRights("C:\\Program Files (x86)\\com0com\\setupc.exe", $"remove 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
string recievedData = serialPort.ReadExisting();
|
||||||
|
var commands = recievedData.Split(new[] { '}' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (string command in commands)
|
||||||
|
{
|
||||||
|
string cleanedCommand = command.TrimStart('{');
|
||||||
|
// Implement your logic to process the received data here
|
||||||
|
Console.WriteLine($"Received data: {cleanedCommand}");
|
||||||
|
OnDataRecieved(cleanedCommand);
|
||||||
|
|
||||||
|
|
||||||
|
// Check if the received packet is a STAT packet
|
||||||
|
if (cleanedCommand == "STAT")
|
||||||
|
{
|
||||||
|
// Simulate entering active mode
|
||||||
|
isActiveMode = true;
|
||||||
|
Console.WriteLine("Entered Active Mode");
|
||||||
|
}
|
||||||
|
else if (cleanedCommand == "RSET")
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (cleanedCommand == "HALT")
|
||||||
|
{
|
||||||
|
isActiveMode = false;
|
||||||
|
}
|
||||||
|
else if (cleanedCommand[2] == 'r' || cleanedCommand[2] == 'k')
|
||||||
|
{
|
||||||
|
char leftOrRight = cleanedCommand[0];
|
||||||
|
char sensor = cleanedCommand[1];
|
||||||
|
char ratio = cleanedCommand[3];
|
||||||
|
|
||||||
|
// Create the new string in the specified format
|
||||||
|
string newString = $"({leftOrRight}{sensor}{cleanedCommand[2]}{ratio})";
|
||||||
|
serialPort.Write(newString);
|
||||||
|
OnDataSent(newString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine(cleanedCommand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendTouchscreenState()
|
||||||
|
{
|
||||||
|
var currentState = _buttonState.GetCurrentState();
|
||||||
|
serialPort?.Write(currentState, 0, currentState.Length);
|
||||||
|
//Console.WriteLine($"Sent Touchscreen State: {report}");*/
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,109 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace WpfMaiTouchEmulator;
|
||||||
|
|
||||||
|
enum TouchValue: long
|
||||||
|
{
|
||||||
|
A1 = 1 << 0, // 2^0
|
||||||
|
A2 = 1 << 1, // 2^1
|
||||||
|
A3 = 1 << 2, // 2^2
|
||||||
|
A4 = 1 << 3, // 2^3
|
||||||
|
A5 = 1 << 4, // 2^4
|
||||||
|
A6 = 1 << 5, // 2^5
|
||||||
|
A7 = 1 << 6, // 2^6
|
||||||
|
A8 = 1 << 7, // 2^7
|
||||||
|
B1 = 1 << 8, // 2^8
|
||||||
|
B2 = 1 << 9, // 2^9
|
||||||
|
B3 = 1 << 10, // 2^10
|
||||||
|
B4 = 1 << 11, // 2^11
|
||||||
|
B5 = 1 << 12, // 2^12
|
||||||
|
B6 = 1 << 13, // 2^13
|
||||||
|
B7 = 1 << 14, // 2^14
|
||||||
|
B8 = 1 << 15, // 2^15
|
||||||
|
C1 = 1 << 16, // 2^16
|
||||||
|
C2 = 1 << 17, // 2^17
|
||||||
|
D1 = 1 << 18, // 2^18
|
||||||
|
D2 = 1 << 19, // 2^19
|
||||||
|
D3 = 1 << 20, // 2^20
|
||||||
|
D4 = 1 << 21, // 2^21
|
||||||
|
D5 = 1 << 22, // 2^22
|
||||||
|
D6 = 1 << 23, // 2^23
|
||||||
|
D7 = 1 << 24, // 2^24
|
||||||
|
D8 = 1 << 25, // 2^25
|
||||||
|
E1 = 1 << 26, // 2^26
|
||||||
|
E2 = 1 << 27, // 2^27
|
||||||
|
E3 = 1 << 28, // 2^28
|
||||||
|
E4 = 1 << 29, // 2^29
|
||||||
|
E5 = 1 << 30, // 2^30
|
||||||
|
E6 = 1L << 31, // Note: Use 1L for long literals, as this and subsequent values exceed Int32.MaxValue
|
||||||
|
E7 = 1L << 32,
|
||||||
|
E8 = 1L << 33,
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class MaiTouchSensorButtonStateManager
|
||||||
|
{
|
||||||
|
static long buttonState = 0L;
|
||||||
|
private readonly Label buttonStateValue;
|
||||||
|
|
||||||
|
public MaiTouchSensorButtonStateManager(Label buttonStateValue)
|
||||||
|
{
|
||||||
|
this.buttonStateValue = buttonStateValue;
|
||||||
|
SetupUpdateLoop();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void SetupUpdateLoop()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
buttonStateValue.Content = buttonState.ToString();
|
||||||
|
});
|
||||||
|
await Task.Delay(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
buttonState = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PressButton(TouchValue button)
|
||||||
|
{
|
||||||
|
buttonState |= ((long)button);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReleaseButton(TouchValue button)
|
||||||
|
{
|
||||||
|
buttonState &= ~((long)button);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetCurrentState()
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
buttonStateValue.Content = buttonState.ToString();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return
|
||||||
|
[
|
||||||
|
0x28,
|
||||||
|
(byte)(buttonState & 0b11111),
|
||||||
|
(byte)(buttonState >> 5 & 0b11111),
|
||||||
|
(byte)(buttonState >> 10 & 0b11111),
|
||||||
|
(byte)(buttonState >> 15 & 0b11111),
|
||||||
|
(byte)(buttonState >> 20 & 0b11111),
|
||||||
|
(byte)(buttonState >> 25 & 0b11111),
|
||||||
|
(byte)(buttonState >> 30 & 0b11111),
|
||||||
|
0x29
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
<Window x:Class="WpfMaiTouchEmulator.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:WpfMaiTouchEmulator"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="MainWindow" Height="243" Width="800">
|
||||||
|
<Grid Background="Transparent">
|
||||||
|
<Button x:Name="ConnectToPortButton" Content="Connect to port" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Click="ConnectToPortButton_Click"/>
|
||||||
|
<Button x:Name="Touch_A1" Content="Touch A1" HorizontalAlignment="Left" Margin="10,92,0,0" VerticalAlignment="Top" PreviewMouseDown="Touch_A1_PreviewMouseDown" PreviewMouseUp="Touch_A1_PreviewMouseUp" />
|
||||||
|
<Button x:Name="Touch_A2_C1" Content="Touch A2 C1" HorizontalAlignment="Left" Margin="10,117,0,0" VerticalAlignment="Top" PreviewMouseUp="Touch_A2_C1_PreviewMouseUp" PreviewMouseDown="Touch_A2_C1_PreviewMouseDown" />
|
||||||
|
<TextBox x:Name="RecievedLogBox"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
AcceptsTab="True"
|
||||||
|
TextWrapping="Wrap" Margin="124,33,530,10" />
|
||||||
|
<TextBox x:Name="SentLogBox"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
AcceptsReturn="True"
|
||||||
|
AcceptsTab="True"
|
||||||
|
TextWrapping="Wrap" Margin="290,33,364,10" />
|
||||||
|
<Label x:Name="label" Content="Recieved" HorizontalAlignment="Left" Margin="124,7,0,0" VerticalAlignment="Top" Width="88"/>
|
||||||
|
<Label x:Name="label_Copy" Content="Sent" HorizontalAlignment="Left" Margin="290,7,0,0" VerticalAlignment="Top" Width="88"/>
|
||||||
|
<Label x:Name="label_Copy1" Content="Button State" HorizontalAlignment="Left" Margin="458,7,0,0" VerticalAlignment="Top" Width="88"/>
|
||||||
|
<Label x:Name="buttonStateValue" Content="0" HorizontalAlignment="Left" Margin="458,33,0,0" VerticalAlignment="Top" RenderTransformOrigin="3.566,1.468"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Window>
|
|
@ -0,0 +1,79 @@
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace WpfMaiTouchEmulator;
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
private MaiTouchSensorButtonStateManager buttonState;
|
||||||
|
private MaiTouchComConnector connector;
|
||||||
|
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
Title = "Mai Touch Emulator";
|
||||||
|
buttonState = new MaiTouchSensorButtonStateManager(buttonStateValue);
|
||||||
|
connector = new MaiTouchComConnector(buttonState);
|
||||||
|
connector.OnConnectStatusChange = (status) => Title = $"Mai Touch Emulator - {status}";
|
||||||
|
connector.OnDataSent = (data) =>
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
SentLogBox.AppendText(data + Environment.NewLine);
|
||||||
|
SentLogBox.ScrollToEnd();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
connector.OnDataRecieved = (data) =>
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
RecievedLogBox.AppendText(data + Environment.NewLine);
|
||||||
|
RecievedLogBox.ScrollToEnd();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var touchPanel = new TouchPanel();
|
||||||
|
touchPanel.onTouch = (value) => { buttonState.PressButton(value); };
|
||||||
|
touchPanel.onRelease = (value) => { buttonState.ReleaseButton(value); };
|
||||||
|
touchPanel.Show();
|
||||||
|
touchPanel.SetDebugMode(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ConnectToPortButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await connector.startLoopAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Touch_A1_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
buttonState.PressButton(TouchValue.A1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Touch_A1_PreviewMouseUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
buttonState.ReleaseButton(TouchValue.A1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Touch_A2_C1_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
buttonState.PressButton(TouchValue.A2);
|
||||||
|
buttonState.PressButton(TouchValue.C1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Touch_A2_C1_PreviewMouseUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
buttonState.ReleaseButton(TouchValue.A2);
|
||||||
|
buttonState.ReleaseButton(TouchValue.C1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
<Window x:Class="WpfMaiTouchEmulator.TouchPanel"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:WpfMaiTouchEmulator"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="TouchPanel" Height="820" Width="800"
|
||||||
|
AllowsTransparency="True" WindowStyle="None" Background="Transparent"
|
||||||
|
>
|
||||||
|
<Border Background="#01000000">
|
||||||
|
<StackPanel>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="0"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Border HorizontalAlignment="Left" VerticalAlignment="Top"
|
||||||
|
Height="20" Background="Gray" MouseLeftButtonDown="DragBar_MouseLeftButtonDown"
|
||||||
|
Cursor="SizeAll">
|
||||||
|
<Border Width="200" HorizontalAlignment="Right" Background="Transparent"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Resize handle in the top right corner -->
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Viewbox Stretch="Uniform" Opacity="1">
|
||||||
|
<Canvas Width="502" Height="502">
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A1.png" Canvas.Left="276" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A1}" Canvas.Top="3"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A2.png" Canvas.Left="382" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A2}" Canvas.Top="102"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A3.png" Canvas.Left="382" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A3}" Canvas.Top="276"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A4.png" Canvas.Left="276" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A4}" Canvas.Top="382"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A5.png" Canvas.Left="102" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A5}" Canvas.Top="382"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A6.png" Canvas.Left="4" HorizontalAlignment="Center" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A6}" Canvas.Top="276"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A7.png" Canvas.Left="3" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A7}" Canvas.Top="102"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\A8.png" Canvas.Left="102" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.A8}" Canvas.Top="3"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B1.png" Canvas.Left="254" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B1}" Canvas.Top="120"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B2.png" Canvas.Left="315" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B2}" Canvas.Top="178"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B3.png" Canvas.Left="315" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B3}" Canvas.Top="253"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B4.png" Canvas.Left="254" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B4}" Canvas.Top="314"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B5.png" Canvas.Left="178" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B5}" Canvas.Top="314"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B6.png" Canvas.Left="120" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B6}" Canvas.Top="253"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B7.png" Canvas.Left="120" HorizontalAlignment="Center" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B7}" Canvas.Top="178"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\B8.png" Canvas.Left="178" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.B8}" Canvas.Top="120"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\C1.png" Canvas.Left="254" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.C1}" Canvas.Top="203"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\C2.png" Canvas.Left="203" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.C2}" Canvas.Top="203"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D1.png" Canvas.Left="219" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D1}"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D2.png" Canvas.Left="354" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D2}" Canvas.Top="52"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D3.png" Canvas.Left="417" HorizontalAlignment="Center" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D3}" Canvas.Top="219"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D4.png" Canvas.Left="354" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D4}" Canvas.Top="353"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D5.png" Canvas.Left="219" HorizontalAlignment="Center" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D5}" Canvas.Top="416"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D6.png" Canvas.Left="53" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D6}" Canvas.Top="354"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D7.png" Canvas.Left="0" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D7}" Canvas.Top="218"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\D8.png" Canvas.Left="53" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.D8}" Canvas.Top="52"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E1.png" Canvas.Left="217" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E1}" Canvas.Top="73"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E2.png" Canvas.Left="329" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E2}" Canvas.Top="125"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E3.png" Canvas.Left="361" HorizontalAlignment="Left" VerticalAlignment="Center" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E3}" Canvas.Top="217"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E4.png" Canvas.Left="329" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E4}" Canvas.Top="328"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E5.png" Canvas.Left="217" HorizontalAlignment="Center" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E5}" Canvas.Top="361"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E6.png" Canvas.Left="125" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E6}" Canvas.Top="328"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E7.png" Canvas.Left="73" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E7}" Canvas.Top="217"/>
|
||||||
|
<Image Source="C:\Dev\WpfMaiTouchEmulator\assets\E8.png" Canvas.Left="125" HorizontalAlignment="Left" VerticalAlignment="Top" PreviewTouchDown="Element_TouchDown" PreviewTouchMove="Element_TouchMove" PreviewTouchUp="Element_TouchUp" Tag="{x:Static local:TouchValue.E8}" Canvas.Top="125"/>
|
||||||
|
<Border x:Name="ResizeGrip"
|
||||||
|
Width="20" Height="20" Background="White"
|
||||||
|
MouseDown="ResizeGrip_MouseDown" RenderTransformOrigin="19.05,-0.7" Canvas.Left="482" Canvas.Top="482"/>
|
||||||
|
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
</Window>
|
|
@ -0,0 +1,201 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using System.Windows.Media.Imaging; // For BitmapImage
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows.Interop; // For Imaging.CreateBitmapSourceFromHBitmap
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Windows.Controls.Primitives; // For Marshal
|
||||||
|
|
||||||
|
namespace WpfMaiTouchEmulator;
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for TouchPanel.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class TouchPanel : Window
|
||||||
|
{
|
||||||
|
internal Action<TouchValue> onTouch;
|
||||||
|
internal Action<TouchValue> onRelease;
|
||||||
|
private bool isResizing = false;
|
||||||
|
private System.Windows.Point clickPosition;
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern int SetWindowLong(IntPtr window, int index, int value);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern int GetWindowLong(IntPtr window, int index);
|
||||||
|
|
||||||
|
public const int GWL_EXSTYLE = -20;
|
||||||
|
public const int WS_EX_TRANSPARENT = 0x00000020;
|
||||||
|
public const int WS_EX_LAYERED = 0x00080000;
|
||||||
|
|
||||||
|
public TouchPanel()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.Topmost = true;
|
||||||
|
var positionManager = new TouchPanelPositionManager();
|
||||||
|
var position = positionManager.GetTouchPanelPosition();
|
||||||
|
if (position != null )
|
||||||
|
{
|
||||||
|
Top = position.Value.Top;
|
||||||
|
Left = position.Value.Left;
|
||||||
|
Width = position.Value.Width;
|
||||||
|
Height = position.Value.Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Loaded += new RoutedEventHandler(Window_Loaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Make the window transparent to input
|
||||||
|
var hwnd = new WindowInteropHelper(this).Handle;
|
||||||
|
//SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_TRANSPARENT | WS_EX_LAYERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
// This allows the entire window to be draggable
|
||||||
|
DragMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DragBar_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
// This event is for the draggable bar, it calls DragMove to move the window
|
||||||
|
DragMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResizeGrip_MouseDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.LeftButton == MouseButtonState.Pressed)
|
||||||
|
{
|
||||||
|
ResizeWindow(ResizeDirection.BottomRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ResizeDirection
|
||||||
|
{
|
||||||
|
BottomRight = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||||
|
private static extern bool ReleaseCapture();
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||||
|
private static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
private void ResizeWindow(ResizeDirection direction)
|
||||||
|
{
|
||||||
|
ReleaseCapture();
|
||||||
|
SendMessage(new System.Windows.Interop.WindowInteropHelper(this).Handle,
|
||||||
|
0x112, // WM_SYSCOMMAND message
|
||||||
|
(IntPtr)(0xF000 + direction),
|
||||||
|
IntPtr.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<int, System.Windows.Controls.Image> activeTouches = new Dictionary<int, System.Windows.Controls.Image>();
|
||||||
|
|
||||||
|
|
||||||
|
private void Element_TouchDown(object sender, TouchEventArgs e)
|
||||||
|
{
|
||||||
|
// Cast the sender to a Border to ensure it's the correct element type.
|
||||||
|
var element = sender as System.Windows.Controls.Image;
|
||||||
|
if (element != null)
|
||||||
|
{
|
||||||
|
// Highlight the element and add it to the active touches tracking.
|
||||||
|
HighlightElement(element, true);
|
||||||
|
onTouch((TouchValue)element.Tag);
|
||||||
|
activeTouches[e.TouchDevice.Id] = element;
|
||||||
|
}
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 System.Windows.Controls.Image newElement)
|
||||||
|
{
|
||||||
|
// If this touch point is already tracking another element, unhighlight the previous one.
|
||||||
|
if (activeTouches.TryGetValue(e.TouchDevice.Id, out System.Windows.Controls.Image previousElement) && previousElement != newElement)
|
||||||
|
{
|
||||||
|
HighlightElement(previousElement, false);
|
||||||
|
onRelease((TouchValue)previousElement.Tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlight the new element and update the tracking.
|
||||||
|
HighlightElement(newElement, true);
|
||||||
|
onTouch((TouchValue)newElement.Tag);
|
||||||
|
activeTouches[e.TouchDevice.Id] = newElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsTouchInsideWindow(touchPoint))
|
||||||
|
{
|
||||||
|
// Touch is outside the window, act accordingly
|
||||||
|
DeselectAllItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 System.Windows.Controls.Image element))
|
||||||
|
{
|
||||||
|
HighlightElement(element, false);
|
||||||
|
onRelease((TouchValue)element.Tag);
|
||||||
|
activeTouches.Remove(e.TouchDevice.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsTouchInsideWindow(System.Windows.Point touchPoint)
|
||||||
|
{
|
||||||
|
// Define the window's bounds
|
||||||
|
var windowBounds = new Rect(0, 0, this.ActualWidth, this.ActualHeight);
|
||||||
|
|
||||||
|
// Check if the touch point is within the window's bounds
|
||||||
|
return windowBounds.Contains(touchPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeselectAllItems()
|
||||||
|
{
|
||||||
|
// Logic to deselect all items or the last touched item
|
||||||
|
foreach (var element in activeTouches.Values)
|
||||||
|
{
|
||||||
|
HighlightElement(element, false);
|
||||||
|
}
|
||||||
|
activeTouches.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetDebugMode(bool enabled)
|
||||||
|
{
|
||||||
|
var buttons = VisualTreeHelperExtensions.FindVisualChildren<System.Windows.Controls.Image>(this);
|
||||||
|
buttons.ForEach(button =>
|
||||||
|
{
|
||||||
|
button.Opacity = enabled ? 0.3 : 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HighlightElement(System.Windows.Controls.Image element, bool highlight)
|
||||||
|
{
|
||||||
|
element.Opacity = highlight ? 0.8 : 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WpfMaiTouchEmulator
|
||||||
|
{
|
||||||
|
class TouchPanelPositionManager
|
||||||
|
{
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
|
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct RECT
|
||||||
|
{
|
||||||
|
public int Left;
|
||||||
|
public int Top;
|
||||||
|
public int Right;
|
||||||
|
public int Bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rect? GetTouchPanelPosition()
|
||||||
|
{
|
||||||
|
// Replace "OtherAppWindowName" with the window name (title) of the other application
|
||||||
|
IntPtr hWnd = FindWindow(null, "Sinmai");
|
||||||
|
if (hWnd != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
RECT rect;
|
||||||
|
if (GetWindowRect(hWnd, out rect))
|
||||||
|
{
|
||||||
|
// Calculate the desired size and position based on the other application's window
|
||||||
|
int width = Convert.ToInt32((rect.Right - rect.Left));
|
||||||
|
int height = width + 20;
|
||||||
|
int left = rect.Left + ((rect.Right - rect.Left) - width) / 2; // Center horizontally
|
||||||
|
int top = rect.Bottom - height;
|
||||||
|
return new Rect(left, top, width, height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("Failed to get window rect.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("Other application window not found.");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
public static class VisualTreeHelperExtensions
|
||||||
|
{
|
||||||
|
// Method to get all Image controls in the visual tree of a parent element
|
||||||
|
public static List<Image> FindVisualChildren<Image>(DependencyObject parent) where Image : DependencyObject
|
||||||
|
{
|
||||||
|
var images = new List<Image>();
|
||||||
|
|
||||||
|
// Recursive search of the visual tree to find all Image controls
|
||||||
|
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
||||||
|
{
|
||||||
|
var child = VisualTreeHelper.GetChild(parent, i);
|
||||||
|
if (child != null && child is Image)
|
||||||
|
{
|
||||||
|
images.Add((Image)child);
|
||||||
|
}
|
||||||
|
|
||||||
|
images.AddRange(FindVisualChildren<Image>(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
return images;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="8.0.1" />
|
||||||
|
<PackageReference Include="System.IO.Ports" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.8.34525.116
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfMaiTouchEmulator", "WpfMaiTouchEmulator.csproj", "{12065588-9C14-41F6-B866-76CAEBDF9E89}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{12065588-9C14-41F6-B866-76CAEBDF9E89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{12065588-9C14-41F6-B866-76CAEBDF9E89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{12065588-9C14-41F6-B866-76CAEBDF9E89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{12065588-9C14-41F6-B866-76CAEBDF9E89}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {54F9B40B-528A-4EBE-BE07-6DCB97467469}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
After Width: | Height: | Size: 724 B |
After Width: | Height: | Size: 777 B |
After Width: | Height: | Size: 779 B |
After Width: | Height: | Size: 697 B |
After Width: | Height: | Size: 781 B |
After Width: | Height: | Size: 731 B |
After Width: | Height: | Size: 732 B |
After Width: | Height: | Size: 783 B |
After Width: | Height: | Size: 420 B |
After Width: | Height: | Size: 451 B |
After Width: | Height: | Size: 440 B |
After Width: | Height: | Size: 397 B |
After Width: | Height: | Size: 408 B |
After Width: | Height: | Size: 445 B |
After Width: | Height: | Size: 444 B |
After Width: | Height: | Size: 412 B |
After Width: | Height: | Size: 361 B |
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 402 B |
After Width: | Height: | Size: 670 B |
After Width: | Height: | Size: 412 B |
After Width: | Height: | Size: 623 B |
After Width: | Height: | Size: 396 B |
After Width: | Height: | Size: 717 B |
After Width: | Height: | Size: 419 B |
After Width: | Height: | Size: 715 B |
After Width: | Height: | Size: 490 B |
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 490 B |
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 490 B |
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 490 B |
After Width: | Height: | Size: 172 B |
After Width: | Height: | Size: 42 KiB |