diff --git a/App.config b/App.config
index 931ba7e..0ac343f 100644
--- a/App.config
+++ b/App.config
@@ -25,6 +25,9 @@
+
+ False
+
\ No newline at end of file
diff --git a/MaiTouchSensorButtonStateManager.cs b/MaiTouchSensorButtonStateManager.cs
index a8eb933..60edf2a 100644
--- a/MaiTouchSensorButtonStateManager.cs
+++ b/MaiTouchSensorButtonStateManager.cs
@@ -3,7 +3,7 @@
namespace WpfMaiTouchEmulator;
-enum TouchValue: long
+public enum TouchValue: long
{
A1 = 1 << 0, // 2^0
A2 = 1 << 1, // 2^1
diff --git a/MainWindow.xaml b/MainWindow.xaml
index 496243e..19321d3 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -5,7 +5,7 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Closing="MainWindow_Closing"
- Title="MainWindow" Height="360" Width="500" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
+ Title="MainWindow" Height="384" Width="500" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
-
+
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 1720de1..cc304a8 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -19,6 +19,7 @@ public MainWindow()
IsAutomaticPortConnectingEnabled = Properties.Settings.Default.IsAutomaticPortConnectingEnabled,
IsAutomaticPositioningEnabled = Properties.Settings.Default.IsAutomaticPositioningEnabled,
IsExitWithSinmaiEnabled = Properties.Settings.Default.IsExitWithSinmaiEnabled,
+ IsRingButtonEmulationEnabled = Properties.Settings.Default.IsRingButtonEmulationEnabled
};
Title = "Mai Touch Emulator";
@@ -241,4 +242,14 @@ private void instructionsLabel_Click(object sender, RoutedEventArgs e)
{
ShowSetupInstructionsDialog();
}
+
+ private void emulateRingButtons_Click(object sender, RoutedEventArgs e)
+ {
+ var dataContext = (MainWindowViewModel)DataContext;
+ var enabled = !dataContext.IsRingButtonEmulationEnabled;
+ dataContext.IsRingButtonEmulationEnabled = !enabled;
+ Properties.Settings.Default.IsRingButtonEmulationEnabled = dataContext.IsRingButtonEmulationEnabled;
+ Properties.Settings.Default.Save();
+ _touchPanel.SetEmulateRingButton(dataContext.IsRingButtonEmulationEnabled);
+ }
}
diff --git a/MainWindowViewModel.cs b/MainWindowViewModel.cs
index 018cdf8..2dbffa7 100644
--- a/MainWindowViewModel.cs
+++ b/MainWindowViewModel.cs
@@ -40,6 +40,10 @@ public string LbExitWithSinmai
{
get; set;
}
+ public string LbEmulateRingButtons
+ {
+ get; set;
+ }
public string LbInstallComPort
{
get; set;
@@ -174,12 +178,18 @@ public string? LbExitWithSinmaiTT
get;
private set;
}
+ public string? LbEmulateRingButtonsTT
+ {
+ get;
+ private set;
+ }
private bool _isAutomaticPortConnectingEnabled;
private bool _isDebugEnabled;
private bool _isAutomaticPositioningEnabled;
private bool _isExitWithSinmaiEnabled;
private CultureInfo _selectedLanguage;
+ private bool _isRingButtonEmulationEnabled;
private readonly ResourceManager resourceManager;
private readonly CultureInfo cultureInfo;
@@ -248,6 +258,17 @@ public bool IsExitWithSinmaiEnabled
}
}
+ public bool IsRingButtonEmulationEnabled
+ {
+ get => _isRingButtonEmulationEnabled;
+ set
+ {
+ _isRingButtonEmulationEnabled = value;
+ OnPropertyChanged();
+ }
+ }
+
+
public CultureInfo SelectedLanguage
{
get => _selectedLanguage;
@@ -282,6 +303,7 @@ private void UpdateLocalizedResources(ResourceManager resourceManager)
LbConnectToPort = resourceManager.GetString("lbConnectToPort");
LbDebugMode = resourceManager.GetString("lbDebugMode");
LbExitWithSinmai = resourceManager.GetString("lbExitWithSinmai");
+ LbEmulateRingButtons = resourceManager.GetString("lbEmulateRingButtons");
LbInstallComPort = resourceManager.GetString("lbInstallComPort");
LbLanguageDropdown = resourceManager.GetString("lbLanguageDropdown");
LbListComPorts = resourceManager.GetString("lbListComPorts");
@@ -294,6 +316,7 @@ private void UpdateLocalizedResources(ResourceManager resourceManager)
LbAutoPortConnectingTT = resourceManager.GetString("lbAutoPortConnectingTT");
LbAutoSensorPositioningTT = resourceManager.GetString("lbAutoSensorPositioningTT");
LbExitWithSinmaiTT = resourceManager.GetString("lbExitWithSinmaiTT");
+ LbEmulateRingButtonsTT = resourceManager.GetString("lbEmulateRingButtonsTT");
LbMenuCategoryHelp = resourceManager.GetString("lbMenuCategoryHelp");
LbMenuItemSetup = resourceManager.GetString("lbMenuItemSetup");
diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs
index e07e5ad..c5d6f88 100644
--- a/Properties/Settings.Designer.cs
+++ b/Properties/Settings.Designer.cs
@@ -94,5 +94,17 @@ public string UserLanguage {
this["UserLanguage"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("False")]
+ public bool IsRingButtonEmulationEnabled {
+ get {
+ return ((bool)(this["IsRingButtonEmulationEnabled"]));
+ }
+ set {
+ this["IsRingButtonEmulationEnabled"] = value;
+ }
+ }
}
}
diff --git a/Properties/Settings.settings b/Properties/Settings.settings
index f6efed3..0a7a5af 100644
--- a/Properties/Settings.settings
+++ b/Properties/Settings.settings
@@ -20,5 +20,8 @@
+
+ False
+
\ No newline at end of file
diff --git a/Resources/Strings.Designer.cs b/Resources/Strings.Designer.cs
index e305b0a..9d195f4 100644
--- a/Resources/Strings.Designer.cs
+++ b/Resources/Strings.Designer.cs
@@ -141,6 +141,24 @@ internal static string lbDebugMode {
}
}
+ ///
+ /// Looks up a localized string similar to Emulate ring buttons.
+ ///
+ internal static string lbEmulateRingButtons {
+ get {
+ return ResourceManager.GetString("lbEmulateRingButtons", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Useful when navigating the menus without a keyboard.
+ ///
+ internal static string lbEmulateRingButtonsTT {
+ get {
+ return ResourceManager.GetString("lbEmulateRingButtonsTT", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Exit when Sinmai exits.
///
diff --git a/Resources/Strings.ja-JP.resx b/Resources/Strings.ja-JP.resx
index ab01da5..116a667 100644
--- a/Resources/Strings.ja-JP.resx
+++ b/Resources/Strings.ja-JP.resx
@@ -144,6 +144,12 @@
デバッグモード
+
+ リングボタンをエミュレートする
+
+
+ キーボードがないときにメニュー操作に便利
+
Sinmai終了時に終了
diff --git a/Resources/Strings.resx b/Resources/Strings.resx
index a098532..6486235 100644
--- a/Resources/Strings.resx
+++ b/Resources/Strings.resx
@@ -144,6 +144,12 @@
Debug mode
+
+ Emulate ring buttons
+
+
+ Useful when navigating the menus without a keyboard
+
Exit when Sinmai exits
diff --git a/Resources/Strings.zh-CN.resx b/Resources/Strings.zh-CN.resx
index c0b4e34..27e69ba 100644
--- a/Resources/Strings.zh-CN.resx
+++ b/Resources/Strings.zh-CN.resx
@@ -144,6 +144,12 @@
调试模式
+
+ 模拟环形按钮
+
+
+ 在没有键盘的情况下导航菜单时很有用
+
随Sinmai退出
diff --git a/RingButtonEmulator.cs b/RingButtonEmulator.cs
new file mode 100644
index 0000000..ce00e48
--- /dev/null
+++ b/RingButtonEmulator.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace WpfMaiTouchEmulator;
+public partial class RingButtonEmulator
+{
+
+ [DllImport("user32.dll")]
+ static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
+
+ private static readonly IDictionary touchRingMapping = new Dictionary()
+ {
+ { TouchValue.A1, 0x57 }, // W
+ { TouchValue.A2, 0x45 }, // E
+ { TouchValue.A3, 0x44 }, // D
+ { TouchValue.A4, 0x43 }, // C
+ { TouchValue.A5, 0x58 }, // X
+ { TouchValue.A6, 0x5A }, // Z
+ { TouchValue.A7, 0x41 }, // A
+ { TouchValue.A8, 0x51 }, // Q
+ };
+ private const uint KEYEVENTF_KEYUP = 0x0002;
+
+ public static bool HasRingButtonMapping(TouchValue touchValue)
+ {
+ return touchRingMapping.ContainsKey(touchValue);
+ }
+
+ public static void PressButton(TouchValue touchValue)
+ {
+ if (touchRingMapping.TryGetValue(touchValue, out var vk))
+ {
+ keybd_event(vk, 0, 0, UIntPtr.Zero);
+ }
+ }
+
+ public static void ReleaseButton(TouchValue touchValue)
+ {
+ if (touchRingMapping.TryGetValue(touchValue, out var vk))
+ {
+ keybd_event(vk, 0, KEYEVENTF_KEYUP, UIntPtr.Zero);
+ }
+ }
+
+ public static void ReleaseAllButtons()
+ {
+ foreach (var vk in touchRingMapping.Values)
+ {
+ keybd_event(vk, 0, KEYEVENTF_KEYUP, UIntPtr.Zero);
+ }
+ }
+}
diff --git a/TouchPanel.xaml.cs b/TouchPanel.xaml.cs
index 6bf10fc..82ca19a 100644
--- a/TouchPanel.xaml.cs
+++ b/TouchPanel.xaml.cs
@@ -17,6 +17,7 @@ public partial class TouchPanel : Window
private readonly TouchPanelPositionManager _positionManager;
private List buttons = [];
private bool isDebugEnabled = Properties.Settings.Default.IsDebugEnabled;
+ private bool isRingButtonEmulationEnabled = Properties.Settings.Default.IsRingButtonEmulationEnabled;
private enum ResizeDirection
{
@@ -106,7 +107,15 @@ private void Element_TouchDown(object sender, TouchEventArgs e)
{
// Highlight the element and add it to the active touches tracking.
HighlightElement(element, true);
- onTouch?.Invoke((TouchValue)element.Tag);
+ var touchValue = (TouchValue)element.Tag;
+ if (isRingButtonEmulationEnabled && RingButtonEmulator.HasRingButtonMapping((TouchValue)element.Tag))
+ {
+ RingButtonEmulator.PressButton((TouchValue)element.Tag);
+ }
+ else
+ {
+ onTouch?.Invoke((TouchValue)element.Tag);
+ }
activeTouches[e.TouchDevice.Id] = element;
}
e.Handled = true;
@@ -149,6 +158,7 @@ private void Element_TouchUp(object sender, TouchEventArgs e)
if (activeTouches.TryGetValue(e.TouchDevice.Id, out var element))
{
HighlightElement(element, false);
+ RingButtonEmulator.ReleaseButton((TouchValue)element.Tag);
onRelease?.Invoke((TouchValue)element.Tag);
activeTouches.Remove(e.TouchDevice.Id);
}
@@ -165,6 +175,7 @@ private void DeselectAllItems()
onRelease?.Invoke((TouchValue)element.Tag);
}
activeTouches.Clear();
+ RingButtonEmulator.ReleaseAllButtons();
}
public void SetDebugMode(bool enabled)
@@ -176,6 +187,11 @@ public void SetDebugMode(bool enabled)
});
}
+ public void SetEmulateRingButton(bool enabled)
+ {
+ isRingButtonEmulationEnabled = enabled;
+ }
+
private void HighlightElement(Polygon element, bool highlight)
{
if (isDebugEnabled)