输入特殊字符时,登录时在C#中的按键双显示字符 [英] Double characters shown when typing special characters while logging keystrokes in c#

查看:414
本文介绍了输入特殊字符时,登录时在C#中的按键双显示字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,登录任何用户按下,但是当我按特殊字符,如 A ,要获得 A ,我得到''a ;当我想同样的事情 A ,然后我得到``一个,所以所有的特殊字符获取输入两次,那么常规字符后得到输入。

I have an application that logs whatever the user press, but when I press special characters like ´ with a, to get á, I get ´´a; same thing when I want to get à, then i get ``a, so all special characters get typed twice and then the regular character get typed after.

我已经寻找过,并不能真正发现任何东西。但是,我已经注意到这个问题是在 toascii将方法,不用的字符键入正确。

I have searched for ever and can't find anything really. But I have noticed that the problem is in the ToAscii method , without that the characters are typed correctly.

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 "";
    }
}



我缺少的东西,或做错了什么?所有其它字符都可以正常使用,但它是即将到来的双字符的特殊字符。

Am I missing something or doing something wrong? All other characters are working perfectly but it's the special characters that is coming as double chars.

编辑:

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



所以,现在我已经打过电话了 toascii将 ToUnicode 几次冲洗真正性质,但没有成功。我是不是做错了?

So now I have tried calling the ToAscii or ToUnicode a couple of times to flush the real character but without success. Am I doing it wrong?

喜欢ASCII,第一次调用 我得到 1 ,所以我再打电话吧,然后我得到 1 ;然后我按下如 A ,要获得 A ,但后来我只得到 A 。同样的事情,如果我用 ToUnicode 两次后对方,我得到的只是 A ,而不是 A ,等等...

Like for ASCII, first call for ´ I get -1, so I call it again, then I get 1; and then I press like a, to get á, but then I only get a. Same thing if I use ToUnicode twice after each other, I get just a instead of á, and so on ...

推荐答案


  • 关于 toascii将 ToUnicode

  • The myth about ToAscii and ToUnicode

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

    In the question, you mentioned about that you've tried both ToAscii and ToUnicode with no success. And I also searched a question which is relative:

    toascii将/在一个键盘钩子ToUnicode摧毁死键

    我并不是说任何答案是正确的或错误。但是,我们可以想一想:

    I'm not saying any answer is right or wrong. However, we can think about:


    • A(不那么)棘手的游戏

    • A (not so) tricky game

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

    In this game, I give the player a random flipped 50 cent coin at a time. One can challenge to get one dollar bill from me, if who collected a pair of 50 cent coins with one is a head and another is a tail.

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

    If one gave up to challenge, then who can reserve that 50 cent, and the game restarts. If who tried but did not collect two meet the rule, then I ask to return me those I've given.

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

    也许时间旅行..

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

    Base on [Processing Global Mouse and Keyboard Hooks in C#] on CodeProject

    和我很老的回答:的小浪代码在C#

    我做了一些修改为您解答题。

    I did some modification for answering your question.


    • 代码

    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 的后面。

    Then You can save the code above in a new file such like HookManager.Modified.cs and add it in project Gma.UserActivityMonitor, or just paste it at the rear of HookManager.Callbacks.cs.

    记住要设置 Gma.UserActivityMonitorDemo 启动项目。它的目标框架设置为2.0,而你可能需要设置到一个更高的。

    Remember to set Gma.UserActivityMonitorDemo as startup project. It was set target framework to 2.0, and you might want to set to a higher.

    输入和RARR;输出

    关于口音

    当我搜索有2种一般的口音,他们是重音并的重音符号

    急性口音的音调符号是 ,和可能的字母áǽćéǵíḱĺḿńóǿṕŕśúẃýź

    重音的音调符号是`,和可能的字母àèìǹòùẁỳ

    As I searched there are two kind of general accent, they are grave accent and acute accent.
    The diacritic of acute accent is ´, and the possible letters are áǽćéǵíḱĺḿńóǿṕŕśúẃýź.
    The diacritic of grave accent is `, and the possible letters are àèìǹòùẁỳ.

    他们两人都是以大写或小写可能的,但我没有找到与他们很容易的工作方式在课堂框架那些内置。例如,我不能使用 ToUpper的 ToLower将来获得与ǹǹ,我甚至试过 ToUpperInvariant ToLowerInvariant 。因此,我选择使用 AccentFormatter 硬编码的序列,并可能将其更改为从文件中读取,或实施其他自定义格式化你自己。

    Both of them are possible in upper case or lower case, but I did not find an easy enough way works with them in classes those are built-in of the framework. For example, I cannot use ToUpper or ToLower to get a opposite case with Ǹ and ǹ, I even tried ToUpperInvariant and ToLowerInvariant. Thus I choose to use a hard-coded sequence in AccentFormatter, and you may change it to reading from files, or implement another custom formatter yourself.

    十六进制表示的阵列排列

    在代码中,我安排锐音符序列为:

    In the code, I arranged the acute accent sequence as:

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

    这就是:

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



    ǼǾ后部放在因为Æ 0 没有以ASCII对应的字符(非扩展)。

    The Ǽ and Ǿ are put at the rear because Æ and Ø do not have a corresponding character in ASCII(non-extended).

    我更喜欢保存在ANSI代码使用默认的代码页,因为我有一个不同的的CultureInfo 从语言是在字母表。你可能想改变他们精确字符的可读性。

    I preferred to save the code in ANSI with a default code page, since I have a different CultureInfo from the languages which is in alphabet. And you might want to change them to exact characters for readability.

    发送键来激活应用程序

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

    If you want to send the key to the active application, then do the following change in the code:

    改变

    #if false
    

    #if !false
    

    里面的条件编译模块,代码片段

    Inside the conditional compilation block, the code fragment is

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



    本机采用退格字符删除以前的类型化 ` 一旦它认定为特定的组合。这里退格键是时间机器。

    It use a backspace character to erase the previous typed ` or ´ once it recognized as a specific combination. Backspace here is the time machine ..

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

    After this demo, I guess you'll know how to modify them to merge in your code.

    这篇关于输入特殊字符时,登录时在C#中的按键双显示字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆