2009-03-19 5 views
8

좋습니다. 약간 이상한 질문입니다.Windows에서 키보드 레이아웃을 추출하는 중입니다.

Google에는 터치 스크린 응용 프로그램 (즉, 키보드 없음)이 있습니다. 사용자가 텍스트를 입력해야 할 때 응용 프로그램은 가상 키보드를 보여줍니다.

새로운 언어마다 손으로 이러한 작업을하는 것은 원숭이 작업입니다. 나는이 키보드 레이아웃 정보가 어딘가에 숨어 있어야한다고 생각한다. 창문 밖으로이 정보를 얻을 수 있습니까?

다른 아이디어를 환영합니다 (적어도 XML 파일에서 생성하는 것은 VS에서 손으로 수행하는 것보다 낫지 만).

이 주제에 꽤 좋은 시리즈 :

UPDATE (참고 나는 일본어 키보드, 상태 머신이 있음을 유의하는 모든 모든이 ... 그래서 XML이 충분하지 않을 수 미루어) here

+2

정말 멋진 질문입니다 ... 다른 환경 (Linux)으로 레이아웃을 이식하는 것도 가능할 수 있지만 물론 저작권에 위배 될 수 있습니다. – unwind

+0

내장 된 Windows 태블릿 키보드를 사용하는 것이 더 쉽지 않습니까? (OS에 올바른 확장 기능이 설치되어 있어야하지만 요즘에는 와콤을 연결하는 것만으로도 충분할 것입니다. –

답변

6

Microsoft Keyboard Layout Creator은 시스템 키보드를로드하여 .klc files으로 내보낼 수 있습니다. .NET으로 작성되었으므로 Reflector을 사용하면 어떻게되는지 확인할 수 있으며 리플렉션을 사용하여이를 구동 할 수 있습니다. 아래는 C# 코드를 사용하여 생성 한 zip file of .klc files for the 187 keyboards in Windows 8입니다. 내가 원래 Windows XP 용 쓴, 지금은 윈도우 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 파일 '경로 곳

+0

멋진 답변입니다! 나는 그것을 시도해야 할 것이다 ... – Benjol

+0

-1은 타르볼을 더 이상 발견 할 수 없다. 다시 액세스 할 수있게되면 업데이트하겠습니다. – Deleted

+0

@Kent 링크가 고정되어 있습니다 – andrewdotn

0

윈도우 API 다음 확인하시기 바랍니다 (저는 믿습니다)

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

확인 MSDN here

+0

흠, 이것은 현재 프로세스/스레드에서 키보드 레이아웃을로드하기 만하면 시각적으로 (즉, 어떤 키가 어떤 위치에 있는지) 재현 할 수 없습니다. – Benjol

+0

여기에 뭔가있을 수도 있지만 분명히 MapVirtualKey는 스캔 코드 (하드웨어)를 VirtualKey에 매핑 할 수 있으며 GetKeyNameText는 스캔 코드를 문자열로 변환 할 수 있습니다. – Benjol

2

화상 키보드 (osk.exe)를 사용하지 않는 이유는 무엇입니까? 네가 바퀴를 다시 발명 한 것 같아. 그리고 가장 쉬운 방법은 아닙니다!

+0

lookologie의 질문, 나는 두려워합니다. 이 컨트롤은 pre-wpf 프로젝트로 모든 컨트롤을 직접 손으로 다시 코딩하여 더욱 예쁘게 만들 수 있음을 명심하십시오. – Benjol

+0

터치 스크린의 경우 약간 작습니다. – ProfK

1

내가 아는 : 레지스트리에서

, 당신은 참조 : 각 지점은 "Layout File"="KBDSP.dll" 같은 몇 가지 값을 가지고

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts 

. 루트 디렉토리는

C:\Windows\System32 

C:\Windows\SystemWOW64 

사람들은 파일이있는 모든 키보드 레이아웃입니다이다. 예를 들어 KBDUS.dll은 "미국 용 키보드"를 의미합니다.

나는 MSKLC에 의해 만들어 내 사용자 지정 DLL과 DLL 파일을 대체 할 시도하고, 나는 그것이 "언어"자동 레이아웃 매핑 이미지를로드 발견 - "입력 방법"- "미리보기"

enter image description here

그래서 우리는 매핑이 DLL에 있음을 알고 있습니다.

관련 문제