Извлечение раскладок клавиатуры из окон - PullRequest
11 голосов
/ 19 марта 2009

ОК, это немного странный вопрос.

У нас есть приложение с сенсорным экраном (т.е. без клавиатуры). Когда пользователям необходимо ввести текст, приложение отображает виртуальную клавиатуру - встроенную вручную в WinForms.

Создание этих вещей вручную для каждого нового языка - работа обезьян. Я полагаю, что окна должны иметь эту информацию о раскладке клавиатуры, скрытую где-то в некоторой DLL. Будет ли в любом случае, чтобы получить эту информацию из окон?

Приветствуются другие идеи (я думаю, по крайней мере, создание вещи из файла XML должно быть лучше, чем делать это вручную в VS).

(Примечание: сказав все что, я отмечу, что есть японская клавиатура, конечный автомат и все ..., поэтому XML может быть недостаточно)

ОБНОВЛЕНИЕ : довольно хорошая серия на эту тему (я считаю) здесь

Ответы [ 5 ]

6 голосов
/ 08 мая 2009

Microsoft Keyboard Layout Creator может загружать системные клавиатуры и экспортировать их как .klc файлы . Поскольку он написан на .NET, вы можете использовать Reflector , чтобы увидеть, как он это делает, и использовать отражение, чтобы управлять им. Вот zip-файл .klc-файлов для 187 клавиатур в Windows 8 , созданный с использованием приведенного ниже кода C #. Обратите внимание, что я изначально писал это для Windows XP, а теперь с Windows 8 и экранной клавиатурой, это действительно медленно и, кажется, вылетает панель задач: / Однако, это работает:)

using System;
using System.Collections;
using System.IO;
using System.Reflection;

class KeyboardExtractor {

    static Object InvokeNonPublicStaticMethod(Type t, String name,
            Object[] args)
    {
        return t.GetMethod(name, BindingFlags.Static | BindingFlags.NonPublic)
            .Invoke(null, args);
    }

    static void InvokeNonPublicInstanceMethod(Object o, String name,
            Object[] args)
    {
        o.GetType().GetMethod(name, BindingFlags.Instance |
                BindingFlags.NonPublic) .Invoke(o, args);
    }

    static Object GetNonPublicProperty(Object o, String propertyName) {
        return o.GetType().GetField(propertyName,
                BindingFlags.Instance | BindingFlags.NonPublic)
            .GetValue(o);
    }

    static void SetNonPublicField(Object o, String propertyName, Object v) {
        o.GetType().GetField(propertyName,
                BindingFlags.Instance | BindingFlags.NonPublic)
            .SetValue(o, v);
    }

    [STAThread] public static void Main() {
        System.Console.WriteLine("Keyboard Extractor...");

        KeyboardExtractor ke = new KeyboardExtractor();
        ke.extractAll();

        System.Console.WriteLine("Done.");
    }

    Assembly msklcAssembly;
    Type utilitiesType;
    Type keyboardType;
    String baseDirectory;

    public KeyboardExtractor() {
        msklcAssembly = Assembly.LoadFile("C:\\Program Files\\Microsoft Keyboard Layout Creator 1.4\\MSKLC.exe");
        utilitiesType = msklcAssembly.GetType("Microsoft.Globalization.Tools.KeyboardLayoutCreator.Utilities");
        keyboardType = msklcAssembly.GetType("Microsoft.Globalization.Tools.KeyboardLayoutCreator.Keyboard");

        baseDirectory = Directory.GetCurrentDirectory();
    }

    public void extractAll() {

        DateTime startTime = DateTime.UtcNow;

        SortedList keyboards = (SortedList)InvokeNonPublicStaticMethod(
                utilitiesType, "KeyboardsOnMachine", new Object[] {false});

        DateTime loopStartTime = DateTime.UtcNow;

        int i = 0;
        foreach (DictionaryEntry e in keyboards) {
            i += 1;
            Object k = e.Value;

            String name = (String)GetNonPublicProperty(k, "m_stLayoutName");
            String layoutHexString = ((UInt32)GetNonPublicProperty(k, "m_hkl"))
                .ToString("X");

            TimeSpan elapsed = DateTime.UtcNow - loopStartTime;
            Double ticksRemaining = ((Double)elapsed.Ticks * keyboards.Count)
                        / i - elapsed.Ticks;
            TimeSpan remaining = new TimeSpan((Int64)ticksRemaining);
            String msgTimeRemaining = "";
            if (i > 1) {
                // Trim milliseconds
                remaining = new TimeSpan(remaining.Hours, remaining.Minutes,
                        remaining.Seconds);
                msgTimeRemaining = String.Format(", about {0} remaining",
                        remaining);
            }
            System.Console.WriteLine(
                    "Saving {0} {1}, keyboard {2} of {3}{4}",
                    layoutHexString, name, i, keyboards.Count,
                    msgTimeRemaining);

            SaveKeyboard(name, layoutHexString);

        }

        System.Console.WriteLine("{0} elapsed", DateTime.UtcNow - startTime);

    }

    private void SaveKeyboard(String name, String layoutHexString) {
        Object k = keyboardType.GetConstructors(
                BindingFlags.Instance | BindingFlags.NonPublic)[0]
            .Invoke(new Object[] {
                        new String[] {"", layoutHexString},
                    false});

        SetNonPublicField(k, "m_fSeenOrHeardAboutPropertiesDialog", true);
        SetNonPublicField(k, "m_stKeyboardTextFileName",
                String.Format("{0}\\{1} {2}.klc",
                    baseDirectory, layoutHexString, name));
        InvokeNonPublicInstanceMethod(k, "mnuFileSave_Click",
                new Object[] {new Object(), new EventArgs()});

        ((IDisposable)k).Dispose();
    }

}

По сути, он получает список всех клавиатур в системе, затем для каждой загружает его в MSKLC, задает имя файла «Сохранить как», определяет, настроено ли уже настроенные свойства клавиатуры, и затем имитирует нажмите на пункт меню Файл -> Сохранить.

2 голосов
/ 29 апреля 2019

Это довольно известный факт, что MSKLC не может точно импортировать и воспроизводить раскладки клавиатуры для всех файлов .DLL, поставляемых Windows, особенно файлов в Windows 8 и выше. И не стоит знать, где находятся эти файлы, если вы не можете извлечь из них какую-либо значимую или полезную информацию. Это задокументировано Майклом Капланом в его блоге (он был разработчиком MSKLC), который, как я вижу, вы указали выше.

Когда MSKLC встречает что-либо, чего он не понимает, эта часть удаляется. Извлечение раскладки с использованием MSKLC будет работать для большинства клавиатур, но есть несколько - а именно клавиатура Cherokee, а также японская и корейская клавиатуры (если назвать несколько, я не уверен, сколько их еще) - для которых извлеченные Раскладка НЕ ​​будет точно или полностью отражать фактическое использование и особенности клавиатуры. Клавиатура Cherokee имеет цепочку мертвых клавиш, которые MSKLC не поддерживает. А на дальневосточных клавиатурах есть клавиши-модификаторы, о которых MSKLC не знает - это означает, что целые слои / состояния сдвига отсутствуют!

Майкл Каплан предоставляет некоторый код и раскрывает некоторые секреты MSLKC и сопутствующего программного обеспечения, которое можно использовать для преодоления некоторых из этих ограничений, но для этого требуется изрядное количество действий вручную - именно то, что вы пытаетесь избежать! Кроме того, цели Майкла направлены на создание клавиатур с функциями, которые MSKLC не может создавать или понимать, но которые работают в Windows (что противоположно тому, что пытается достичь OP).

Я уверен, что мое решение слишком поздно, чтобы быть полезным для ОП, но, возможно, оно будет полезно в будущем кому-то в аналогичной ситуации. Это моя надежда и причина опубликовать это.

Пока все, что я сделал, это объяснил, что других ответов недостаточно. Даже самый лучший не сможет и не сможет полностью и точно воспроизвести все встроенные клавиатуры Windows и отобразить их в исходные файлы KLC. Это действительно прискорбно, и, конечно, это не вина его автора, потому что это очень умный кусок кода / скрипта! К счастью, скрипт и исходные файлы (чья ссылка может работать, а может и не работать) полезны и эффективны для большинства клавиатур Windows, а также для любых пользовательских клавиатур, созданных MSKLC.

Клавиатуры, имеющие расширенные функции, которые не поддерживает MSKLC, были созданы Windows DDK, но эти функции официально не задокументированы. Хотя об их потенциале можно немного узнать, изучив исходные файлы, поставляемые с MSKLC.

К сожалению, единственное решение, которое я могу предложить, - это стороннее платное программное обеспечение под названием KbdEdit . Я считаю, что это единственное доступное в настоящее время решение, которое действительно способно точно декодировать и воссоздавать любую из предоставленных Windows клавиатур - хотя есть несколько расширенных функций, которые даже он не может воспроизвести (например, комбинации клавиш / горячие клавиши, которые выполняют специальный родной язык функции, например: Ctrl + CapsLock для активации KanaLock (японский слой-модификатор). KbdEdit ДОЛЖНО точно воспроизводит тот слой-модификатор, который MSKLC удаляет, он просто не поддерживает этот альтернативный метод активации этого состояния сдвига, если вы этого не сделаете иметь японскую клавиатуру с клавишей блокировки Kana, хотя она позволит вам преобразовать клавишу на клавиатуре в клавишу Kana (возможно, Scroll Lock?).

К счастью, ни одна из этих неподдерживаемых функций даже не применима к экранной клавиатуре.

KbdEdit - действительно мощный и удивительный инструмент, и он стоил каждого пенни, за который я заплатил! (И это НЕ то, что я бы сказал практически о любом другом платном программном обеспечении…) Хотя KbdEdit является сторонним программным обеспечением, оно необходимо только для создания клавиатур, а не для их использования. Все клавиатуры, которые он создает, работают в любой системе Windows без установки KbdEdit. Поддерживает додо 15 состояний модификаторов и три дополнительные клавиши модификаторов, одна из которых переключается, как CapsLock. Он также поддерживает цепные мертвые клавиши и переназначение любых клавиш на большинстве клавиатур.

2 голосов
/ 06 июня 2017

Я знаю, где путь к этим DLL-файлам:

В вашем реестре вы видите:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts

, где каждая ветвь имеет какое-то значение, например "Layout File"="KBDSP.dll". Корневой каталог

C:\Windows\System32

и

C:\Windows\SystemWOW64

Это все файлы раскладки клавиатуры. Например, KBDUS.dll означает «клавиатура для США».

Я попытался заменить файл DLL моей собственной библиотекой DLL, созданной MSKLC, и обнаружил, что она автоматически загружает изображения отображения макета в «Язык» - «Метод ввода» - «Предварительный просмотр»:

enter image description here

Итак, мы знаем, что отображение есть в DLL.

2 голосов
/ 19 марта 2009

Почему вы не используете экранную клавиатуру (osk.exe)? Похоже, вы заново изобретаете колесо. И не самый простой!

0 голосов
/ 19 марта 2009

Пожалуйста, проверьте следующее Windows API

 [DllImport("user32.dll")]
 private static extern long LoadKeyboardLayout(string pwszKLID, uint Flags);

Проверьте MSDN здесь

...