412 lines
14 KiB
C#
412 lines
14 KiB
C#
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.InteropServices;
|
|
using ShortcutsHelper.Models;
|
|
using ShortcutsHelper.Services;
|
|
using WpfApplication = System.Windows.Application;
|
|
using SystemTimer = System.Timers.Timer;
|
|
|
|
namespace ShortcutsHelper.ViewModels
|
|
{
|
|
public class MainViewModel : INotifyPropertyChanged, IDisposable
|
|
{
|
|
private readonly ShortcutService _shortcutService;
|
|
private readonly ConfigurationService _configService;
|
|
private readonly KeyCaptureService _keyCaptureService;
|
|
private readonly SystemTimer _appDetectionTimer;
|
|
private readonly SystemTimer _inactivityTimer;
|
|
|
|
private string _currentApplication = "";
|
|
private ShortcutRecord? _selectedShortcut;
|
|
private string _originalDescription = "";
|
|
private bool _isInitialized = false;
|
|
private bool _isPinnedMode = true; // Por defecto está activo
|
|
|
|
public ObservableCollection<ShortcutRecord> Shortcuts { get; } = new();
|
|
|
|
public string CurrentApplication
|
|
{
|
|
get => _currentApplication;
|
|
private set
|
|
{
|
|
if (_currentApplication != value)
|
|
{
|
|
_currentApplication = value;
|
|
OnPropertyChanged();
|
|
LoadShortcutsForCurrentApp();
|
|
}
|
|
}
|
|
}
|
|
|
|
public ShortcutRecord? SelectedShortcut
|
|
{
|
|
get => _selectedShortcut;
|
|
set
|
|
{
|
|
if (_selectedShortcut != value)
|
|
{
|
|
_selectedShortcut = value;
|
|
OnPropertyChanged();
|
|
EnsureEmptyRows();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsCapturingKeys => _keyCaptureService.IsCapturing;
|
|
|
|
public bool IsPinnedMode
|
|
{
|
|
get => _isPinnedMode;
|
|
set
|
|
{
|
|
if (_isPinnedMode != value)
|
|
{
|
|
_isPinnedMode = value;
|
|
OnPropertyChanged();
|
|
|
|
// Actualizar configuración
|
|
_appConfig.IsPinnedMode = value;
|
|
|
|
if (value)
|
|
{
|
|
// Al activar Pin, guardar la aplicación actual como pinned (si no está vacía)
|
|
if (!string.IsNullOrEmpty(CurrentApplication))
|
|
{
|
|
_appConfig.PinnedApplication = CurrentApplication;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Al desactivar Pin, limpiar la aplicación pinned y mostrar la ventana
|
|
_appConfig.PinnedApplication = "";
|
|
VisibilityChanged?.Invoke(this, true); // Mostrar ventana cuando se desactiva Pin
|
|
}
|
|
|
|
_configService.SaveConfiguration(_appConfig);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Configuración de aplicación actual
|
|
private AppConfiguration _appConfig = new();
|
|
private ApplicationSettings? _currentAppSettings;
|
|
|
|
// Evento para notificar cambios de visibilidad de la ventana
|
|
public event EventHandler<bool>? VisibilityChanged;
|
|
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
public MainViewModel()
|
|
{
|
|
_shortcutService = new ShortcutService();
|
|
_configService = new ConfigurationService();
|
|
_keyCaptureService = new KeyCaptureService();
|
|
|
|
// Configurar timers
|
|
_appDetectionTimer = new SystemTimer(1000); // Cada segundo
|
|
_appDetectionTimer.Elapsed += OnAppDetectionTimer;
|
|
|
|
_inactivityTimer = new SystemTimer(TimeSpan.FromMinutes(5).TotalMilliseconds); // 5 minutos por defecto
|
|
_inactivityTimer.Elapsed += OnInactivityTimer;
|
|
|
|
// Suscribirse a eventos
|
|
_keyCaptureService.KeyCaptured += OnKeyCaptured;
|
|
_keyCaptureService.CaptureCancelled += OnCaptureCancelled;
|
|
_shortcutService.ApplicationShortcutsChanged += OnApplicationShortcutsChanged;
|
|
|
|
Initialize();
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
if (_isInitialized) return;
|
|
|
|
// Cargar configuración
|
|
_appConfig = _configService.LoadConfiguration();
|
|
_inactivityTimer.Interval = TimeSpan.FromMinutes(_appConfig.InactivityTimeoutMinutes).TotalMilliseconds;
|
|
|
|
// Restaurar estado de Pin
|
|
_isPinnedMode = _appConfig.IsPinnedMode;
|
|
OnPropertyChanged(nameof(IsPinnedMode));
|
|
|
|
// Cargar todos los shortcuts de una vez
|
|
_shortcutService.LoadAllShortcuts();
|
|
|
|
// Si está en modo Pin y no hay aplicación pinned, establecer la primera aplicación detectada
|
|
// Pero primero detectar la aplicación actual para establecer CurrentApplication
|
|
string initialApp = GetActiveProcessName();
|
|
if (!string.IsNullOrWhiteSpace(initialApp) &&
|
|
!initialApp.Equals("ShortcutsHelper", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
CurrentApplication = initialApp;
|
|
LoadApplicationSettings();
|
|
|
|
// Si está en modo Pin y no hay aplicación pinned, establecer esta como pinned
|
|
if (IsPinnedMode && string.IsNullOrEmpty(_appConfig.PinnedApplication))
|
|
{
|
|
_appConfig.PinnedApplication = initialApp;
|
|
_configService.SaveConfiguration(_appConfig);
|
|
}
|
|
}
|
|
|
|
// Iniciar detección de aplicación
|
|
_appDetectionTimer.Start();
|
|
|
|
// Iniciar timer de inactividad
|
|
_inactivityTimer.Start();
|
|
|
|
_isInitialized = true;
|
|
}
|
|
|
|
private void OnAppDetectionTimer(object? sender, System.Timers.ElapsedEventArgs e)
|
|
{
|
|
DetectActiveApplication();
|
|
}
|
|
|
|
private void OnInactivityTimer(object? sender, System.Timers.ElapsedEventArgs e)
|
|
{
|
|
// Guardar cambios por inactividad
|
|
SavePendingChanges();
|
|
}
|
|
|
|
private void DetectActiveApplication()
|
|
{
|
|
string appName = GetActiveProcessName();
|
|
if (string.IsNullOrWhiteSpace(appName))
|
|
return;
|
|
|
|
// Si está en modo Pin
|
|
if (IsPinnedMode)
|
|
{
|
|
// Si no hay aplicación pinned, establecer la aplicación actual (excepto ShortcutsHelper)
|
|
if (string.IsNullOrEmpty(_appConfig.PinnedApplication) &&
|
|
!appName.Equals("ShortcutsHelper", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_appConfig.PinnedApplication = appName;
|
|
CurrentApplication = appName;
|
|
LoadApplicationSettings();
|
|
_configService.SaveConfiguration(_appConfig);
|
|
return;
|
|
}
|
|
|
|
// Si hay aplicación pinned, manejar visibilidad
|
|
if (!string.IsNullOrEmpty(_appConfig.PinnedApplication))
|
|
{
|
|
bool isShortcutsHelper = appName.Equals("ShortcutsHelper", StringComparison.OrdinalIgnoreCase);
|
|
bool isPinnedApp = appName.Equals(_appConfig.PinnedApplication, StringComparison.OrdinalIgnoreCase);
|
|
|
|
// Mostrar ventana solo si está en ShortcutsHelper o en la aplicación pinned
|
|
bool shouldBeVisible = isShortcutsHelper || isPinnedApp;
|
|
VisibilityChanged?.Invoke(this, shouldBeVisible);
|
|
|
|
// No cambiar la aplicación actual cuando está pinned
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Modo normal: cambiar aplicación pero no mostrar ShortcutsHelper
|
|
if (appName.Equals("ShortcutsHelper", StringComparison.OrdinalIgnoreCase))
|
|
return;
|
|
|
|
if (appName != CurrentApplication)
|
|
{
|
|
SaveCurrentApplicationSettings();
|
|
CurrentApplication = appName;
|
|
LoadApplicationSettings();
|
|
}
|
|
}
|
|
|
|
public void TogglePinMode()
|
|
{
|
|
IsPinnedMode = !IsPinnedMode;
|
|
}
|
|
|
|
private void LoadShortcutsForCurrentApp()
|
|
{
|
|
WpfApplication.Current.Dispatcher.Invoke(() =>
|
|
{
|
|
Shortcuts.Clear();
|
|
var shortcuts = _shortcutService.GetShortcutsForApplication(CurrentApplication);
|
|
|
|
foreach (var shortcut in shortcuts)
|
|
{
|
|
Shortcuts.Add(shortcut);
|
|
}
|
|
|
|
EnsureEmptyRows();
|
|
});
|
|
}
|
|
|
|
private void EnsureEmptyRows()
|
|
{
|
|
WpfApplication.Current.Dispatcher.BeginInvoke(() =>
|
|
{
|
|
var emptyRows = Shortcuts.Where(s => string.IsNullOrWhiteSpace(s.Shortcut) && string.IsNullOrWhiteSpace(s.Description)).Count();
|
|
while (emptyRows < 3)
|
|
{
|
|
Shortcuts.Add(new ShortcutRecord { Application = CurrentApplication });
|
|
emptyRows++;
|
|
}
|
|
});
|
|
}
|
|
|
|
private void OnApplicationShortcutsChanged(object? sender, string applicationName)
|
|
{
|
|
if (applicationName == CurrentApplication)
|
|
{
|
|
LoadShortcutsForCurrentApp();
|
|
}
|
|
}
|
|
|
|
public void DeleteSelectedShortcut()
|
|
{
|
|
if (SelectedShortcut != null && !string.IsNullOrWhiteSpace(SelectedShortcut.Shortcut))
|
|
{
|
|
_shortcutService.RemoveShortcut(CurrentApplication, SelectedShortcut.Shortcut);
|
|
Shortcuts.Remove(SelectedShortcut);
|
|
EnsureEmptyRows();
|
|
}
|
|
}
|
|
|
|
public void StartKeyCapture()
|
|
{
|
|
if (SelectedShortcut == null) return;
|
|
|
|
if (_keyCaptureService.IsCapturing)
|
|
{
|
|
_keyCaptureService.StopCapturing();
|
|
return;
|
|
}
|
|
|
|
_originalDescription = SelectedShortcut.Description;
|
|
SelectedShortcut.Description = "Presiona las teclas... (Esc para cancelar)";
|
|
_keyCaptureService.StartCapturing();
|
|
OnPropertyChanged(nameof(IsCapturingKeys));
|
|
}
|
|
|
|
private void OnKeyCaptured(object? sender, string keyString)
|
|
{
|
|
if (SelectedShortcut != null)
|
|
{
|
|
SelectedShortcut.Shortcut = keyString;
|
|
SelectedShortcut.Description = _originalDescription;
|
|
SelectedShortcut.IsModified = true;
|
|
}
|
|
OnPropertyChanged(nameof(IsCapturingKeys));
|
|
}
|
|
|
|
private void OnCaptureCancelled(object? sender, EventArgs e)
|
|
{
|
|
if (SelectedShortcut != null)
|
|
{
|
|
SelectedShortcut.Description = _originalDescription;
|
|
}
|
|
OnPropertyChanged(nameof(IsCapturingKeys));
|
|
}
|
|
|
|
public void SavePendingChanges()
|
|
{
|
|
try
|
|
{
|
|
// Guardar shortcuts modificados
|
|
var modifiedShortcuts = Shortcuts.Where(s => s.IsModified && !string.IsNullOrWhiteSpace(s.Shortcut)).ToList();
|
|
foreach (var shortcut in modifiedShortcuts)
|
|
{
|
|
_shortcutService.AddOrUpdateShortcut(shortcut);
|
|
}
|
|
|
|
if (_shortcutService.HasModifiedShortcuts())
|
|
{
|
|
_shortcutService.SaveAllShortcuts();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error al guardar cambios: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public ApplicationSettings GetCurrentApplicationSettings()
|
|
{
|
|
return _configService.GetApplicationSettings(_appConfig, CurrentApplication);
|
|
}
|
|
|
|
public void SaveCurrentApplicationSettings()
|
|
{
|
|
if (string.IsNullOrEmpty(CurrentApplication) || _currentAppSettings == null) return;
|
|
|
|
_configService.UpdateApplicationSettings(_appConfig, CurrentApplication, _currentAppSettings);
|
|
_configService.SaveConfiguration(_appConfig);
|
|
}
|
|
|
|
private void LoadApplicationSettings()
|
|
{
|
|
_currentAppSettings = _configService.GetApplicationSettings(_appConfig, CurrentApplication);
|
|
}
|
|
|
|
public void UpdateWindowSettings(double left, double top, double width, double height)
|
|
{
|
|
if (_currentAppSettings != null)
|
|
{
|
|
_currentAppSettings.Left = left;
|
|
_currentAppSettings.Top = top;
|
|
_currentAppSettings.Width = width;
|
|
_currentAppSettings.Height = height;
|
|
}
|
|
}
|
|
|
|
public void UpdateColumnWidths(double favoriteWidth, double shortcutWidth, double descriptionWidth)
|
|
{
|
|
if (_currentAppSettings != null)
|
|
{
|
|
_currentAppSettings.FavoriteColumnWidth = favoriteWidth;
|
|
_currentAppSettings.ShortcutColumnWidth = shortcutWidth;
|
|
_currentAppSettings.DescriptionColumnWidth = descriptionWidth;
|
|
}
|
|
}
|
|
|
|
private static string GetActiveProcessName()
|
|
{
|
|
IntPtr hWnd = GetForegroundWindow();
|
|
if (hWnd == IntPtr.Zero) return string.Empty;
|
|
|
|
GetWindowThreadProcessId(hWnd, out uint pid);
|
|
try
|
|
{
|
|
var proc = Process.GetProcessById((int)pid);
|
|
return proc.ProcessName;
|
|
}
|
|
catch
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
|
{
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
SavePendingChanges();
|
|
SaveCurrentApplicationSettings();
|
|
|
|
_appDetectionTimer?.Stop();
|
|
_appDetectionTimer?.Dispose();
|
|
_inactivityTimer?.Stop();
|
|
_inactivityTimer?.Dispose();
|
|
_keyCaptureService?.Dispose();
|
|
}
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern IntPtr GetForegroundWindow();
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
|
}
|
|
} |