本文介绍了从Windows中提取的键盘布局的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

OK,这是一个稍显怪异的问题。

OK, this is a slightly weird question.

我们有一个触摸屏的应用程序(即没有键盘)。当用户需要输入文本时,应用程序显示虚拟键盘 - 手工打造的的WinForms

We have a touch-screen application (i.e., no keyboard). When users need to enter text, the application shows virtual keyboard - hand-built in WinForms.

制作这些东西手动为每个新的语言是猴子的工作。我想,窗户必须有此键盘布局信息在某些DLL藏在什么地方。会有反正来获取此信息窗外?

Making these things by hand for each new language is monkey work. I figure that windows must have this keyboard layout information hiding somewhere in some dll. Would there be anyway to get this information out of windows?

其他的想法表示欢迎(我估计至少是从一个XML文件生成的东西一定是比VS手工做的更好)。

Other ideas welcome (I figure at least generating the thing from a xml file has got to be better than doing it by hand in VS).

(注:话说所有这一切,我注意到有日语键盘,状态机和所有...,所以XML可能不足以)

(Note: having said all which, I note that there is a Japanese keyboard, state machine and all..., so XML might not be sufficient)

更新:pretty好对这个问题(我相信)的

UPDATE: pretty good series on this subject (I believe) here

推荐答案

可以加载系统键盘,并将其导出为来看看它是如何做的,并使用反射来驱动它。下面是在Windows 8 为187键盘.klc文件 zip文件使用下面的C#code创建。请注意,我最初的Windows 8写这适用于Windows XP,现在和屏幕上的键盘,它实在是太慢了,似乎崩溃任务栏:/但是,它的工作:)

Microsoft Keyboard Layout Creator can load system keyboards and export them as .klc files. Since it’s written in .NET you can use Reflector to see how it does that, and use reflection to drive it. Here's a zip file of .klc files for the 187 keyboards in Windows 8 created using the below C# code. Note that I originally wrote this for Windows XP, and now with Windows 8 and the on-screen keyboard, it is really slow and seems to crash the taskbar :/ However, it does work :)

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,设置了另存为文件名,就在于它是否是已经配置自定义键盘属性,然后模拟点击文件 - >保存菜单项

Basically, it gets a list of all the keyboards on the system, then for each one, loads it in MSKLC, sets the "Save As" filename, lies about whether it's already configured the custom keyboard properties, and then simulates a click on the File -> Save menu item.

这篇关于从Windows中提取的键盘布局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!