好的,这是一个有点奇怪的问题。
我们有一个触摸屏应用程序(即没有键盘)。当用户需要输入文本时,应用程序会显示虚拟键盘 - 手工构建在WinForms中。
为每种新语言手工制作这些东西都是猴子的工作。我认为Windows必须将此键盘布局信息隐藏在某些dll中的某处。无论如何都会从窗口获取这些信息吗?
欢迎其他想法(我认为至少从xml文件生成东西必须比在VS中手动执行更好)。
(注意:说了所有这些,我注意到有一个日文键盘,状态机和所有......,所以XML可能还不够)
更新:关于此主题的相当不错的系列(我相信)here
答案 0 :(得分:6)
Microsoft Keyboard Layout Creator可以加载系统键盘并将其导出为.klc files。由于它是用.NET编写的,因此您可以使用Reflector来查看它是如何做到的,并使用反射来驱动它。这是使用以下C#代码创建的zip file of .klc files for the 187 keyboards in 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中,设置“另存为”文件名,说明它是否已经配置了自定义键盘属性,然后模拟一个点击文件 - >保存菜单项。
答案 1 :(得分:2)
为什么不使用屏幕键盘(osk.exe)?看起来你正在重新发明轮子。而不是最容易的!
答案 2 :(得分:2)
我知道这些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中存在映射。
答案 3 :(得分:2)
众所周知,MSKLC无法忠实地导入和复制Windows提供的所有.DLL文件的键盘布局,尤其是Windows 8及更高版本中的键盘布局。如果您无法从这些文件中提取任何有意义或有用的信息,那么知道这些文件在哪里也无济于事。 迈克尔·卡普兰(Michael Kaplan)在他的博客(他曾是MSKLC的开发者)上对此进行了记录,我发现您已链接到上面。
当MSKLC遇到它不了解的任何内容时,该部分将被删除。 使用MSKLC提取布局可用于大多数键盘,但是有几种-即切诺基键盘和日文和韩文键盘(仅举几例,我不确定还有多少种键盘)-提取的是布局不会准确或完全反映键盘的实际使用情况和功能。 切诺基键盘已链接MSKLC不支持的死键。而且远东的键盘具有MSKLC不知道的修饰键-这意味着缺少整个图层/移位状态!
Michael Kaplan提供了一些代码并解锁了MSLKC及其附带的软件的一些秘密,这些秘密可用于解决这些限制中的一些限制,但是它需要大量的手工工作-正是您要尝试的事情避免!另外,Michael的目标是创建具有MSKLC无法创建或理解的功能的键盘,但是这些功能确实可以在Windows中工作(这与OP试图实现的功能相反)。
我确定我的解决方案来不及使用OP,但是将来对类似情况的人可能会有所帮助。这是我发布此帖子的希望和理由。
到目前为止,我所做的只是解释其他答案还不够。即使是最好的键盘,也不会,也不会完全准确地重现Windows的所有本机键盘并将它们呈现为KLC源文件。这确实是不幸的,并且肯定不是作者的错,因为那是一段非常聪明的代码/脚本!幸运的是,脚本和源文件(其链接可能会或可能仍然无法使用)对于大多数Windows键盘以及MSKLC创建的任何自定义键盘都是有用且有效的。
具有MSKLC不支持的高级功能的键盘是由Windows DDK创建的,但是这些功能并未正式记录。尽管可以通过研究MSKLC随附的源文件来了解它们的潜力。
遗憾的是,我唯一能提供的解决方案是名为KbdEdit的第三方付费软件。我相信这是目前唯一可用的解决方案,实际上能够忠实地解码和重新创建Windows提供的任何键盘-尽管有一些高级功能甚至无法再现(例如,执行特殊本地语言的按键组合/热键)函数;例如:Ctrl + CapsLock激活KanaLock(日语修改器层)KbdEdit确实复制了带MSKLC的修改器层,如果不这样做,它不支持激活移位状态的替代方法的日语键盘带有假名锁定键,尽管如此,它可以让您将键盘上的键转换为假名键(也许是Scroll Lock?)。
幸运的是,所有这些不受支持的功能甚至都不适用于屏幕键盘。
KbdEdit是一个功能强大且令人赞叹的工具,值得我为此付出的每一分钱! (关于几乎所有其他付费软件,我都不会这么说……) 即使KbdEdit是第三方软件,也只需要创建键盘即可,而无需使用它们。它创建的所有键盘都可以在没有安装KbdEdit的任何Windows系统上本地运行。 它最多支持15个修改器状态和三个附加修改器键,其中之一是可切换的,如CapsLock。它还支持链式死键,并且可以重新映射大多数键盘上的任何键。
答案 4 :(得分:0)
请检查以下Windows API
[DllImport("user32.dll")]
private static extern long LoadKeyboardLayout(string pwszKLID, uint Flags);