簡體   English   中英

從 windows 中提取鍵盤布局

[英]Extracting keyboard layouts from windows

好的,這是一個有點奇怪的問題。

我們有一個觸摸屏應用程序(即沒有鍵盤)。 當用戶需要輸入文本時,應用程序會顯示虛擬鍵盤 - WinForms 中手動內置。

為每種新語言手工制作這些東西是猴子的工作。 我認為 windows 必須將此鍵盤布局信息隱藏在某些 dll 的某處。 無論如何可以從 windows 中獲取這些信息嗎?

歡迎其他想法(我認為至少從 xml 文件生成東西必須比在 VS 中手動生成要好)。

(注意:說了這么多,我注意到有一個日文鍵盤,state 機器和所有......,所以 XML 可能還不夠)

更新:關於這個主題的很好的系列(我相信)在這里

Microsoft Keyboard Layout Creator可以加載系統鍵盤並將它們導出為.klc 文件 由於它是用 .NET 編寫的,因此您可以使用Reflector來查看它是如何做到的,並使用反射來驅動它。 這是使用以下 C# 代碼創建的Windows 8 中 187 個鍵盤的 zip 文件 of.klc 文件 請注意,我最初是為 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 中,設置“另存為”文件名,確定是否已經配置了自定義鍵盤屬性,然后模擬單擊文件 -> 保存菜單項。

我知道這些 DLL 文件的路徑在哪里:

在您的注冊表中,您會看到:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts

其中每個分支都有一些值,例如"Layout File"="KBDSP.dll" 根目錄是

C:\Windows\System32

C:\Windows\SystemWOW64

這些是所有鍵盤布局文件所在的位置。 例如, KBDUS.dll表示“美國鍵盤”。

我試圖用MSKLC制作的自定義DLL替換DLL文件,我發現它會在“語言”-“輸入法”-“預覽”中自動加載布局映射圖像:

在此處輸入圖像描述

所以我們知道映射在 DLL 中。

眾所周知,MSKLC 無法忠實地導入和重現 Windows 提供的所有.DLL 文件的鍵盤布局,尤其是 Windows 8 及更高版本中的那些文件。 如果您無法從中提取任何有意義或有用的信息,那么知道這些文件在哪里也沒有任何好處。 Michael Kaplan 在他的博客(他是 MSKLC 的開發人員)上記錄了這一點,我看到你已經鏈接到上面。

當 MSKLC 遇到任何它不理解的內容時,該部分將被刪除。 使用 MSKLC 提取布局適用於大多數鍵盤,但也有少數——即 Cherokee 鍵盤和日韓鍵盤(僅舉幾例,我不確定還有多少)——提取的布局不會准確或完全反映鍵盤的實際使用和功能。 Cherokee 鍵盤具有 MSKLC 不支持的鏈接死鍵。 遠東鍵盤具有 MSKLC 不知道的修飾鍵——這意味着缺少整個層/移位狀態!

Michael Kaplan 提供了一些代碼並解開了 MSLKC 的一些秘密以及可用於繞過其中一些限制的隨附軟件,但它需要大量的手工操作——這正是你試圖避免的,另外, Michael 的目標是創建具有 MSKLC 無法創建或理解的功能的鍵盤。 但是哪個在 Windows 中工作(這與 OP 試圖完成的相反)。

我確信我的解決方案來得太晚,無法用於 OP,但也許它在未來對處於類似情況的人會有所幫助。 這就是我發布這個的希望和原因。

到目前為止,我所做的只是解釋其他答案是不夠的。 即使是最好的鍵盤也不會也不可能完全准確地再現所有 Windows 的本機鍵盤並將它們呈現為 KLC 源文件。 這真的很不幸,這當然不是其作者的錯,因為這是一段非常聰明的代碼/腳本,謝天謝地,腳本和源文件(其鏈接可能會或可能不會仍然有效)對大多數人來說都是有用和有效的Windows 的鍵盤。 以及由 MSKLC 創建的任何自定義鍵盤。

具有 MSKLC 不支持的高級功能的鍵盤是由 Windows DDK 創建的,但這些功能並未正式記錄。 雖然人們可以通過研究 MSKLC 提供的源文件來了解它們的潛力。

遺憾的是,我能提供的唯一解決方案是名為KbdEdit的第 3 方付費軟件。 我相信它是目前唯一真正能夠忠實地解碼和重新創建 Windows 提供的鍵盤的可用解決方案——盡管有一些高級功能甚至無法重現(例如執行特殊母語的組合鍵/熱鍵功能;例如:Ctrl+CapsLock 激活 KanaLock(日本修改器層)。KbdEdit 確實忠實地再現了 MSKLC 剝離的修改器層,它只是不支持這種激活轉換 state 的替代方法,如果你不這樣做有一個帶有假名鎖定鍵的日文鍵盤。雖然,它允許您將鍵盤上的鍵轉換為假名鍵(也許是 Scroll Lock?)。

幸運的是,這些不受支持的功能甚至都不適用於屏幕鍵盤。

KbdEdit 是一個非常強大且令人驚嘆的工具,我為它付出的每一分錢都物有所值,(這不是我對幾乎任何其他付費軟件所說的話......)即使 KbdEdit 是第 3 方軟件,它只需要創建鍵盤。 不要使用它們。 它創建的所有鍵盤都可以在沒有安裝 KbdEdit 的任何 Windows 系統上本地工作,它支持多達 15 個修改狀態和三個附加修改鍵。 一種是可切換的——比如 CapsLock,它還支持鏈式死鍵。 並重新映射大多數鍵盤上的任何鍵。

為什么不使用屏幕鍵盤(osk.exe)? 看起來你重新發明了輪子。 而且不是最簡單的!

請檢查以下 Windows API

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

在此處查看 MSDN

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM