2009-03-19 1 views
8

OK, das ist eine etwas seltsame Frage.Extrahieren Tastaturlayouts von Windows

Wir haben eine Touchscreen-Anwendung (d. H. Keine Tastatur). Wenn Benutzer Text eingeben müssen, zeigt die Anwendung eine virtuelle Tastatur an, die in WinForms erstellt wurde.

Diese Dinge für jede neue Sprache von Hand zu machen ist Affe Arbeit. Ich denke, dass Windows muss diese Tastaturlayout Informationen irgendwo in einer DLL verstecken. Wäre es trotzdem möglich, diese Informationen aus den Fenstern zu holen?

Andere Ideen willkommen (Ich denke, zumindest das Ding aus einer XML-Datei generieren muss besser sein als es in VS von Hand).

(Hinweis: gesagt hat, alles, was ich fest, dass es eine japanische Tastatur ist die Zustandsmaschine und alle ..., so XML nicht ausreichend sein könnte)

UPDATE: ziemlich gute Serie zu diesem Thema (ich glaube) here

+2

Das ist eine wirklich coole Frage ... Das Portieren der Layouts in andere Umgebungen (Linux) könnte ebenfalls möglich sein, aber es ist natürlich eine Verletzung des Urheberrechts. – unwind

+0

Wäre es nicht einfacher, die integrierte Windows-Tablet-Tastatur zu verwenden? (Natürlich braucht man die richtigen Erweiterungen, die im Betriebssystem installiert sind, aber es scheint, dass es genügt, nur einen Wacom hinein zu stecken, also könnte es mehr Wege geben?). –

Antwort

6

Microsoft Keyboard Layout Creator kann Systemtastaturen laden und exportieren Sie sie als .klc files. Da es in .NET geschrieben ist, können Sie Reflector verwenden, um zu sehen, wie es das macht, und Reflektion verwenden, um es zu steuern. Hier ist eine zip file of .klc files for the 187 keyboards in Windows 8 erstellt mit dem folgenden C# -Code. Beachten Sie, dass ich ursprünglich schrieb dies für Windows XP und jetzt mit Windows 8 und der Tastatur auf dem Bildschirm, es ist wirklich langsam und scheint die Taskleiste zu einem Absturz:/Aber es funktioniert :)

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(); 
    } 

} 

Grundsätzlich Es ruft eine Liste aller Tastaturen auf dem System ab, lädt sie dann in MSKLC, legt den Dateinamen "Speichern unter" fest, legt fest, ob die benutzerdefinierten Tastatureigenschaften bereits konfiguriert sind, und simuliert dann einen Klick auf die Datei - > Menüpunkt speichern.

+0

Das ist eine coole Antwort! Ich muss es versuchen ... – Benjol

+0

-1, da der Tarball nicht mehr gefunden werden kann. Ich werde aktualisieren, sobald es wieder zugänglich ist. – Deleted

+0

@Kent Link ist fest – andrewdotn

0

Bitte überprüfen Sie folgende Windows-API

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

prüfen MSDN here

+0

Hm, dies lädt nur ein Tastaturlayout im aktuellen Prozess/Thread, es erlaubt mir nicht, es visuell zu reproduzieren (d. H. Welcher Schlüssel in welcher Position ist). – Benjol

+0

Auch wenn Sie hier etwas machen können, kann MapVirtualKey offensichtlich einen Scancode (Hardware) einem VirtualKey zuordnen, und GetKeyNameText kann einen Scancode in einen String umwandeln ... – Benjol

2

Warum verwenden Sie nicht die Bildschirmtastatur (osk.exe)? Sieht so aus, als hättest du das Rad neu erfunden. Und nicht der einfachste!

+0

Eine Frage der Lookologie, fürchte ich. Denken Sie daran, dass dies ein Pre-WPF-Projekt ist, bei dem alle Bedienelemente von Hand neu programmiert wurden, um sie schöner zu machen. – Benjol

+0

Es ist auch ein bisschen klein für einen Touchscreen. – ProfK

1

Ich weiß, wo diese DLL-Dateien Pfad sind:

in Ihrer Registrierung, Sie sehen:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts 

wo jeder Zweig einen Wert wie "Layout File"="KBDSP.dll" hat. Das Stammverzeichnis ist

C:\Windows\System32 

und

C:\Windows\SystemWOW64 

Das sind alle Tastaturlayout-Dateien befinden. Zum Beispiel bedeutet KBDUS.dll "Tastatur für US".

Ich habe versucht, die DLL-Datei mit meiner benutzerdefinierten DLL durch MSKLC, und ich fand es lädt die Layout-Mapping Bilder automatisch in der „Sprache“ gemacht zu ersetzen - „Eingabemethode“ - „Vorschau“:

enter image description here

So wissen wir, dass das Mapping in der DLL ist.