Как я могу программно найти список всех сочетаний клавиш, назначенных в C # Winform?

#c# #winforms #keyboard-shortcuts

#c# #winforms #сочетания клавиш

Вопрос:

Как я могу программно получить список сочетаний клавиш, которые используются в моем приложении? У меня есть winform со многими меню и пунктами меню (включая динамически генерируемые пункты меню), которым назначены сочетания клавиш.

На самом деле мне было трудно отслеживать все сочетания клавиш, и я подумал, что было бы неплохо отобразить список для пользователя.

Комментарии:

1. Даже если бы вы могли это сделать (и я не могу придумать надежный способ добиться этого) Вероятно, для написания этого потребуется больше времени, чем для простого просмотра каждой формы и аудита

2. Вы можете использовать SendInput метод и попробовать в цикле.

3. Вы пробовали перечислять пункты меню и извлекать их свойства коротких клавиш и определять значения (неудобно, потому что это флаги, но выполнимо, потому что все это часть перечисления ключей). Обратите внимание, вы, конечно, не сказали, что используете ToolStripMenuItem, но я бы также отметил, что если вы используете и установили свойство ShortcutKeyDisplayString для каждого, вы можете использовать это, если это просто для отображения списка пользователю

4. @CaiusJard в частности, я думал о меню toolstrip, не был уверен, существуют ли сочетания клавиш в другом месте

Ответ №1:

Я вижу несколько проблем в вашем требовании:

  • Для File-New вас нужно ввести <alt-F> <alt-N> ; для Edit-Names вас нужно ввести <Alt-E> <Alt-N>
  • Поэтому <Alt-N> в вашей коллекции сочетаний клавиш недостаточно, вам нужна полная комбинация: <alt-F> <alt-N> для меню File-New и <Alt-E> <Alt-N> для Edit-Names
  • Что, если разработчик забыл добавить <alt-F> в файловую часть и <alt-E> в редактируемую часть? Тогда у вас будет два <alt-N> сочетания клавиш!
  • Сокращения также работают с другими элементами управления, такими как кнопки
  • Как насчет стандартных сочетаний клавиш, таких как <Ctrl-C> и <Ctrl-V> ?

Давайте предположим, что ваши сочетания клавиш уникальны, вам нужны только ярлыки для пунктов меню, и вы хотите, чтобы они были из корневого меню. Увы, class System.Windows.Forms.Shortcut не имеет значений для <Alt-..> сочетаний клавиш, поэтому мы просто запомним сочетания клавиш в виде символов верхнего регистра: так что «FN» означает <alt-F> <alt-N>"

Вам нужно повторить каждый пункт меню со всеми пунктами подменю и проверить Text , содержит ли свойство амперсанд.

Я сделаю это как методы расширения для MenuStrip и ToolStripItem . Строка меню имеет главное меню в качестве элементов ToolStripItems в свойстве Items ; элемент ToolStripItem имеет подменю в свойстве DropDownItems .

Если вы не знакомы с методами расширения, см. раздел Методы расширения демистифицированные

Сначала класс для ввода результатов:

 using System.Windows.Forms;
class ShortCut
{
    public string ShortcutSequence {get; set;} = String.Empty;
    ToolStripItem ToolStripItem {get; set;}
}
 

Получите ярлык ToolStripMenuItem или по умолчанию, если у него нет ярлыка:

 public static char GetShortcutCharOrDefault(this ToolStripMenuItem menuItem)
{
    // Return the character after the ampersand in property Text,
    // or null if there is no such thing
    return menuItem?.Text?.SkipWhile(c => c != 'amp;') // skip until amp;
        .Skip(1)                                    // skip the amp;
        .Select(c => char.ToUpper(c))               // make the char uppercase
        .FirstOrDefault()                           // char after the ampersand
        ?? default(char);                           // or default char if no text
}
 

От последовательности ToolStripMenuItems до последовательности сочетаний клавиш.

 public static IEnumerable<Shortcut> ToShortcuts(
    this IEnumerable<ToolStripMenuItem> menuItems,
    string parentShortcutSequence)
{
    // TODO: handle invalid input

    foreach (var menuItem in menuItems)
    {
        char shortcutCar = menuItem.GetShortcutChar();
        if (shortCutChar != default(char))
        {
           // This menuItem has a shortcut.
           var shortcut = new ShortCut
           {
               ShortcutSequence = parentShortcutSequence   shortcutChar,
               ToolstripItem = menuItem,
           }

           // return this shortcut
           yield return shortcut;

           // and check for the shortcuts of the sub menu items
           // recursively!
           var subShortcuts = menuItem.Items.ToShortcuts(shortcut.ShortcutSequence);
           foreach (var subShortcut in subShortcuts)
           {
               yield return subShortCut);
           }
        }
    }
}
 

Использование:

 MenuStrip mainMenuStrip = ...
IEnumerable<ToolStripItem> menus = mainMenuStrip.Items.Cast<ToolStripItem>();
IEnumerable<Shortcut> shortcuts = menus.ToShortCusts(String.Empty);