简体   繁体   English

从 windows 中提取键盘布局

[英]Extracting keyboard layouts from windows

OK, this is a slightly weird question.好的,这是一个有点奇怪的问题。

We have a touch-screen application (ie, no keyboard).我们有一个触摸屏应用程序(即没有键盘)。 When users need to enter text, the application shows virtual keyboard - hand-built in WinForms.当用户需要输入文本时,应用程序会显示虚拟键盘 - WinForms 中手动内置。

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.我认为 windows 必须将此键盘布局信息隐藏在某些 dll 的某处。 Would there be anyway to get this information out of windows?无论如何可以从 windows 中获取这些信息吗?

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 文件生成东西必须比在 VS 中手动生成要好)。

(Note: having said all which, I note that there is a Japanese keyboard, state machine and all..., so XML might not be sufficient) (注意:说了这么多,我注意到有一个日文键盘,state 机器和所有......,所以 XML 可能还不够)

UPDATE : pretty good series on this subject (I believe) here更新:关于这个主题的很好的系列(我相信)在这里

Microsoft Keyboard Layout Creator can load system keyboards and export them as .klc files . Microsoft Keyboard Layout Creator可以加载系统键盘并将它们导出为.klc 文件 Since it's written in .NET you can use Reflector to see how it does that, and use reflection to drive it.由于它是用 .NET 编写的,因此您可以使用Reflector来查看它是如何做到的,并使用反射来驱动它。 Here's a zip file of.klc files for the 187 keyboards in Windows 8 created using the below C# code.这是使用以下 C# 代码创建的Windows 8 中 187 个键盘的 zip 文件 of.klc 文件 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:)请注意,我最初是为 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();
    }

}

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.基本上,它获取系统上所有键盘的列表,然后对于每个键盘,将其加载到 MSKLC 中,设置“另存为”文件名,确定是否已经配置了自定义键盘属性,然后模拟单击文件 -> 保存菜单项。

I know where are these DLL files' path:我知道这些 DLL 文件的路径在哪里:

In your registry, you see:在您的注册表中,您会看到:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts

where each branch has some value like "Layout File"="KBDSP.dll" .其中每个分支都有一些值,例如"Layout File"="KBDSP.dll" The root directory is根目录是

C:\Windows\System32

and

C:\Windows\SystemWOW64

Those are all the keyboard layout files are located.这些是所有键盘布局文件所在的位置。 For example, KBDUS.dll means "keyboard for US".例如, KBDUS.dll表示“美国键盘”。

I tried to substitute the DLL file with my custom DLL made by MSKLC, and I found it loads the layout mapping images automatically in the "Language" - "input method" - "preview":我试图用MSKLC制作的自定义DLL替换DLL文件,我发现它会在“语言”-“输入法”-“预览”中自动加载布局映射图像:

在此处输入图像描述

So we know that the mapping is there in the DLL.所以我们知道映射在 DLL 中。

It is a fairly well-known fact that MSKLC is unable to faithfully import & reproduce keyboard layouts for all of the.DLL files supplied by Windows–especially those in Windows 8 & above.众所周知,MSKLC 无法忠实地导入和重现 Windows 提供的所有.DLL 文件的键盘布局,尤其是 Windows 8 及更高版本中的那些文件。 And it doesn't do any good to know where those files are if you can't extract any meaningful or helpful information from them.如果您无法从中提取任何有意义或有用的信息,那么知道这些文件在哪里也没有任何好处。 This is documented by Michael Kaplan on his blog (he was a developer of MSKLC) which I see you have linked to above. Michael Kaplan 在他的博客(他是 MSKLC 的开发人员)上记录了这一点,我看到你已经链接到上面。

When MSKLC encounters anything it does not understand, that portion is removed.当 MSKLC 遇到任何它不理解的内容时,该部分将被删除。 Extracting the layout using MSKLC will work for most keyboards, but there are a few–namely the Cherokee keyboard, and the Japanese & Korean keyboards (to name a few, I'm not sure how many more there are)–for which the extracted layout will NOT accurately or completely reflect the actual usage & features of the keyboard.使用 MSKLC 提取布局适用于大多数键盘,但也有少数——即 Cherokee 键盘和日韩键盘(仅举几例,我不确定还有多少)——提取的布局不会准确或完全反映键盘的实际使用和功能。 The Cherokee keyboard has chained dead keys which MSKLC doesn't support. Cherokee 键盘具有 MSKLC 不支持的链接死键。 And the far Eastern keyboards have modifier keys which MSKLC isn't aware of–that means entire layers/shift states which are missing!远东键盘具有 MSKLC 不知道的修饰键——这意味着缺少整个层/移位状态!

Michael Kaplan supplies some code and unlocks some of the secrets of MSLKC and the accompanying software that can be used to get around some of these limitations but it requires a fair amount of doing things by hand–exactly what you're trying to avoid, Plus, Michael's objectives are aimed at creating keyboards with features that MSKLC can not create or understand. Michael Kaplan 提供了一些代码并解开了 MSLKC 的一些秘密以及可用于绕过其中一些限制的随附软件,但它需要大量的手工操作——这正是你试图避免的,另外, Michael 的目标是创建具有 MSKLC 无法创建或理解的功能的键盘。 but which DO work in Windows (which is the opposite of what the OP is trying to accomplish).但是哪个在 Windows 中工作(这与 OP 试图完成的相反)。

I am sure that my solution comes too late to be of use to the OP, but perhaps it will be helpful in the future to someone in a similar situation.我确信我的解决方案来得太晚,无法用于 OP,但也许它在未来对处于类似情况的人会有所帮助。 That is my hope and reason for posting this.这就是我发布这个的希望和原因。

So far all I've done is explain that the other answers are insufficient.到目前为止,我所做的只是解释其他答案是不够的。 Even the best one will not and can not fully & accurately reproduce all of Windows' native keyboards and render them into KLC source files.即使是最好的键盘也不会也不可能完全准确地再现所有 Windows 的本机键盘并将它们呈现为 KLC 源文件。 This is really unfortunate and it is certainly not the fault of its author because that is a very clever piece of code/script, Thankfully the script & the source files (whose link may or may not still work) is useful & effective for the majority of Windows' keyboards.这真的很不幸,这当然不是其作者的错,因为这是一段非常聪明的代码/脚本,谢天谢地,脚本和源文件(其链接可能会或可能不会仍然有效)对大多数人来说都是有用和有效的Windows 的键盘。 as well as any custom keyboards created by MSKLC.以及由 MSKLC 创建的任何自定义键盘。

The keyboards that have the advanced features that MSKLC doesn't support were created by the Windows DDK, but those features are not officially documented.具有 MSKLC 不支持的高级功能的键盘是由 Windows DDK 创建的,但这些功能并未正式记录。 Although one can learn quite a bit about their potential by studying the source files provided with MSKLC.虽然人们可以通过研究 MSKLC 提供的源文件来了解它们的潜力。

Sadly the only solution I can offer is 3rd party, paid software called KbdEdit .遗憾的是,我能提供的唯一解决方案是名为KbdEdit的第 3 方付费软件。 I believe it is the only currently available solution which is actually able to faithfully decode & recreate any of the Windows supplied keyboards–although there are a few advanced features which even it can not reproduce (such as keys combinations/hotkeys which perform special native language functions; for example: Ctrl+CapsLock to activate KanaLock (a Japanese modifier layer). KbdEdit DOES faithfully reproduce that modifier layer which MSKLC with strip away, it just doesn't support this alternate method of activating that shift state if you don't have a Japanese keyboard with a Kana lock key. Although, it will allow you to convert a key on your keyboard to a Kana key (perhaps Scroll Lock?).我相信它是目前唯一真正能够忠实地解码和重新创建 Windows 提供的键盘的可用解决方案——尽管有一些高级功能甚至无法重现(例如执行特殊母语的组合键/热键功能;例如:Ctrl+CapsLock 激活 KanaLock(日本修改器层)。KbdEdit 确实忠实地再现了 MSKLC 剥离的修改器层,它只是不支持这种激活转换 state 的替代方法,如果你不这样做有一个带有假名锁定键的日文键盘。虽然,它允许您将键盘上的键转换为假名键(也许是 Scroll Lock?)。

Fortunately, none of those unsupported features are even applicable to an on-screen keyboard.幸运的是,这些不受支持的功能甚至都不适用于屏幕键盘。

KbdEdit is a really powerful & amazing tool, and it has been worth every penny I paid for it, (And that's NOT something I would say about virtually any other paid software…) Even though KbdEdit is 3rd party software, it is only needed to create the keyboards. KbdEdit 是一个非常强大且令人惊叹的工具,我为它付出的每一分钱都物有所值,(这不是我对几乎任何其他付费软件所说的话......)即使 KbdEdit 是第 3 方软件,它只需要创建键盘。 not to use them.不要使用它们。 All of the keyboards it creates work natively on any Windows system without KbdEdit being installed, It supports up to 15 modifier states and three addition modifier keys.它创建的所有键盘都可以在没有安装 KbdEdit 的任何 Windows 系统上本地工作,它支持多达 15 个修改状态和三个附加修改键。 one which is togglable–like CapsLock, It also supports chained dead keys.一种是可切换的——比如 CapsLock,它还支持链式死键。 and remapping any of the keys on most any keyboard.并重新映射大多数键盘上的任何键。

Why don't you use the on-screen keyboard (osk.exe)?为什么不使用屏幕键盘(osk.exe)? Looks like you re-inventing the wheel.看起来你重新发明了轮子。 And not the easiest one!而且不是最简单的!

Please check following Windows API请检查以下 Windows API

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

Check MSDN here在此处查看 MSDN

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM