Skip to content

Commit fb4c6c2

Browse files
feat: adding setting to menu to skip tts messages
1 parent e977268 commit fb4c6c2

File tree

12 files changed

+305
-47
lines changed

12 files changed

+305
-47
lines changed

src/TwitchStreamingTools/Configuration.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
using Nullinside.Api.Common.Twitch;
1111

12+
using TwitchStreamingTools.Controls.ViewModels;
1213
using TwitchStreamingTools.Models;
1314
using TwitchStreamingTools.Utilities;
1415

@@ -85,6 +86,9 @@ public static Configuration Instance {
8586
/// <inheritdoc />
8687
public bool SayUsernameWithMessage { get; set; }
8788

89+
/// <inheritdoc />
90+
public Keybind? SkipTtsKey { get; set; } = new() { Key = Keys.End };
91+
8892
/// <summary>
8993
/// Writes the configuration file to disk.
9094
/// </summary>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<UserControl xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:viewModels="clr-namespace:TwitchStreamingTools.Controls.ViewModels"
6+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
7+
x:Class="TwitchStreamingTools.Controls.Keybind"
8+
x:DataType="viewModels:KeybindViewModel">
9+
<StackPanel>
10+
<Button Content="{Binding Keybind}" Command="{Binding ListenForKeystroke}" />
11+
</StackPanel>
12+
</UserControl>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Avalonia.Controls;
2+
3+
namespace TwitchStreamingTools.Controls;
4+
5+
/// <summary>
6+
/// Represents a keybind.
7+
/// </summary>
8+
public partial class Keybind : UserControl {
9+
/// <summary>
10+
/// Initializes a new instance of the <see cref="Keybind" /> class.
11+
/// </summary>
12+
public Keybind() {
13+
InitializeComponent();
14+
}
15+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System.Text;
2+
3+
using TwitchStreamingTools.Models;
4+
5+
namespace TwitchStreamingTools.Controls.ViewModels;
6+
7+
/// <summary>
8+
/// A keybind.
9+
/// </summary>
10+
public class Keybind {
11+
/// <summary>
12+
/// The key pressed.
13+
/// </summary>
14+
public Keys Key { get; set; }
15+
16+
/// <summary>
17+
/// Indicates whether the Control (Ctrl) key is pressed as part of the keybind.
18+
/// </summary>
19+
public bool IsCtrl { get; set; }
20+
21+
/// <summary>
22+
/// Indicates whether the Shift key is pressed as part of the keybind.
23+
/// </summary>
24+
public bool IsShift { get; set; }
25+
26+
/// <summary>
27+
/// Indicates whether the Alt key is pressed as part of the keybind.
28+
/// </summary>
29+
public bool IsAlt { get; set; }
30+
31+
/// <summary>
32+
/// Returns a string representation of the keybind, including any modifier keys (Ctrl, Shift, Alt) and the key itself.
33+
/// </summary>
34+
/// <returns>
35+
/// A string representing the current keybind in the format of "Ctrl + Shift + Alt + Key",
36+
/// including only the applicable modifiers.
37+
/// </returns>
38+
public override string ToString() {
39+
var sb = new StringBuilder();
40+
if (IsCtrl) {
41+
sb.Append("Ctrl + ");
42+
}
43+
44+
if (IsShift) {
45+
sb.Append("Shift + ");
46+
}
47+
48+
if (IsAlt) {
49+
sb.Append("Alt + ");
50+
}
51+
52+
sb.Append(Key);
53+
return sb.ToString();
54+
}
55+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Reactive;
2+
3+
using ReactiveUI;
4+
5+
using TwitchStreamingTools.Services;
6+
using TwitchStreamingTools.ViewModels;
7+
8+
namespace TwitchStreamingTools.Controls.ViewModels;
9+
10+
/// <summary>
11+
/// Handles storing information required to visualize a keybind.
12+
/// </summary>
13+
public class KeybindViewModel : ViewModelBase {
14+
/// <summary>
15+
/// The listener for keystrokes on the keyboard.
16+
/// </summary>
17+
private readonly IGlobalKeyPressService _service;
18+
19+
/// <summary>
20+
/// The keybind, if set.
21+
/// </summary>
22+
private Keybind? _keybind;
23+
24+
/// <summary>
25+
/// Initializes a new instance of the <see cref="KeybindViewModel" /> class.
26+
/// </summary>
27+
/// <param name="service">The listener for keystrokes on the keyboard.</param>
28+
public KeybindViewModel(IGlobalKeyPressService service) {
29+
_service = service;
30+
ListenForKeystroke = ReactiveCommand.Create(StartListenKeystroke);
31+
}
32+
33+
/// <summary>
34+
/// The keybind.
35+
/// </summary>
36+
public Keybind? Keybind {
37+
get => _keybind;
38+
set => this.RaiseAndSetIfChanged(ref _keybind, value);
39+
}
40+
41+
/// <summary>
42+
/// Listens for keystrokes.
43+
/// </summary>
44+
public ReactiveCommand<Unit, Unit> ListenForKeystroke { get; }
45+
46+
/// <summary>
47+
/// Starts listening for keystrokes.
48+
/// </summary>
49+
private void StartListenKeystroke() {
50+
_service.OnKeystroke -= OnKeystroke;
51+
_service.OnKeystroke += OnKeystroke;
52+
}
53+
54+
/// <summary>
55+
/// Called whenever a keystroke is pressed.
56+
/// </summary>
57+
/// <param name="keybind">The key that was press.</param>
58+
private void OnKeystroke(Keybind keybind) {
59+
if (_service.IsModifier(keybind.Key)) {
60+
return;
61+
}
62+
63+
Keybind = keybind;
64+
_service.OnKeystroke -= OnKeystroke;
65+
}
66+
}

src/TwitchStreamingTools/IConfiguration.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using Nullinside.Api.Common.Twitch;
44

5+
using TwitchStreamingTools.Controls.ViewModels;
56
using TwitchStreamingTools.Models;
67

78
namespace TwitchStreamingTools;
@@ -50,6 +51,11 @@ public interface IConfiguration {
5051
/// </summary>
5152
bool SayUsernameWithMessage { get; set; }
5253

54+
/// <summary>
55+
/// The key press to skip the TTS.
56+
/// </summary>
57+
Keybind? SkipTtsKey { get; set; }
58+
5359
/// <summary>
5460
/// Writes the configuration file to disk.
5561
/// </summary>

src/TwitchStreamingTools/ServiceCollectionExtensions.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using Nullinside.Api.Common.Twitch;
66

7+
using TwitchStreamingTools.Controls.ViewModels;
78
using TwitchStreamingTools.Services;
89
using TwitchStreamingTools.Utilities;
910
using TwitchStreamingTools.ViewModels;
@@ -25,7 +26,7 @@ public static void AddCommonServices(this IServiceCollection collection) {
2526
collection.AddSingleton<IConfiguration, Configuration>(_ => Configuration.Instance);
2627
collection.AddSingleton<ITwitchClientProxy, TwitchClientProxy>(_ => TwitchClientProxy.Instance);
2728
collection.AddSingleton<ITwitchChatLog, TwitchChatLog>();
28-
collection.AddSingleton<GlobalKeyPressService>();
29+
collection.AddSingleton<IGlobalKeyPressService, GlobalKeyPressService>();
2930

3031
// Services
3132
collection.AddSingleton<ITwitchAccountService, TwitchAccountService>();
@@ -39,6 +40,7 @@ public static void AddCommonServices(this IServiceCollection collection) {
3940
collection.AddTransient<SettingsViewModel>();
4041
collection.AddTransient<TtsPhoneticWordsViewModel>();
4142
collection.AddTransient<TtsSkipUsernamesViewModel>();
43+
collection.AddTransient<KeybindViewModel>();
4244
}
4345

4446
/// <summary>
@@ -48,6 +50,6 @@ public static void AddCommonServices(this IServiceCollection collection) {
4850
public static void StartupServices(this IServiceProvider provider) {
4951
provider.GetRequiredService<ITwitchAccountService>();
5052
provider.GetRequiredService<ITwitchTtsService>();
51-
provider.GetRequiredService<GlobalKeyPressService>();
53+
provider.GetRequiredService<IGlobalKeyPressService>();
5254
}
5355
}

src/TwitchStreamingTools/Services/GlobalKeyPressService.cs

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
4-
using System.Text;
54
using System.Threading;
65

76
using log4net;
87

98
using PInvoke;
109

10+
using TwitchStreamingTools.Controls.ViewModels;
1111
using TwitchStreamingTools.Models;
1212

1313
namespace TwitchStreamingTools.Services;
1414

1515
/// <summary>
1616
/// Detects when keys are pressed anywhere on the OS.
1717
/// </summary>
18-
public class GlobalKeyPressService {
18+
public class GlobalKeyPressService : IGlobalKeyPressService {
1919
/// <summary>
2020
/// The logger.
2121
/// </summary>
@@ -53,6 +53,11 @@ public class GlobalKeyPressService {
5353
/// </summary>
5454
private readonly Thread _thread;
5555

56+
/// <summary>
57+
/// The keystroke callback.
58+
/// </summary>
59+
private Action<Keybind>? s_onKeystroke;
60+
5661
/// <summary>
5762
/// Initializes a new instance of the <see cref="GlobalKeyPressService" /> class.
5863
/// </summary>
@@ -67,7 +72,15 @@ public GlobalKeyPressService() {
6772
/// <summary>
6873
/// Gets or sets the callbacks to invoke when a keystroke is pressed.
6974
/// </summary>
70-
public static Action<Keys, bool, bool, bool>? OnKeystroke { get; set; }
75+
public Action<Keybind>? OnKeystroke {
76+
get => s_onKeystroke;
77+
set => s_onKeystroke = value;
78+
}
79+
80+
/// <inheritdoc />
81+
public bool IsModifier(Keys key) {
82+
return modifiers.Contains(key);
83+
}
7184

7285
/// <summary>
7386
/// The main loop which registers for keystrokes on the system and flushes the message buffer.
@@ -90,7 +103,7 @@ private void Main() {
90103
/// <param name="wParam">The <seealso cref="KeyboardMessage" />.</param>
91104
/// <param name="lParam">The <seealso cref="KeyboardLowLevelHookStruct" />.</param>
92105
/// <returns>The next hook that should be called.</returns>
93-
private static int KeystrokeCallback(int nCode, IntPtr wParam, IntPtr lParam) {
106+
private int KeystrokeCallback(int nCode, IntPtr wParam, IntPtr lParam) {
94107
var keyboardEvent = Marshal.PtrToStructure<KeyboardLowLevelHookStruct>(lParam);
95108
var whatHappened = (KeyboardMessage)wParam;
96109
var key = (Keys)keyboardEvent.vkCode;
@@ -104,8 +117,14 @@ private static int KeystrokeCallback(int nCode, IntPtr wParam, IntPtr lParam) {
104117
bool holdingAlt = (keyboardEvent.flags & 0b_0001_0000) != 0;
105118
bool holdingCtrl = holding[Keys.Control] || holding[Keys.ControlKey] || holding[Keys.LControlKey] || holding[Keys.RControlKey];
106119
bool holdingShift = holding[Keys.Shift] || holding[Keys.ShiftKey] || holding[Keys.LShiftKey] || holding[Keys.RShiftKey];
107-
LogKey(key, holdingCtrl, holdingAlt, holdingShift);
108-
OnKeystroke?.Invoke(key, holdingCtrl, holdingAlt, holdingShift);
120+
var keybind = new Keybind {
121+
IsCtrl = holdingCtrl,
122+
IsShift = holdingShift,
123+
IsAlt = holdingAlt,
124+
Key = key
125+
};
126+
LogKey(keybind);
127+
s_onKeystroke?.Invoke(keybind);
109128
}
110129
else if (whatHappened == KeyboardMessage.KEY_UP) {
111130
if (modifiers.Contains(key)) {
@@ -119,26 +138,8 @@ private static int KeystrokeCallback(int nCode, IntPtr wParam, IntPtr lParam) {
119138
/// <summary>
120139
/// Logs the keystroke for debugging.
121140
/// </summary>
122-
/// <param name="key">The key pressed.</param>
123-
/// <param name="holdingCtrl">True if control is held down.</param>
124-
/// <param name="holdingAlt">True if alt is held down.</param>
125-
/// <param name="holdingShift">True if shift is held down.</param>
126-
private static void LogKey(Keys key, bool holdingCtrl, bool holdingAlt, bool holdingShift) {
127-
var sb = new StringBuilder("Key Pressed: ");
128-
if (holdingCtrl) {
129-
sb.Append("Ctrl + ");
130-
}
131-
132-
if (holdingShift) {
133-
sb.Append("Shift + ");
134-
}
135-
136-
if (holdingAlt) {
137-
sb.Append("Alt + ");
138-
}
139-
140-
sb.Append(key);
141-
142-
LOGGER.Debug(sb.ToString());
141+
/// <param name="keybind">The key pressed.</param>
142+
private void LogKey(Keybind keybind) {
143+
LOGGER.Debug($"Key pressed: {keybind}");
143144
}
144145
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
3+
using TwitchStreamingTools.Controls.ViewModels;
4+
using TwitchStreamingTools.Models;
5+
6+
namespace TwitchStreamingTools.Services;
7+
8+
/// <summary>
9+
/// The contract for a service that detects when keys are pressed anywhere on the OS.
10+
/// </summary>
11+
public interface IGlobalKeyPressService {
12+
/// <summary>
13+
/// Gets or sets the callbacks to invoke when a keystroke is pressed.
14+
/// </summary>
15+
Action<Keybind>? OnKeystroke { get; set; }
16+
17+
/// <summary>
18+
/// True if the key press is a modifier key and not a real keystroke.
19+
/// </summary>
20+
/// <param name="key">The key.</param>
21+
/// <returns>True if modifier, false otherwise.</returns>
22+
bool IsModifier(Keys key);
23+
}

0 commit comments

Comments
 (0)