2013-03-18 24 views
2

我有一個應用程序,登錄任何用戶按下,但是當我按下特殊字符,如´a,得到á,我得到´´a;同樣的事情,當我想要à,然後我得到``a,所以所有的特殊字符被鍵入兩次,然後常規字符被鍵入後。雙字符

我找遍了,找不到任何東西。但我注意到,問題出在ToAscii方法中,沒有正確輸入字符。

public string GetString(IntPtr lParam, int vCode) 
{ 
    try 
    { 
     bool shift = Keys.Shift == Control.ModifierKeys || Console.CapsLock; 

     string value = ""; 

     KeyboardHookStruct MyKeyboardHookStruct = 
      (KeyboardHookStruct)Marshal.PtrToStructure(
       lParam, typeof(KeyboardHookStruct)); 

     byte[] keyState = new byte[256]; 
     byte[] inBuffer = new byte[2]; 

     DllClass.GetKeyboardState(keyState); 

     var ascii= 
      DllClass.ToAscii(
       MyKeyboardHookStruct.vkCode, 
       MyKeyboardHookStruct.scanCode, 
       keyState, inBuffer, MyKeyboardHookStruct.flags 
       ); 

     if (ascii == 1) 
     { 
      char key = (char)inBuffer[0]; 

      if ((shift) && Char.IsLetter(key)) 
       key = Char.ToUpper(key); 

      value = key.ToString(); 
     } 

     return value; 
    } 
    catch (Exception) 
    { 
     return ""; 
    } 
} 

我錯過了什麼或做錯了什麼?所有其他角色都可以完美運行,但它是以雙字符形式出現的特殊字符。


編輯:

ToUnicode而不是試圖。

[DllImport("USER32.DLL", CharSet = CharSet.Unicode)] 
public static extern int ToUnicode(
    uint virtualKey, uint scanCode, byte[] keyStates, 
    [MarshalAs(UnmanagedType.LPArray)] [Out] char[] chars, 
    int charMaxCount, uint flags); 

public string GetString(IntPtr lParam, int vCode) 
{ 
    try 
    { 
     bool shift = Keys.Shift == Control.ModifierKeys || Console.CapsLock; 

     string value = ""; 

     KeyboardHookStruct MyKeyboardHookStruct = 
      (KeyboardHookStruct)Marshal.PtrToStructure(
       lParam, typeof(KeyboardHookStruct)); 

     byte[] keyState = new byte[256]; 
     byte[] inBuffer = new byte[2]; 

     char[] chars = new char[2]; 

     DllClass.GetKeyboardState(keyState); 

     int val = 0; 

     val = ToUnicode(
       (uint)MyKeyboardHookStruct.vkCode, 
       (uint)MyKeyboardHookStruct.scanCode, 
       keyState, chars, chars.Length, 0 
       ); 

     val = ToUnicode(
       (uint)MyKeyboardHookStruct.vkCode, 
       (uint)MyKeyboardHookStruct.scanCode, 
       keyState, chars, chars.Length, 0 
       ); 

     if (val == 1) 
     { 
      char key = (char)chars[0]; 

      if ((shift) && Char.IsLetter(key)) 
       key = Char.ToUpper(key); 

      value = key.ToString(); 
     } 

     return value; 
    } 
    catch (Exception) 
    { 
     return ""; 
    } 
} 

有人請幫助我,我真的需要弄清楚=/


編輯:

int val = -1; 

if (IsDeadKey((uint)vCode)) 
{ 
    while (val == -1) 
    { 
     val = ToUnicode(
       (uint)MyKeyboardHookStruct.vkCode, 
       (uint)MyKeyboardHookStruct.scanCode, 
       keyState, chars, chars.Length, 0 
       ); 
    } 
} 
else 
    val = ToUnicode(
      (uint)MyKeyboardHookStruct.vkCode, 
      (uint)MyKeyboardHookStruct.scanCode, 
      keyState, chars, chars.Length, 0 
      ); 

所以,現在我已經打過電話了ToAsciiToUnicode幾次沖洗特色,但都沒有成功。我做錯了嗎?

贊成ASCII,第一個電話´我得到-1,所以我再次調用它,然後我得到1;然後我按01​​,得到á,但後來我只得到a。同樣的事情,如果我以後對方使用ToUnicode兩次,我得到的只是a代替á,等等...

+10

鍵盤記錄器...他們不應該存在。 – 2013-03-18 23:11:48

+1

我完全同意我的朋友,但這不是你想到的那種鍵盤記錄器。這實際上是一個針對有記住用戶名/密碼問題的人的學校項目,通過這個工具,他們將把所有內容保存在一個安全的地方。 – syncis 2013-03-18 23:17:41

+9

是的,關於鍵盤記錄器和密碼沒有任何不安全的地方。 – 2013-03-18 23:23:14

回答

4
  • 神話約ToAsciiToUnicode

    在的問題,你提到,你都試過ToAsciiToUnicode沒有成功。我還搜查一個問題是相對的:

    ToAscii/ToUnicode in a keyboard hook destroys dead keys

    我不是說任何的答案是對還是錯。但是,我們可以想一想:

    • A(沒有的話)棘手的遊戲

      在這個遊戲中,我給玩家在同一時間隨機翻轉50美分的硬幣。一個人可以挑戰從我這裏得到一美元的鈔票,如果誰收集了一雙帶有的50美分硬幣,一個是頭部另一個是尾部

      如果一個人放棄了挑戰,那麼誰可以保留50美分,遊戲重新開始。如果誰嘗試但沒有收集符合規則的人,那麼我要求將我給的那些回報給我。

      如何從我身上獲得一美元的鈔票而不會損失任何硬幣?

    也許一時間旅行..


基礎上[Processing Global Mouse and Keyboard Hooks in C#]在CodeProject

和我很老的回答:Konami Code in C#

我做了一些修改回答你的問題。

  • 代碼

    namespace Gma.UserActivityMonitor { 
        using System.Diagnostics; 
        using System.Windows.Forms; 
    
        using System.Collections.Generic; 
        using System.Linq; 
    
        partial class HookManager { 
         private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam) { 
          // indicates if any of underlaing events set e.Handled flag 
          bool handled=false; 
    
          if(nCode>=0) { 
           // read structure KeyboardHookStruct at lParam 
           var MyKeyboardHookStruct= 
            (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); 
    
           // raise KeyDown 
           if(s_KeyDown!=null&&(wParam==WM_KEYDOWN||wParam==WM_SYSKEYDOWN)) { 
            Keys keyData=(Keys)MyKeyboardHookStruct.VirtualKeyCode; 
            KeyEventArgs e=new KeyEventArgs(keyData); 
            s_KeyDown.Invoke(null, e); 
            handled=e.Handled; 
           } 
    
           // raise KeyPress 
           if(s_KeyPress!=null&&wParam==WM_KEYDOWN) { 
            var keyText=GetString(lParam, nCode, ref handled); 
    
            if(""!=keyText) { 
             var keyChar=keyText.First(); 
             Debug.Print("keyText => {0}", keyText); 
    
    #if false 
             if(AccentFormatter.Combination.Values.Contains(keyChar)) { 
              SendKeys.Send("\b"+keyText); 
              return -1; 
             } 
    #endif 
            } 
           } 
    
           // raise KeyUp 
           if(s_KeyUp!=null&&(wParam==WM_KEYUP||wParam==WM_SYSKEYUP)) { 
            Keys keyData=(Keys)MyKeyboardHookStruct.VirtualKeyCode; 
            KeyEventArgs e=new KeyEventArgs(keyData); 
            s_KeyUp.Invoke(null, e); 
            handled=handled||e.Handled; 
           } 
          } 
    
          // if event handled in application do not handoff to other listeners 
          if(handled) 
           return -1; 
    
          // forward to other application 
          return CallNextHookEx(s_KeyboardHookHandle, nCode, wParam, lParam); 
         } 
    
         public static String GetString(IntPtr lParam, int vCode, ref bool handled) { 
          var MyKeyboardHookStruct= 
           (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); 
    
          bool isDownShift=((GetKeyState(VK_SHIFT)&0x80)==0x80?true:false); 
          bool isDownCapslock=(GetKeyState(VK_CAPITAL)!=0?true:false); 
    
          byte[] keyState=new byte[256]; 
          GetKeyboardState(keyState); 
          byte[] inBuffer=new byte[2]; 
    
          var keyText=""; 
    
          var ascii= 
           ToAscii(
            MyKeyboardHookStruct.VirtualKeyCode, 
            MyKeyboardHookStruct.ScanCode, 
            keyState, inBuffer, MyKeyboardHookStruct.Flags 
            ); 
    
          if(ascii==1) { 
           char key=(char)inBuffer[0]; 
    
           if((isDownCapslock^isDownShift)&&Char.IsLetter(key)) 
            key=Char.ToUpper(key); 
    
           KeyPressEventArgs e=new KeyPressEventArgs(key); 
           s_KeyPress.Invoke(null, e); 
           handled=handled||e.Handled; 
    
           keyText=new String(new[] { e.KeyChar }); 
           var sequence=KeySequence.Captured(e.KeyChar); 
    
           if(null!=sequence) 
            keyText=sequence.ToString(AccentFormatter.Default); 
          } 
    
          return keyText; 
         } 
        } 
    
        public class KeySequence { 
         public String ToString(IFormatProvider provider) { 
          return 
           null==provider 
            ?new String(Sequence.Select(x => (char)x).ToArray()) 
            :String.Format(provider, "{0}", Sequence); 
         } 
    
         public override String ToString() { 
          return this.ToString(default(IFormatProvider)); 
         } 
    
         public bool Captures(int keyValue) { 
          for(var i=Sequence.Length; i-->0;) { 
           if(Sequence[i]!=keyValue) { 
            if(0==i) 
             Count=0; 
    
            continue; 
           } 
    
           if(Count!=i) 
            continue; 
    
           ++Count; 
           break; 
          } 
    
          var x=Sequence.Length==Count; 
          Count=x?0:Count; 
          return x; 
         } 
    
         public KeySequence(int[] newSequence) { 
          Sequence=newSequence; 
         } 
    
         public static KeySequence Captured(int keyValue) { 
          return m_List.FirstOrDefault(x => x.Captures(keyValue)); 
         } 
    
         public int Count { 
          private set; 
          get; 
         } 
    
         public int[] Sequence { 
          set; 
          get; 
         } 
    
         static KeySequence() { 
          m_List.AddRange(
           from x in AccentFormatter.Combination.Keys 
           let intArray=x.Select(c => (int)c).ToArray() 
           select new KeySequence(intArray) 
           ); 
         } 
    
         static readonly List<KeySequence> m_List=new List<KeySequence>(); 
        } 
    
        public class AccentFormatter: IFormatProvider, ICustomFormatter { 
         String ICustomFormatter.Format(String format, object arg, IFormatProvider formatProvider) { 
          return GetAccent(new String((arg as int[]).Select(x => (char)x).ToArray())); 
         } 
    
         object IFormatProvider.GetFormat(Type formatType) { 
          return typeof(ICustomFormatter)!=formatType?null:this; 
         } 
    
         public static String GetAccent(String input) { 
          return 
           Combination.Keys.Contains(input, StringComparer.OrdinalIgnoreCase) 
            ?Combination[input].ToString() 
            :""; 
         } 
    
         static AccentFormatter() { 
          AcuteSymbol=((char)0xb4).ToString(); 
          GraveSymbol=('`').ToString(); 
    
          var ae=(char)0xe6; 
          var oe=(char)0xf8; 
          AcuteCandidates="acegiklmnoprsuwyz".ToArray().Concat(new[] { ae, oe }).ToArray(); 
          GraveCandidates="aeinouwy".ToArray(); 
    
          var lowerAcuteAccents=(
           new[] { 
            0xe1, 0x107, 
            0xe9, 0x1f5, 
            0xed, 0x1e31, 0x13a, 0x1e3f, 0x144, 
            0xf3, 0x1e55, 0x155, 0x15b, 
            0xfa, 0x1e83, 0xfd, 0x17a, 
            0x1fd, 0x1ff 
           } 
           ).Select(
            (x, i) => new { 
             Key=AcuteSymbol+AcuteCandidates[i], 
             Value=(char)x 
            } 
            ); 
    
          var upperAcuteAccents=(
           new[] { 
            0xc1, 0x106, 
            0xc9, 0x1f4, 
            0xcd, 0x1e30, 0x139, 0x1e3e, 0x143, 
            0xd3, 0x1e54, 0x154, 0x15a, 
            0xda, 0x1e82, 0xdd, 0x179, 
            0x1fc, 0x1fe 
           } 
           ).Select(
            (x, i) => new { 
             Key=AcuteSymbol+char.ToUpper(AcuteCandidates[i]), 
             Value=(char)x 
            } 
            ); 
    
          var lowerGraveAccents=(
           new[] { 0xe0, 0xe8, 0xec, 0x1f9, 0xf2, 0xf9, 0x1e81, 0x1ef3 } 
           ).Select(
            (x, i) => new { 
             Key=GraveSymbol+GraveCandidates[i], 
             Value=(char)x 
            } 
            ); 
    
          var upperGraveAccents=(
           new[] { 0xc0, 0xc8, 0xcc, 0x1f8, 0xd2, 0xd9, 0x1e80, 0x1ef2 } 
           ).Select(
            (x, i) => new { 
             Key=GraveSymbol+char.ToUpper(GraveCandidates[i]), 
             Value=(char)x 
            } 
            ); 
    
          Combination= 
           lowerAcuteAccents 
            .Concat(upperAcuteAccents) 
            .Concat(lowerGraveAccents) 
            .Concat(upperGraveAccents) 
            .ToDictionary(x => x.Key, x => x.Value); 
         } 
    
         public static readonly Dictionary<String, char> Combination; 
         public static readonly String AcuteSymbol, GraveSymbol; 
         public static readonly char[] AcuteCandidates, GraveCandidates; 
         public static readonly AccentFormatter Default=new AccentFormatter(); 
        } 
    } 
    

    首先,從CodeProject上下載的代碼,發現HookManager.Callbacks.cs刪除整個方法KeyboardHookProc

    然後您可以將上面的代碼保存在一個新文件中,例如HookManager.Modified.cs並將其添加到項目Gma.UserActivityMonitor中,或者將其粘貼到HookManager.Callbacks.cs的後部。

    請記得設置Gma.UserActivityMonitorDemo啓動項目。它將目標框架設置爲2.0,並且您可能希望將其設置爲更高。

  • 輸入輸出→

    Vmh1A.jpg

  • 關於口音

    正如我搜索有兩種普遍的口音,他們是grave accentacute accent
    急性口音的變音符號是´,可能的字母是áǽćéǵíḱĺḿńóǿṕŕśúẃýź
    嚴重口音的變音符號是', and the possible letters areàèìòòùẁỳ`。

    兩者都可能是大寫或小寫,但我沒有找到一個簡單的方法與他們在框架內置的類中一起工作。例如,我不能使用ToUpperToLower以獲得與Ǹǹ相反的情況,我甚至嘗試過ToUpperInvariantToLowerInvariant。因此,我選擇在AccentFormatter中使用硬編碼序列,並且您可以將其更改爲從文件讀取,或者自己實現另一個自定義格式化程序。十六進制表示

    在代碼的

  • 陣列布置中,我設置在銳音符序列爲:

     
    0xc1, 0x106, 
    0xc9, 0x1f4, 
    0xcd, 0x1e30, 0x139, 0x1e3e, 0x143, 
    0xd3, 0x1e54, 0x154, 0x15a, 
    0xda, 0x1e82, 0xdd, 0x179, 
    0x1fc, 0x1fe 
    

    它是:

     
    ÁĆ 
    ÉǴ 
    ÍḰĹḾŃ 
    ÓṔŔŚ 
    ÚẂÝŹ 
    ǼǾ 
    

    ǼǾ是放在後面,因爲ÆØ在ASCII(非擴展)中沒有相應的字符。

    我更喜歡使用默認代碼頁將代碼保存在ANSI中,因爲我從字母表中的語言中有不同的CultureInfo。而且您可能想要將它們更改爲精確的字符以提高可讀性。

  • 發送鍵來激活應用程序

    如果你想關鍵發送到活動的應用程序,然後執行的代碼如下變化:

    變化

    #if false 
    

    #if !false 
    

    裏面的條件編譯塊,代碼片段是

    if(AccentFormatter.Combination.Values.Contains(keyChar)) { 
        SendKeys.Send("\b"+keyText); 
        return -1; 
    } 
    

    它使用退格字符刪除以前鍵入的``or'`一旦它認定爲特定的組合。 Backspace這裏是時間機器。

在這個演示之後,我猜你會知道如何修改它們來合併你的代碼。

+0

+1感謝分享。我做了大量的研究,發現很多人都陷在這個問題上。 – 2013-03-31 04:04:11

+0

Í無法得到它的工作,仍然得到一個沒有á。我做錯了什麼,我正在使用你提到的確切項目,並將這兩個項目升級到4.0,他們仍然不會工作。 – syncis 2013-03-31 18:10:49

+0

是的,我認爲我現在有你的想法,非常好,我的朋友,非常好!我想實際上我可以用我的應用程序來完成這項工作,因爲我現在正在接受á。 – syncis 2013-03-31 18:22:22

5

但我已經注意到這個問題是在ToAsciii方法,不用的字符輸入正確。

這正是我想要猜測的。我很感謝你爲我做了修腳! :-)

問題是這些「特殊」字符是而不是 ASCII字符。也就是說,它們實際上是一些花式褲子的Unicode字符,它們不是ASCII字符集的一部分。

當您嘗試將它們轉換爲ASCII字符,功能想必做的最好是可以的,分解的代碼點組成á到單獨的字符´a

很明顯,這不是你想要的。您想將á視爲單個字符,因此您需要使用Unicode。這並不是一個真正的問題:至少在十年內,Windows在內部都是Unicode的。陳舊的ToAscii功能;相反,您需要使用MapVirtualKeyMapVirtualKeyEx將通過低級別鍵盤鉤子獲得的虛擬鍵碼轉換爲字符值。

+0

非常感謝您提供這些信息,但我有1個問題。還有一種類似於ToAsciii的方法,名爲ToUnicode,不能這麼做,或者我應該嘗試使用mapvirtualkey? – syncis 2013-03-18 23:38:02

+0

@syncis \t是的,你可能對'ToUnicode' /'ToUnicodeEx'有一些好運,但是這兩種方法仍然存在死鎖問題。一種可能的解決方法是在第一次通過時得到死鎖(返回值爲-1)的情況下再次調用它。相關閱讀:http://blogs.msdn.com/b/michkap/archive/2005/01/19/355870.aspx – 2013-03-18 23:41:27

+0

好吧讓我們嘗試第一種方法,通過調用它們兩次,我首先用ToAscii調用它,如果它返回-1,我再次調用它?試着現在,我沒有得到雙重字符,但我沒有得到「過了一個,我剛剛得到了一個,而不是á。也許mapvirtualkeyex解決了這個問題? – syncis 2013-03-18 23:49:08