输入特殊字符时,同时记录在C#中的按键显示双字符(Double characters shown w

2019-07-21 21:36发布

我有一个应用程序,登录任何用户按下,但是当我按下特殊字符,如´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 ; 然后我按象a ,拿到á ,但后来我只得到a 。 同样的事情,如果我使用ToUnicode后对方两次,我得到的只是a而不是á ,等等...

Answer 1:

  • 关于神话ToAsciiToUnicode

    在这个问题,你提到,你都试过ToAsciiToUnicode没有成功。 我还搜查一个问题是相对的:

    在一个键盘钩子toascii将/ ToUnicode破坏死键

    我不是说任何的答案是对还是错。 不过,我们可以想一想:

    • A(没有的话)棘手的游戏

      在这个游戏中,我给玩家在同一时间随机翻转50美分的硬币。 人们可以挑战从我这里得到一个美元的钞票,如果谁收集的一对50个美分硬币有一个是头另一个是尾巴

      如果一个人放弃了挑战,那么谁可以保留有50%,而比赛重新开始。 如果谁试过,但没有收集两人见面的规则,然后我问回我那些我已经放弃。

      一个人怎么可以从我一分美元的钞票,而不会丢失任何硬币吗?

    也许时间旅行..


基地[ C#中处理全球鼠标和键盘钩子 ]在CodeProject

我很老的回答: 科乐美的代码在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,你可能要设置为高。

  • 输入→输出

  • 关于调

    正如我搜索有两种普遍的口音,他们是重音和重音符号 。
    急性口音的音调符号是´ ,和可能的字母áǽćéǵíḱĺḿńóǿṕŕśúẃýź
    重音的音调符号是`` , 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 

    这就是:

      AC  ÉǴ  ÍḰĹḾŃ  OPRS  ÚẂÝŹ  ǼǾ 

    ǼǾ在后方放入因为ÆØ没有在ASCII(非扩展)对应的字符。

    我更愿意保存ANSI代码与默认代码页,因为我有一个不同CultureInfo有不同于字母的语言。 你可能想改变他们精确字符的可读性。

  • 发送键来激活应用程序

    如果你想关键发送到活动的应用程序,然后执行的代码如下变化:

    更改

     #if false 

     #if !false 

    内的条件编译块,代码片段是

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

    它使用一个退格字符删除以前键入的`` or '`一旦它认定为特定的组合。 退格这里是时间机器..

这个演示后,我想你知道如何修改它们在你的代码合并。



Answer 2:

但我已经注意到这个问题是在ToAsciii方法,不用的字符键入正确。

这正是我正要猜测。 我很欣赏你已经做跑腿我! :-)

问题是,这些“特”字不是 ASCII字符。 也就是说,它们实际上是某种类型的花式裤子的Unicode不属于ASCII字符集的一部分的字符。

当您尝试将它们转换为ASCII字符,功能想必做的最好是可以的,分解的代码点组成á成单独的字符´a

显然,这不是你想要的。 你要正确对待á为单个字符,所以你需要使用Unicode。 这不是一个真正的问题:Windows已经被所有的Unicode内部至少十年。 沟陈旧ToAscii功能; 相反,你需要使用任何MapVirtualKeyMapVirtualKeyEx给你通过低级别的键盘钩子获取虚拟键代码转换为字符值。



文章来源: Double characters shown when typing special characters while logging keystrokes in c#