diff --git a/Text-Grab/App.xaml.cs b/Text-Grab/App.xaml.cs index 662c6703..f84fd237 100644 --- a/Text-Grab/App.xaml.cs +++ b/Text-Grab/App.xaml.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Media; @@ -234,6 +235,9 @@ private void appExit(object sender, ExitEventArgs e) private async void appStartup(object sender, StartupEventArgs e) { + if (checkForAdminWindow(e.Args)) + return; + NumberOfRunningInstances = Process.GetProcessesByName("Text-Grab").Length; Current.DispatcherUnhandledException += CurrentDispatcherUnhandledException; @@ -272,6 +276,23 @@ private async void appStartup(object sender, StartupEventArgs e) DefaultLaunch(); } + private bool checkForAdminWindow(string[] args) + { + WindowCollection allWindows = Current.Windows; + + foreach (Window window in allWindows) + if (window is AdminWindow) + return true; + + if (args.Length == 0 || !args.Contains("admin")) + return false; + + AdminWindow aw = new(); + aw.Show(); + + return true; + } + private void CurrentDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { // unhandled exceptions thrown from UI thread diff --git a/Text-Grab/Pages/LanguageSettings.xaml b/Text-Grab/Pages/LanguageSettings.xaml index a4b64540..d134975e 100644 --- a/Text-Grab/Pages/LanguageSettings.xaml +++ b/Text-Grab/Pages/LanguageSettings.xaml @@ -25,6 +25,14 @@ Click="HyperlinkButton_Click" Content="How to install OCR languages with PowerShell" NavigateUri="https://learn.microsoft.com/en-us/windows/powertoys/text-extractor#how-to-query-for-ocr-language-packs" /> + + + -/// Interaction logic for LanguageSettings.xaml -/// public partial class LanguageSettings : Page { private readonly Settings DefaultSettings = AppUtilities.TextGrabSettings; @@ -47,7 +44,7 @@ private async void Page_Loaded(object sender, RoutedEventArgs e) private void LoadWindowsLanguages() { WindowsLanguagesListView.Items.Clear(); - List possibleOCRLanguages = OcrEngine.AvailableRecognizerLanguages.ToList(); + List possibleOCRLanguages = [.. OcrEngine.AvailableRecognizerLanguages]; foreach (Language language in possibleOCRLanguages) WindowsLanguagesListView.Items.Add(language); } @@ -155,4 +152,44 @@ private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) { UseShellExecute = true }); e.Handled = true; } + + private void InstalWindowsLangButton_Click(object sender, RoutedEventArgs e) + { + if (AppContext.BaseDirectory is not string exeDir) + return; + + string exePath = Path.Combine(exeDir, "Text-Grab.exe"); + + ProcessStartInfo startInfo = new() + { + UseShellExecute = true, + WorkingDirectory = Environment.CurrentDirectory, + FileName = exePath, + Verb = "runas", + Arguments = "admin", + WindowStyle = ProcessWindowStyle.Normal + }; + + try + { + Process? process = Process.Start(startInfo); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } +} + + +public record LangListItem +{ + public string RightPart { get; set; } = string.Empty; + + public string LeftPart { get; set; } = string.Empty; + + public override string ToString() + { + return string.Join(' ', [LeftPart, RightPart]); + } } diff --git a/Text-Grab/Text-Grab.csproj b/Text-Grab/Text-Grab.csproj index 6ccd2424..4d3afbf5 100644 --- a/Text-Grab/Text-Grab.csproj +++ b/Text-Grab/Text-Grab.csproj @@ -71,6 +71,7 @@ + diff --git a/Text-Grab/Utilities/WindowsLanguageUtilities.cs b/Text-Grab/Utilities/WindowsLanguageUtilities.cs new file mode 100644 index 00000000..c6abeaeb --- /dev/null +++ b/Text-Grab/Utilities/WindowsLanguageUtilities.cs @@ -0,0 +1,58 @@ +namespace Text_Grab.Utilities; +public class WindowsLanguageUtilities +{ + public static string PowerShellCommandForInstallingWithTag(string languageTag) + { + // $Capability = Get-WindowsCapability -Online | Where-Object { $_.Name -Like 'Language.OCR*en-US*' } + return $"$Capability = Get-WindowsCapability -Online | Where-Object {{ $_.Name -Like 'Language.OCR*{languageTag}*' }}; $Capability | Add-WindowsCapability -Online"; + } + + public static string DismLanguageCommand(string languageTag) + { + return $"Language.OCR~~~{languageTag}"; + } + + public static string PowerShellCommandForUninstallingWithTag(string languageTag) + { + // $Capability = Get-WindowsCapability -Online | Where-Object { $_.Name -Like 'Language.OCR*en-US*' } + return $"$Capability = Get-WindowsCapability -Online | Where-Object {{ $_.Name -Like 'Language.OCR*{languageTag}*' }}; $Capability | Remove-WindowsCapability -Online"; + } + + public static readonly string[] AllLanguages = [ + "ar-SA", + "bg-BG", + "bs-LATN-BA", + "cs-CZ", + "da-DK", + "de-DE", + "el-GR", + "en-GB", + "en-US", + "es-ES", + "es-MX", + "fi-FI", + "fr-CA", + "fr-FR", + "hr-HR", + "hu-HU", + "it-IT", + "ja-JP", + "ko-KR", + "nb-NO", + "nl-NL", + "pl-PL", + "pt-BR", + "pt-PT", + "ro-RO", + "ru-RU", + "sk-SK", + "sl-SI", + "sr-CYRL-RS", + "sr-LATN-RS", + "sv-SE", + "tr-TR", + "zh-CN", + "zh-HK", + "zh-TW", + ]; +} diff --git a/Text-Grab/Views/AdminWindow.xaml b/Text-Grab/Views/AdminWindow.xaml new file mode 100644 index 00000000..044b2c39 --- /dev/null +++ b/Text-Grab/Views/AdminWindow.xaml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Text-Grab/Views/AdminWindow.xaml.cs b/Text-Grab/Views/AdminWindow.xaml.cs new file mode 100644 index 00000000..5ff5eacb --- /dev/null +++ b/Text-Grab/Views/AdminWindow.xaml.cs @@ -0,0 +1,98 @@ +using Microsoft.Dism; +using System; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; +using Text_Grab.Pages; +using Text_Grab.Utilities; + +namespace Text_Grab.Views; + +public partial class AdminWindow : Wpf.Ui.Controls.FluentWindow +{ + public AdminWindow() + { + InitializeComponent(); + + AllWindowsLanguagesComboBox.Items.Clear(); + foreach (string textName in WindowsLanguageUtilities.AllLanguages) + { + CultureInfo languageCulture = new(textName); + string paddedTextName = textName.PadRight(12); + LangListItem langListItem = new() + { + LeftPart = paddedTextName, + RightPart = languageCulture.DisplayName + }; + AllWindowsLanguagesComboBox.Items.Add(langListItem); + } + + DismApi.Initialize(DismLogLevel.LogErrorsWarnings); + } + + private void Window_Closed(object sender, EventArgs e) + { + DismApi.Shutdown(); + Application.Current.Shutdown(); + } + + private async void InstalWindowsLangButton_Click(object sender, RoutedEventArgs e) + { + if (AllWindowsLanguagesComboBox.SelectedItem is not LangListItem pickedLanguageFile) + return; + + using DismSession session = DismApi.OpenOnlineSession(); + + DismCapability? langToInstall = DismApi.GetCapabilities(session).FirstOrDefault(cap => cap.Name.Contains(pickedLanguageFile.LeftPart.Trim())); + + if (langToInstall is null) + { + foreach (DismCapability cap in DismApi.GetCapabilities(session)) + if (cap.Name.Contains("Language.OCR~~~")) + { + DismOutputTextBlock.Text += $"{Environment.NewLine}Dism capability: {cap.Name}"; + + if (cap.Name.Contains(pickedLanguageFile.LeftPart)) + DismOutputTextBlock.Text += $"<--- Found {pickedLanguageFile.LeftPart}"; + } + + DismOutputTextBlock.Text += $"{Environment.NewLine}Language: {pickedLanguageFile.LeftPart} not found."; + return; + } + + DismProgressBar.Visibility = Visibility.Visible; + + DismProgressCallback progressCallback = new(progress => + { + DismProgressBar.Maximum = progress.Total; + DismProgressBar.Value = progress.Current; + }); + + await Task.Run(() => + { + DismApi.AddCapability(session, langToInstall.Name, false, null, progressCallback, null); + }); + + DismProgressBar.Visibility = Visibility.Collapsed; + } + + private void LoadLanguages_Click(object sender, RoutedEventArgs e) + { + using DismSession session = DismApi.OpenOnlineSession(); + + var caps = DismApi.GetCapabilities(session); + + foreach (DismCapability cap in DismApi.GetCapabilities(session)) + { + string capName = cap.Name; + if (!capName.StartsWith("Language.OCR~~~")) + continue; + if (cap.State != DismPackageFeatureState.Installed) + continue; + string localeName = capName["Language.OCR~~~".Length..capName.LastIndexOf('~')]; + CultureInfo culture = new(localeName); + DismOutputTextBlock.Text += $"{Environment.NewLine}{localeName} - {culture.DisplayName} - {capName}"; + } + } +} diff --git a/Text-Grab/Views/GrabFrame.xaml b/Text-Grab/Views/GrabFrame.xaml index d276ba4f..71187e2a 100644 --- a/Text-Grab/Views/GrabFrame.xaml +++ b/Text-Grab/Views/GrabFrame.xaml @@ -130,7 +130,9 @@ x:Name="IsTopmostMenuItem" Header="Keep Grab Frame On Top" IsCheckable="True" - IsChecked="{Binding Topmost, ElementName=GrabFrameWindow, Mode=TwoWay}" /> + IsChecked="{Binding Topmost, + ElementName=GrabFrameWindow, + Mode=TwoWay}" /> + IsChecked="{Binding IsChecked, + ElementName=FreezeToggleButton, + Mode=TwoWay}" /> + IsChecked="{Binding IsChecked, + ElementName=TableToggleButton, + Mode=TwoWay}" /> + IsChecked="{Binding IsChecked, + ElementName=EditToggleButton, + Mode=TwoWay}" /> + IsChecked="{Binding IsChecked, + ElementName=EditTextToggleButton, + Mode=TwoWay}" /> + Visibility="{Binding Visibility, + ElementName=SearchBox, + Mode=OneWay}" />