Извлечение раскладок клавиатуры из окон

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

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

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

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

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

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

Ответ 1

Microsoft Layout Creator может загружать системные клавиатуры и экспортировать их как .klc. Начиная с его написания в .NET вы можете использовать Reflector, чтобы увидеть, как он это делает, и использовать отражение для его вождения. Здесь zip файл .klc файлов для 187-клавишных клавиатур в Windows 8, созданный с использованием приведенного ниже кода С#. Обратите внимание, что я изначально написал это для 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

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

Ответ 3

Я знаю, где находятся пути этих DLL файлов:

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

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts

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

C:\Windows\System32

и

C:\Windows\SystemWOW64

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

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

введите описание изображения здесь

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

Ответ 4

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

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

Отметьте MSDN здесь

Ответ 5

Это довольно известный факт, что 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. Он также поддерживает цепные мертвые клавиши и переназначение любой из клавиш на любой клавиатуре.