2013-03-18 45 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