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.
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.
EDIT:
Trying with ToUnicode
instead.
[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 "";
}
}
Someone PLEASE help me, I really need to figure this out =/
.
EDIT:
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
);
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?
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 ...
The myth about
ToAscii
andToUnicode
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 in a keyboard hook destroys dead keys
I'm not saying any answer is right or wrong. However, we can think about:
A (not so) tricky game
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.
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.
How can one get one dollar bill from me without losing any coin?
Maybe a time-travelling ..
Base on [Processing Global Mouse and Keyboard Hooks in C#] on CodeProject
and my very old answer: Konami Code in C#
I did some modification for answering your question.
Code
First off, with the code downloaded from CodeProject, find
HookManager.Callbacks.cs
and delete the whole methodKeyboardHookProc
.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
.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.Input → Output
About the accent
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
àèìǹòùẁỳ`.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.Array arrangement of hexadecimal representation
In the code, I arranged the acute accent sequence as:
which is:
The
Ǽ
andǾ
are put at the rear becauseÆ
andØ
do not have a corresponding character in ASCII(non-extended).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.Send keys to the active application
If you want to send the key to the active application, then do the following change in the code:
change
to
Inside the conditional compilation block, the code fragment is
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.
That's exactly what I was about to guess. I appreciate you having done the legwork for me! :-)
The problem is that these "special" characters are not ASCII characters. That is, they're actually some type of fancy-pants Unicode characters that are not part of the ASCII character set.
When you try to convert them to ASCII characters, the function presumably does the best it can, decomposing the code points that make up
á
into the separate characters´
anda
.Obviously that's not what you want. You want to treat
á
as a single character, so you need to use Unicode. That's not really a problem: Windows has been all Unicode internally for at least a decade. Ditch the antiquatedToAscii
function; instead you'll want to use eitherMapVirtualKey
orMapVirtualKeyEx
to convert the virtual key code you're getting through the low-level keyboard hook into a character value.