Add project files.

pull/7/head
ScottM 2024-02-08 17:41:21 +13:00
parent 2bcca49c6c
commit 52cc91d2f8
48 changed files with 800 additions and 0 deletions

9
App.xaml 100644
View File

@ -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>

12
App.xaml.cs 100644
View File

@ -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
{
}

10
AssemblyInfo.cs 100644
View File

@ -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)
)]

View File

@ -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}");*/
}
}

View File

@ -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
];
}
}

34
MainWindow.xaml 100644
View File

@ -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>

79
MainWindow.xaml.cs 100644
View File

@ -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);
}
}

74
TouchPanel.xaml 100644
View File

@ -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>

201
TouchPanel.xaml.cs 100644
View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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

BIN
assets/A1.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

BIN
assets/A2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

BIN
assets/A3.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

BIN
assets/A4.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 697 B

BIN
assets/A5.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 B

BIN
assets/A6.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 731 B

BIN
assets/A7.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

BIN
assets/A8.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 783 B

BIN
assets/B1.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

BIN
assets/B2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

BIN
assets/B3.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

BIN
assets/B4.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

BIN
assets/B5.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

BIN
assets/B6.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

BIN
assets/B7.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

BIN
assets/B8.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

BIN
assets/C1.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

BIN
assets/C2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

BIN
assets/D1.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

BIN
assets/D2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

BIN
assets/D3.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

BIN
assets/D4.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

BIN
assets/D5.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

BIN
assets/D6.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

BIN
assets/D7.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 419 B

BIN
assets/D8.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

BIN
assets/E1.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

BIN
assets/E2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

BIN
assets/E3.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

BIN
assets/E4.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

BIN
assets/E5.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

BIN
assets/E6.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

BIN
assets/E7.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

BIN
assets/E8.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB