mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-02-12 20:41:37 +00:00
Fixed shortcut key monitoring
This commit is contained in:
parent
18fa36c32b
commit
7ff53ebcae
@ -12,44 +12,37 @@
|
|||||||
@T("Press the desired key combination to set the shortcut. The shortcut will be registered globally and will work even when the app is not focused.")
|
@T("Press the desired key combination to set the shortcut. The shortcut will be registered globally and will work even when the app is not focused.")
|
||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
|
|
||||||
<MudPaper Class="pa-4 mb-3 d-flex align-center justify-center shortcut-capture-area"
|
<MudFocusTrap DefaultFocus="DefaultFocus.FirstChild">
|
||||||
Style="min-height: 80px; cursor: pointer;"
|
<MudTextField
|
||||||
Elevation="2"
|
@ref="@this.inputField"
|
||||||
@onclick="@this.FocusInput">
|
T="string"
|
||||||
@* Hidden input to capture keyboard events *@
|
Text="@this.ShowText"
|
||||||
<input type="text"
|
Variant="Variant.Outlined"
|
||||||
@ref="this.hiddenInput"
|
Label="@T("Define a shortcut")"
|
||||||
@onkeydown="@this.HandleKeyDown"
|
Placeholder="@T("Press a key combination...")"
|
||||||
style="position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none;"
|
Adornment="Adornment.Start"
|
||||||
autocomplete="off"
|
AdornmentIcon="@Icons.Material.Filled.Keyboard"
|
||||||
readonly />
|
Immediate="@true"
|
||||||
@if (string.IsNullOrWhiteSpace(this.currentShortcut))
|
TextUpdateSuppression="false"
|
||||||
{
|
OnKeyDown="@this.HandleKeyDown"
|
||||||
<MudText Typo="Typo.h6" Color="Color.Secondary">
|
OnBlur="@this.HandleBlur"
|
||||||
@T("Press a key combination...")
|
UserAttributes="@USER_INPUT_ATTRIBUTES"
|
||||||
</MudText>
|
AutoFocus="true"
|
||||||
}
|
KeyDownPreventDefault="true"
|
||||||
else
|
KeyUpPreventDefault="true"
|
||||||
{
|
HelperText="@T("Supported modifiers: Ctrl/Cmd, Shift, Alt.")"
|
||||||
<MudText Typo="Typo.h5" Color="Color.Primary">
|
Class="me-3"/>
|
||||||
@this.GetDisplayShortcut()
|
</MudFocusTrap>
|
||||||
</MudText>
|
|
||||||
}
|
|
||||||
</MudPaper>
|
|
||||||
|
|
||||||
@if (!string.IsNullOrWhiteSpace(this.validationMessage))
|
@if (!string.IsNullOrWhiteSpace(this.validationMessage))
|
||||||
{
|
{
|
||||||
<MudAlert Severity="@this.validationSeverity" Class="mb-3">
|
<MudAlert Severity="@this.validationSeverity" Variant="Variant.Filled" Class="mb-3">
|
||||||
@this.validationMessage
|
@this.validationMessage
|
||||||
</MudAlert>
|
</MudAlert>
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="mb-2">
|
|
||||||
@T("Supported modifiers: Ctrl/Cmd, Shift, Alt. Example: Ctrl+Shift+R")
|
|
||||||
</MudText>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<MudButton OnClick="@this.ClearShortcut" Variant="Variant.Text" Color="Color.Warning" StartIcon="@Icons.Material.Filled.Clear">
|
<MudButton OnClick="@this.ClearShortcut" Variant="Variant.Filled" Color="Color.Info" StartIcon="@Icons.Material.Filled.Clear">
|
||||||
@T("Clear Shortcut")
|
@T("Clear Shortcut")
|
||||||
</MudButton>
|
</MudButton>
|
||||||
<MudSpacer/>
|
<MudSpacer/>
|
||||||
|
|||||||
@ -29,44 +29,42 @@ public partial class ShortcutDialog : MSGComponentBase
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public string ShortcutName { get; set; } = string.Empty;
|
public string ShortcutName { get; set; } = string.Empty;
|
||||||
|
|
||||||
private ElementReference hiddenInput;
|
private static readonly Dictionary<string, object?> USER_INPUT_ATTRIBUTES = new();
|
||||||
|
|
||||||
private string currentShortcut = string.Empty;
|
private string currentShortcut = string.Empty;
|
||||||
private string validationMessage = string.Empty;
|
private string validationMessage = string.Empty;
|
||||||
private Severity validationSeverity = Severity.Info;
|
private Severity validationSeverity = Severity.Info;
|
||||||
private bool hasValidationError;
|
private bool hasValidationError;
|
||||||
|
|
||||||
// Current key state
|
//
|
||||||
|
// Current key state:
|
||||||
|
//
|
||||||
private bool hasCtrl;
|
private bool hasCtrl;
|
||||||
private bool hasShift;
|
private bool hasShift;
|
||||||
private bool hasAlt;
|
private bool hasAlt;
|
||||||
private bool hasMeta;
|
private bool hasMeta;
|
||||||
private string? currentKey;
|
private string? currentKey;
|
||||||
|
private MudTextField<string>? inputField;
|
||||||
private bool isFirstRender = true;
|
|
||||||
|
|
||||||
#region Overrides of ComponentBase
|
#region Overrides of ComponentBase
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
base.OnInitialized();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
// Configure the spellchecking for the user input:
|
||||||
|
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||||
|
|
||||||
this.currentShortcut = this.InitialShortcut;
|
this.currentShortcut = this.InitialShortcut;
|
||||||
this.ParseExistingShortcut();
|
this.ParseExistingShortcut();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
||||||
{
|
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
|
||||||
|
|
||||||
// Auto-focus the hidden input when the dialog opens
|
|
||||||
if (this.isFirstRender)
|
|
||||||
{
|
|
||||||
this.isFirstRender = false;
|
|
||||||
await this.hiddenInput.FocusAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private string ShowText => string.IsNullOrWhiteSpace(this.currentShortcut)
|
||||||
|
? T("Press a key combination...")
|
||||||
|
: this.GetDisplayShortcut();
|
||||||
|
|
||||||
private void ParseExistingShortcut()
|
private void ParseExistingShortcut()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(this.currentShortcut))
|
if (string.IsNullOrWhiteSpace(this.currentShortcut))
|
||||||
@ -107,15 +105,9 @@ public partial class ShortcutDialog : MSGComponentBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task FocusInput()
|
|
||||||
{
|
|
||||||
// Focus the hidden input to capture keyboard events
|
|
||||||
await this.hiddenInput.FocusAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HandleKeyDown(KeyboardEventArgs e)
|
private async Task HandleKeyDown(KeyboardEventArgs e)
|
||||||
{
|
{
|
||||||
// Ignore pure modifier key presses
|
// Ignore pure modifier key presses:
|
||||||
if (IsModifierKey(e.Code))
|
if (IsModifierKey(e.Code))
|
||||||
{
|
{
|
||||||
this.UpdateModifiers(e);
|
this.UpdateModifiers(e);
|
||||||
@ -124,10 +116,9 @@ public partial class ShortcutDialog : MSGComponentBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update modifiers
|
|
||||||
this.UpdateModifiers(e);
|
this.UpdateModifiers(e);
|
||||||
|
|
||||||
// Get the key
|
// Get the key:
|
||||||
this.currentKey = TranslateKeyCode(e.Code);
|
this.currentKey = TranslateKeyCode(e.Code);
|
||||||
|
|
||||||
// Validate: must have at least one modifier + a key
|
// Validate: must have at least one modifier + a key
|
||||||
@ -140,11 +131,10 @@ public partial class ShortcutDialog : MSGComponentBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the shortcut string
|
|
||||||
this.UpdateShortcutString();
|
this.UpdateShortcutString();
|
||||||
|
|
||||||
// Validate the shortcut
|
|
||||||
await this.ValidateShortcut();
|
await this.ValidateShortcut();
|
||||||
|
|
||||||
|
this.StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateModifiers(KeyboardEventArgs e)
|
private void UpdateModifiers(KeyboardEventArgs e)
|
||||||
@ -213,10 +203,7 @@ public partial class ShortcutDialog : MSGComponentBase
|
|||||||
|
|
||||||
private string GetDisplayShortcut()
|
private string GetDisplayShortcut()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(this.currentShortcut))
|
// Convert internal format to display format:
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
// Convert internal format to display format
|
|
||||||
return this.currentShortcut
|
return this.currentShortcut
|
||||||
.Replace("CmdOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl")
|
.Replace("CmdOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl")
|
||||||
.Replace("CommandOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl");
|
.Replace("CommandOrControl", OperatingSystem.IsMacOS() ? "Cmd" : "Ctrl");
|
||||||
@ -376,4 +363,10 @@ public partial class ShortcutDialog : MSGComponentBase
|
|||||||
// Default: return as-is
|
// Default: return as-is
|
||||||
_ => code,
|
_ => code,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void HandleBlur()
|
||||||
|
{
|
||||||
|
// Re-focus the input field to keep capturing keys:
|
||||||
|
this.inputField?.FocusAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user