输入特殊字符时,登录时在C#中的按键双显示字符 [英] Double characters shown when typing special characters while logging keystrokes in 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
andToUnicode
在的问题,你提到,你都试过
toascii将
和ToUnicode
,但没有成功。我还搜查一个问题是相对的:In the question, you mentioned about that you've tried both
ToAscii
andToUnicode
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 projectGma.UserActivityMonitor
, or just paste it at the rear ofHookManager.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将
来获得与ǹ一个相反的情况code>和
ǹ
,我甚至试过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
orToLower
to get a opposite case withǸ
andǹ
, I even triedToUpperInvariant
andToLowerInvariant
. Thus I choose to use a hard-coded sequence inAccentFormatter
, 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屋!
-