diff --git a/src/composer/KeyboardLeds.cs b/src/composer/KeyboardLeds.cs index 9e1cb211..cc973045 100644 --- a/src/composer/KeyboardLeds.cs +++ b/src/composer/KeyboardLeds.cs @@ -62,27 +62,38 @@ private static void DisableTimer() private static IList m_kbd_devices = new List(); + private static readonly IDictionary m_vk_to_flag = new Dictionary() + { + { VK.CAPITAL, KEYBOARD.CAPS_LOCK_ON }, + { VK.NUMLOCK, KEYBOARD.NUM_LOCK_ON }, + { VK.PAUSE, KEYBOARD.SCROLL_LOCK_ON }, + }; + private static void Refresh(object o) { var indicators = new KEYBOARD_INDICATOR_PARAMETERS(); int buffer_size = (int)Marshal.SizeOf(indicators); + var led_vk = Settings.LedKey.Value[0].VirtualKey; + // NOTE: I was unable to make IOCTL.KEYBOARD_QUERY_INDICATORS work // properly, but querying state with GetKeyState() seemed more // robust anyway. Think of the user setting Caps Lock as their // compose key, entering compose state, then suddenly changing // the compose key to Shift: the LED state would be inconsistent. - if (NativeMethods.GetKeyState(VK.CAPITAL) != 0 - || (Composer.IsComposing && Composer.CurrentComposeKey.VirtualKey == VK.CAPITAL)) - indicators.LedFlags |= KEYBOARD.CAPS_LOCK_ON; - - if (NativeMethods.GetKeyState(VK.NUMLOCK) != 0 - || (Composer.IsComposing && Composer.CurrentComposeKey.VirtualKey == VK.NUMLOCK)) - indicators.LedFlags |= KEYBOARD.NUM_LOCK_ON; - - if (NativeMethods.GetKeyState(VK.SCROLL) != 0 - || (Composer.IsComposing && Composer.CurrentComposeKey.VirtualKey == VK.SCROLL)) - indicators.LedFlags |= KEYBOARD.SCROLL_LOCK_ON; + foreach (var kv in m_vk_to_flag) + { + var vk = kv.Key; + var flag = kv.Value; + if (NativeMethods.GetKeyState(vk) != 0) + indicators.LedFlags |= flag; + else if (Composer.IsComposing) + { + if (Composer.CurrentComposeKey.VirtualKey == vk && led_vk == VK.COMPOSE + || led_vk == vk) + indicators.LedFlags |= flag; + } + } lock (m_kbd_devices) { diff --git a/src/i18n/Text.Designer.cs b/src/i18n/Text.Designer.cs index 88ef2950..405b30b5 100644 --- a/src/i18n/Text.Designer.cs +++ b/src/i18n/Text.Designer.cs @@ -564,6 +564,24 @@ public static string KeyApps { } } + /// + /// Looks up a localized string similar to Keyboard LED. + /// + public static string KeyboardLed { + get { + return ResourceManager.GetString("KeyboardLed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If set, the corresponding keyboard LED will be lit when a compose sequence is in progress.. + /// + public static string KeyboardLedToolTip { + get { + return ResourceManager.GetString("KeyboardLedToolTip", resourceCulture); + } + } + /// /// Looks up a localized string similar to Caps Lock. /// @@ -573,6 +591,15 @@ public static string KeyCapital { } } + /// + /// Looks up a localized string similar to Compose. + /// + public static string KeyCompose { + get { + return ResourceManager.GetString("KeyCompose", resourceCulture); + } + } + /// /// Looks up a localized string similar to Conversion. /// @@ -943,7 +970,7 @@ public static string TestTyping { } /// - /// Looks up a localized string similar to If enabled, any compose sequence will be cancelled after a certain delay if no keyboard activity is detected.. + /// Looks up a localized string similar to If set, any compose sequence will be cancelled after a certain delay if no keyboard activity is detected.. /// public static string TimeoutToolTip { get { diff --git a/src/i18n/Text.resx b/src/i18n/Text.resx index bb15dcc6..d5016079 100644 --- a/src/i18n/Text.resx +++ b/src/i18n/Text.resx @@ -586,7 +586,19 @@ Name of the category (Unicode characters, Emoji, User macros, Favorites) - If enabled, any compose sequence will be cancelled after a certain delay if no keyboard activity is detected. + If set, any compose sequence will be cancelled after a certain delay if no keyboard activity is detected. + + Keyboard LED + + + + If set, the corresponding keyboard LED will be lit when a compose sequence is in progress. + + + + Compose + The short name of the compose key + diff --git a/src/sequences/Key.cs b/src/sequences/Key.cs index ad388c1e..92d857f3 100644 --- a/src/sequences/Key.cs +++ b/src/sequences/Key.cs @@ -149,6 +149,7 @@ private static Dictionary KeyNames m_key_names = new Dictionary { { new Key(VK.DISABLED), i18n.Text.KeyDisabled }, + { new Key(VK.COMPOSE), i18n.Text.KeyCompose}, { new Key(VK.LMENU), i18n.Text.KeyLMenu }, { new Key(VK.RMENU), i18n.Text.KeyRMenu }, { new Key(VK.LCONTROL), i18n.Text.KeyLControl }, diff --git a/src/sequences/Sequence.cs b/src/sequences/Sequence.cs index 9b9db322..7e6d3528 100644 --- a/src/sequences/Sequence.cs +++ b/src/sequences/Sequence.cs @@ -21,7 +21,7 @@ namespace WinCompose /// /// The KeySequenceConverter class allows to convert a string or a string-like -/// object to a Key object and back. +/// object to a KeySequence object and back. /// public class KeySequenceConverter : TypeConverter { diff --git a/src/settings/Settings.cs b/src/settings/Settings.cs index 394012f1..86ee8fd9 100644 --- a/src/settings/Settings.cs +++ b/src/settings/Settings.cs @@ -90,6 +90,8 @@ public static string Version [EntryLocation("composing", "compose_key")] public static SettingsEntry ComposeKeys { get; } = new SettingsEntry(new KeySequence()); + [EntryLocation("composing", "led_key")] + public static SettingsEntry LedKey { get; } = new SettingsEntry(new KeySequence()); [EntryLocation("composing", "reset_delay")] public static SettingsEntry ResetTimeout { get; } = new SettingsEntry(-1); [EntryLocation("composing", "use_xorg_rules")] @@ -134,6 +136,15 @@ public static string Version public static IEnumerable ValidComposeKeys => m_valid_compose_keys; public static Dictionary ValidLanguages => m_valid_languages; + public static IList ValidLedKeys { get; } = new List() + { + new Key(VK.DISABLED), + new Key(VK.COMPOSE), + new Key(VK.CAPITAL), + new Key(VK.NUMLOCK), + new Key(VK.PAUSE), + }; + public static void StartWatchConfigFile() { m_ini_file.OnFileChanged += LoadConfig; @@ -147,8 +158,9 @@ public static void StopWatchConfigFile() private static IniFile m_ini_file; - private static void ValidateComposeKeys() + private static void ValidateSettings() { + // Check that the configured compose key(s) are legal KeySequence compose_keys = new KeySequence(); if (ComposeKeys.Value?.Count == 0) { @@ -172,6 +184,12 @@ private static void ValidateComposeKeys() compose_keys.Add(new Key(VK.DISABLED)); } ComposeKeys.Value = compose_keys; + + // Check that the keyboard LED key is legal + if (LedKey.Value.Count != 1 || !ValidLedKeys.Contains(LedKey.Value[0])) + { + LedKey.Value = new KeySequence() { new Key(VK.COMPOSE) }; + } } public static void LoadConfig() @@ -187,7 +205,7 @@ public static void LoadConfig() } } - ValidateComposeKeys(); + ValidateSettings(); // HACK: if the user uses the "it-CH" locale, replace it with "it" // because we use "it-CH" as a special value to mean Sardinian. diff --git a/src/ui/SettingsWindow.xaml b/src/ui/SettingsWindow.xaml index 4ed754cc..5cd475ef 100644 --- a/src/ui/SettingsWindow.xaml +++ b/src/ui/SettingsWindow.xaml @@ -153,6 +153,7 @@ + @@ -175,27 +176,37 @@ + Margin="8,4" VerticalAlignment="Center"/> - + + + + + + + - - @@ -238,9 +249,15 @@ + + + + + + - + @@ -276,44 +293,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/SettingsWindowViewModel.cs b/src/ui/SettingsWindowViewModel.cs index eb2aa596..194fb291 100644 --- a/src/ui/SettingsWindowViewModel.cs +++ b/src/ui/SettingsWindowViewModel.cs @@ -55,6 +55,13 @@ public string SelectedLanguage set => SetValue(ref m_selected_language, value, nameof(SelectedLanguage)); } + public Key SelectedLedKey + { + // FIXME: this settings value should be a Key, not a KeySequence + get => Settings.LedKey.Value[0]; + set => Settings.LedKey.Value = new KeySequence() { value }; + } + public Key ComposeKey0 { get => GetComposeKey(0); set => SetComposeKey(0, value); } public Key ComposeKey1 { get => GetComposeKey(1); set => SetComposeKey(1, value); }