mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-13 12:33:48 +00:00
Added focused-window shortcut fallback on Linux (#882)
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
This commit is contained in:
1 parent
db508edc28
commit
1e5f07cb01
11 files changed
+350
-17
No files matched your search
@@ -15,7 +15,7 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
private IDialogService DialogService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
private GlobalShortcutService GlobalShortcutService { get; init; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The shortcut binding data.
|
||||
@@ -69,7 +69,7 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
{
|
||||
// Suspend shortcut processing while the dialog is open, so the user can
|
||||
// press the current shortcut to re-enter it without triggering the action:
|
||||
await this.RustService.SuspendShortcutProcessing();
|
||||
await this.GlobalShortcutService.SuspendShortcutProcessing();
|
||||
|
||||
try
|
||||
{
|
||||
@@ -106,7 +106,7 @@ public partial class ConfigurationShortcut : ConfigurationBaseCore
|
||||
finally
|
||||
{
|
||||
// Resume the shortcut processing when the dialog is closed:
|
||||
await this.RustService.ResumeShortcutProcessing();
|
||||
await this.GlobalShortcutService.ResumeShortcutProcessing();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
[Inject]
|
||||
private RustService RustService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private GlobalShortcutService GlobalShortcutService { get; init; } = null!;
|
||||
|
||||
[Inject]
|
||||
private ISnackbar Snackbar { get; init; } = null!;
|
||||
|
||||
@@ -35,6 +38,8 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
this.GlobalShortcutService.RuntimeStateChanged += this.OnShortcutRuntimeStateChanged;
|
||||
|
||||
// Register for global shortcut events:
|
||||
this.ApplyFilters([], [Event.TAURI_EVENT_RECEIVED, Event.VOICE_RECORDING_AVAILABILITY_CHANGED]);
|
||||
|
||||
@@ -43,8 +48,15 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender && this.ShouldRenderVoiceRecording)
|
||||
await this.EnsureSoundEffectsAvailableAsync("during the first interactive render");
|
||||
if (firstRender)
|
||||
{
|
||||
this.localShortcutDotNetReference = DotNetObjectReference.Create(this);
|
||||
this.localShortcutInteropReady = true;
|
||||
await this.ApplyLocalShortcutState(this.GlobalShortcutService.GetRuntimeState(Shortcut.VOICE_RECORDING_TOGGLE));
|
||||
|
||||
if (this.ShouldRenderVoiceRecording)
|
||||
await this.EnsureSoundEffectsAvailableAsync("during the first interactive render");
|
||||
}
|
||||
|
||||
await base.OnAfterRenderAsync(firstRender);
|
||||
}
|
||||
@@ -69,6 +81,36 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnShortcutRuntimeStateChanged(GlobalShortcutRuntimeState runtimeState)
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.InvokeAsync(() => this.ApplyLocalShortcutState(runtimeState));
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
this.Logger.LogDebug("Ignoring a shortcut state change after the voice recorder was disposed.");
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
this.Logger.LogDebug(ex, "The focused-window shortcut listener could not be updated because the component dispatcher is unavailable.");
|
||||
}
|
||||
}
|
||||
|
||||
[JSInvokable]
|
||||
public async Task OnLocalShortcutPressed()
|
||||
{
|
||||
var runtimeState = this.GlobalShortcutService.GetRuntimeState(Shortcut.VOICE_RECORDING_TOGGLE);
|
||||
if (runtimeState.Backend is not ShortcutBackend.LOCAL || runtimeState.IsSuspended)
|
||||
{
|
||||
this.Logger.LogDebug("Ignoring a stale focused-window shortcut event.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.Logger.LogInformation("Focused-window shortcut triggered for voice recording toggle.");
|
||||
await this.ToggleRecordingFromShortcut();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the recording state when triggered by a global shortcut.
|
||||
/// </summary>
|
||||
@@ -101,6 +143,48 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
private string? currentRecordingPath;
|
||||
private string? finalRecordingPath;
|
||||
private DotNetObjectReference<VoiceRecorder>? dotNetReference;
|
||||
private DotNetObjectReference<VoiceRecorder>? localShortcutDotNetReference;
|
||||
private bool localShortcutInteropReady;
|
||||
|
||||
private async Task ApplyLocalShortcutState(GlobalShortcutRuntimeState runtimeState)
|
||||
{
|
||||
if (!this.localShortcutInteropReady
|
||||
|| this.localShortcutDotNetReference is null
|
||||
|| runtimeState.ShortcutId is not Shortcut.VOICE_RECORDING_TOGGLE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (runtimeState.Backend is ShortcutBackend.LOCAL
|
||||
&& !runtimeState.IsSuspended
|
||||
&& !string.IsNullOrWhiteSpace(runtimeState.Shortcut))
|
||||
{
|
||||
await this.JsRuntime.InvokeVoidAsync(
|
||||
"localShortcut.register",
|
||||
"voice-recording-toggle",
|
||||
runtimeState.Shortcut,
|
||||
this.localShortcutDotNetReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
await this.JsRuntime.InvokeVoidAsync("localShortcut.unregister", "voice-recording-toggle");
|
||||
}
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
this.Logger.LogDebug("The focused-window shortcut listener could not be updated because the JS runtime disconnected.");
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
this.Logger.LogDebug("Updating the focused-window shortcut listener was canceled.");
|
||||
}
|
||||
catch (JSException ex)
|
||||
{
|
||||
this.Logger.LogWarning(ex, "Failed to update the focused-window shortcut listener.");
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldRenderVoiceRecording => PreviewFeatures.PRE_SPEECH_TO_TEXT_2026.IsEnabled(this.SettingsManager)
|
||||
&& !string.IsNullOrWhiteSpace(this.SettingsManager.ConfigurationData.App.UseTranscriptionProvider);
|
||||
@@ -482,6 +566,15 @@ public partial class VoiceRecorder : MSGComponentBase
|
||||
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
this.GlobalShortcutService.RuntimeStateChanged -= this.OnShortcutRuntimeStateChanged;
|
||||
|
||||
if (this.localShortcutInteropReady)
|
||||
_ = this.JsRuntime.InvokeVoidAsync("localShortcut.unregister", "voice-recording-toggle");
|
||||
|
||||
this.localShortcutDotNetReference?.Dispose();
|
||||
this.localShortcutDotNetReference = null;
|
||||
this.localShortcutInteropReady = false;
|
||||
|
||||
// Clean up recording resources if still active:
|
||||
if (this.currentRecordingStream is not null)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user