2009-03-19 5 views
8

OK, esta es una pregunta un poco rara.Extracción de diseños de teclado desde Windows

Tenemos una aplicación de pantalla táctil (es decir, sin teclado). Cuando los usuarios necesitan ingresar texto, la aplicación muestra el teclado virtual, construido a mano en WinForms.

Hacer estas cosas a mano para cada nuevo idioma es el trabajo del mono. Me imagino que las ventanas deben tener esta información de diseño del teclado escondida en algún lugar de alguna dll. ¿Habría alguna forma de sacar esta información de las ventanas?

Otras ideas bienvenidas (Me imagino que al menos generar la cosa de un archivo xml tiene que ser mejor que hacerlo a mano en VS).

(Nota: una vez dicho todo lo cual, observo que hay un teclado japonés, máquina de estado y todo ..., por lo XML podría no ser suficiente)

ACTUALIZACIÓN: muy buena serie sobre este tema (creo) here

+2

Esa es una pregunta realmente genial ... También podría ser posible trasladar los diseños a otros entornos (Linux), pero tal vez sea una violación de los derechos de autor, por supuesto. – unwind

+0

¿No sería más fácil usar el teclado incorporado de la tableta de Windows? (obviamente necesita las extensiones correctas instaladas en el sistema operativo, pero parece que ya basta con enchufar un wacom en él en estos días, ¿así que podría haber más formas?). –

Respuesta

6

Microsoft Keyboard Layout Creator puede cargar los teclados del sistema y exportarlos como .klc files. Dado que está escrito en .NET, puede usar Reflector para ver cómo lo hace y usar el reflejo para conducirlo. Aquí hay un zip file of .klc files for the 187 keyboards in Windows 8 creado usando el siguiente código C#. Tenga en cuenta que originalmente escribí esto para Windows XP, y ahora con Windows 8 y el teclado en pantalla, es muy lento y suele bloquearse la barra de tareas:/Sin embargo, funciona :)

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

} 

Básicamente, obtiene una lista de todos los teclados del sistema, luego para cada uno, lo carga en MSKLC, establece el nombre de archivo "Guardar como", miente sobre si ya está configurado las propiedades del teclado personalizado, y luego simula un clic en el Archivo - > Guardar elemento de menú.

+0

¡Esa es una buena respuesta! Tendré que intentarlo ... – Benjol

+0

-1 ya que el tarball ya no se puede encontrar. Actualizaré una vez que esté accesible de nuevo. – Deleted

+0

@El enlace de Kent está fijado – andrewdotn

0

Compruebe los siguientes API de Windows

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

Comprobar MSDN here

+0

Hm, esto solo carga un diseño de teclado en el proceso/hilo actual, no me permite reproducirlo visualmente (es decir, qué tecla está en qué posición). – Benjol

+0

Aunque es posible que haya algo aquí, aparentemente MapVirtualKey puede asignar un scancode (hardware) a una VirtualKey, y GetKeyNameText puede convertir un scancode en una cadena ... – Benjol

2

¿Por qué no usa el teclado en pantalla (osk.exe)? Parece que reinventa la rueda. ¡Y no el más fácil!

+0

Una cuestión de lookologie, me temo. Tenga en cuenta que este es un proyecto previo a la wpf donde recodificaron todos los controles a mano, para que sean más bonitos. – Benjol

+0

También es un poco pequeño para una pantalla táctil. – ProfK

1

sé dónde están camino de estos archivos DLL:

En su registro, que se ve:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts 

donde cada rama tiene algún valor como "Layout File"="KBDSP.dll". El directorio raíz es

C:\Windows\System32 

y

C:\Windows\SystemWOW64 

Esos son toda la disposición del teclado archivos se encuentran. Por ejemplo, KBDUS.dll significa "teclado para EE. UU.".

Me trataron de sustituir el archivo DLL con mi DLL personalizada hecha por MSKLC, y me pareció que carga las imágenes cartográficas diseño automáticamente en el "idioma" - "método de entrada" - "vista previa":

enter image description here

Así que sabemos que la asignación está allí en el archivo DLL.

Cuestiones relacionadas