C++/VB - SendInput and Unicode
Asked By Karl E. Peterson on 29-Jan-09 02:23 PM
Is there anyone out there who wants to use Unicode characters with the SendInput
function? I had someone ask me recently if I could update my SendKeys replacement
sample (http://vb.mvps.org/samples/SendInput) such that they could also send Unicode
characters with it. I tweaked it a bit, and she reported it was now working for
her, but I'm not sure it was a most-representative user doing the testing. I have
no need (or interest) in using that functionality myself, so I'm not sure if my
assumptions were good for others. Anyone wanna have a crack at it?
--
.NET: It's About Trust!
http://vfred.mvps.org
expvb replied on 29-Jan-09 05:15 PM
The sample is unchanged since I downloaded it about 2 months ago(no binary
differences).
Karl E. Peterson replied on 29-Jan-09 05:46 PM
Sorry! I should've been more clear. I was seeking input *before* uploading for
all. <g>
Here's the updated code: http://vb.mvps.org/samples/raw/MSendInput.bas.txt
(Note to Archive: Not sure that'll stay there, after this thread dies down.)
--
.NET: It's About Trust!
http://vfred.mvps.org
Karl E. Peterson replied on 29-Jan-09 05:52 PM
Key points I'm wondering about are,
1) Is a simple 0-255 check sufficient recognition for "Unicode" characters, where
the input variable 'this' is a single character from a longer string?
Private Sub ProcessChar(this As String)
Dim code As Integer
Dim vk As Integer
Dim capped As Boolean
' Determine whether we need to treat as Unicode.
code = AscW(this)
If code >= 0 And code < 256 Then 'ascii
' Add input events for single character, taking capitalization
' into account. HiByte will contain the shift state, and LoByte
' will contain the key code.
vk = VkKeyScan(Asc(this))
capped = CBool(ByteHi(vk) And 1)
vk = ByteLo(vk)
Call StuffBuffer(vk, capped)
Else 'unicode
Call StuffBufferW(code)
End If
End Sub
2) If it's Unicode, that means we skip all the Shiftkey processing, and instead just
do this, right?
Private Sub StuffBufferW(ByVal CharCode As Integer)
' Unicode is relatively simple, in this context?!
' Press and release this key.
With m_Events(m_EvtPtr)
.wVK = 0
.wScan = CharCode
.dwFlags = KEYEVENTF_UNICODE
End With
m_EvtPtr = m_EvtPtr + 1
With m_Events(m_EvtPtr)
.wVK = 0
.wScan = CharCode
.dwFlags = KEYEVENTF_UNICODE Or KEYEVENTF_KEYUP
End With
m_EvtPtr = m_EvtPtr + 1
End Sub
3) What else I've overlooked? <g>
Thanks... Karl
--
.NET: It's About Trust!
http://vfred.mvps.org
expvb replied on 29-Jan-09 07:09 PM
I am by no means an expert in this area, but here is what I know. Char codes
from 128 to 255 have special meaning, depending on whether you are using
ANSI or Unicode. In Unicode, their meaning is fixed regardless of Code Page.
They refer to Latin-1 Supplement, so for instance char code 169 is always
the copyright symbol.
In ANSI, char codes from 128 to 255 have no meaning without the associated
Code Page. So when someone says char code 169 is the copyright symbol, he or
she is wrong. They must also say what Code Page they are talking about.
So you have to add a Unicode flag to treat char codes 128 to 255 properly.
See these articles:
http://en.wikipedia.org/wiki/Basic_Multilingual_Plane
http://en.wikipedia.org/wiki/Unicode
It seems so. It seems that in order to get keyboard scan codes, keyboard
layout and support for specific code pages has to be loaded(In the Control
Panel perhaps), so it doesn't seem possible to get scan codes for every
possible Unicode char. You can however send a Unicode char by sending
WM_CHAR using the W version of SendMessage after checking that the window is
a Unicode window by calling IsWindowUnicode().
Checking that the OS is Windows 2000 before using KEYEVENTF_UNICODE flag,
and that the minimum required OS is Windows 98 because that is when
SendInput() was introduced.
Karl E. Peterson replied on 29-Jan-09 08:46 PM
Ouch! Okay, I'll have a look at those. (I'm in the middle of some lengthy installs
at the moment, and they don't like an open browser. <groan>)
I wonder if it really matters from a SendKeys perspective, though? I mean, if you
sent a "©" to Sendkeys, it'd just use whatever codepage was in effect, no?
Shouldn't a drop-in SendKeys replacement do the same thing? (Semi-rhetorical,
granted.)
I guess I need to read those pages you cited. Thinking ahead, are you suggesting I
possibly just slip the test down to do the unicode processing for anything >= 128?
I like that response. :-)
Not sure I'm following there?
Excellent catch(es)! Would be wise to add something like that, but I think it'd
just fail silently (except on Win95) without it, right?
Thanks much... Karl
--
.NET: It's About Trust!
http://vfred.mvps.org
expvb replied on 29-Jan-09 10:36 PM
You can always consider anything < 256 to be ANSI, which what VB's SendKeys
does. If someone wants to send Unicode characters in the range 128 to 255,
then they can change the source code by themselves.
I was saying that it's not always possible to get scan codes for every
character. After checking the documentation, when you use KEYEVENTF_UNICODE,
Windows sends VK_PACKET, which later translates to WM_CHAR and converted to
ANSI if the window is ANSI, so there is nothing special you need to do.
However, it seems that in certain situations the Unicode character is
discarded. Use the Search tab in MSDN and type "VK_PACKET" (5 results), or
You can call VB's SendKeys in Windows 9x.
Thorsten Albers replied on 30-Jan-09 07:51 AM
Karl E. Peterson <karl@mvps.org> schrieb im Beitrag
characters, where
Yes, unless you want to deal with codepage pecularities since Unicode
character codes 128 to 255 encode always the same characters while ANSI
character code 128 to 255 are codepage dependent.
Easier and presumably faster:
If Not CBool(code And &HFF00) Then
Maybe you should check for some Unicode characters and prevent them from
beeing sent, like the
- High surrogates
D800h to DBFFh
- Low surrogates
DC00h to DFFFh
- Specials
FFF0h to FFFFh
It can't be excluded that sending one of these to a process may cause
trouble...
--
Thorsten Albers
albers (a) uni-freiburg.de
Thorsten Albers replied on 30-Jan-09 07:56 AM
Karl E. Peterson <karl@mvps.org> schrieb im Beitrag
mean, if you
no?
(Semi-rhetorical,
I wouldn't bother about codepage issues: You are providing an ANSI and a
Unicode version of your procedure. The ANSI procedures always sends ANSI
characters, the Unicode procedure always sends Unicode characters (even for
0-255). It's up to the developer which of the two procedures he has to
call.
--
Thorsten Albers
albers (a) uni-freiburg.de
mark.tunnard.jackso replied on 01-Feb-09 02:34 AM
I agree with Thorsten. And I don't think checking AscW<255 is going to
work anyway. For instance, on code page 1252 (English & Western
Europe), ANSI character 0x83 is Unicode character 0x0192 ("#LATIN
SMALL LETTER F WITH HOOK")
? ascw(chr$(&H83&)), asc(chr$(&H83&))
402 131
Unicode character 0x0083 is a non-breaking hyphen.
The point is that "ANSI" character code 128-255 will map to a
different set of Unicode characters depending on the code page. I'm
not sure how best to test whether a character is supported on the
current code page. Maybe convert Unicode->"ANSI"->Unicode and see if
the string is unchanged?
Tim Oppmann replied on 30-Jan-09 07:14 PM
I am interested, but I do not have much experience in this area.
Karl E. Peterson replied on 02-Feb-09 08:13 PM
Very good point. :-)
And the very goal of that project was to replace/replicate SendKeys.
Okay, will take a look.
Heh, there's a snarky workaround, alright! <bg>
--
.NET: It's About Trust!
http://vfred.mvps.org
Karl E. Peterson replied on 02-Feb-09 08:16 PM
Hmmmm, that's not what that code was doing, though. Rather, it was just processing
the passed string, one character at a time, and then stuffing a SendInput buffer
based on what was found. If the character was >=256, it would stuff it with a
Unicode character. If it was 0-255, it'd use the normal ANSI procedures, taking
into account things like Shift states and such.
--
.NET: It's About Trust!
http://vfred.mvps.org
Karl E. Peterson replied on 02-Feb-09 08:18 PM
Yikes! That's getting real ugly real fast.
Another thought would be to offer a new escape character, much like VB provides
escapes for the three common shift keys?
--
.NET: It's About Trust!
http://vfred.mvps.org
Karl E. Peterson replied on 02-Feb-09 08:21 PM
What's scary is Mark's example:
? ascw(chr$(&H83&)), asc(chr$(&H83&))
402 131
I guess it'll still work, though? I mean, so I get 402 instead of 131, all that
means is I'm ignoring the Shift escapes and pushing a Unicode character into the
buffer, eh?
Was gonna make sure the test was valid first, of course. He said. Heh... <g>
Yep!
First I've ever heard of them! Remember, I'm USian, and therefore *highly*
unicode-impaired. :-/
--
.NET: It's About Trust!
http://vfred.mvps.org
expvb replied on 02-Feb-09 08:53 PM
After some more reading, it seems that MS introduced a way to insert
characters without having to have a keyboard scan code by adding
KEYEVENTF_UNICODE. This was probably done to support writing
pads(handwriting recognition pads). In these pads there are no keys, so
there are no scan codes. KEYEVENTF_UNICODE/VK_PACKET was introduced for this
purpose, but since "IME_PROP_ACCEPT_WIDE_VKEY" flag can affect how VK_PACKET
is processed, you can avoid VK_PACKET and send the Unicode character by
using SendUnicodeChar() function below. Windows would automatically convert
the Unicode character to ANSI if the target window is ANSI(See WM_CHAR in
MSDN for details). Note that I am using the W version of SendMessage.
Option Explicit
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" ( _
ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, _
lParam As Any) As Long
Private Declare Function SendMessageW Lib "user32" (ByVal hWnd As Long, _
ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Const WM_CHAR = &H102
Private Const WM_UNICHAR = &H109
' Windows 2000+ Only
Public Function SendUnicodeChar(ByVal hWnd As Long, _
ByVal lKey As Long) As Long
SendUnicodeChar = SendMessageW(hWnd, WM_CHAR, lKey, ByVal 1&)
End Function
Karl E. Peterson replied on 02-Feb-09 09:22 PM
That's what I'm doing!
That would prevent the mixing of character sets (to allow for stuff like navigation
keys, etc), that I was trying to support. So the question is, what advantage does
that confer over stuffing the SendInput buffer with the Unicode character?
' http://vb.mvps.org/samples/raw/MSendInput.bas.txt
Private Sub StuffBufferW(ByVal CharCode As Integer)
' Unicode is relatively simple, in this context?!
' Press and release this key.
With m_Events(m_EvtPtr)
.wVK = 0
.wScan = CharCode
.dwFlags = KEYEVENTF_UNICODE
End With
m_EvtPtr = m_EvtPtr + 1
With m_Events(m_EvtPtr)
.wVK = 0
.wScan = CharCode
.dwFlags = KEYEVENTF_UNICODE Or KEYEVENTF_KEYUP
End With
m_EvtPtr = m_EvtPtr + 1
End Sub
--
.NET: It's About Trust!
http://vfred.mvps.org
Thorsten Albers replied on 03-Feb-09 07:42 AM
Karl E. Peterson <karl@mvps.org> schrieb im Beitrag
processing
buffer
with a
taking
IMHO a procedure supporting Unicode should be a Unicode-only procedure.
Otherwise the result may differ from what was expected. E.g.
A) Sending character code 00C4h as Unicode
1. Receiving application does support Unicode
Application works with character code 00C4h and shows up the glyph 'A with
diaeresis above'.
That's o.k.
2. Receiving application does not support Unicode
Application works with character code C4h and shows up the glyph which in
the application's/user's/system's current ANSI codepage is encoded with
character code C4h (Western: 'A with diaresis above'; Greek: 'Delta';
Cyrillic: 'De', etc.)
That's o.k.
B) Sending character code C4h as ANSI
1. Receiving application does support Unicode
Application converts the character code from ANSI to Unicode according to
the application's/user's/system's current ANSI codepage which may be 00C4h
(Latin 'A with diaeresis above'), 0394h (Greek 'Delta'), 0414h (Cyrillic
'De'), etc.
This doesn't make much sense and presumably is not what the user of the
procedure expects!!
2. Receiving application does not support Unicode
S. A.2.
If at all, using ANSI instead of Unicode in your procedure would make sense
only if restricted to >>ASCII<< character codes (000-127) because they are
the same in any ASCII and ANSI codepage as well as in Unicode. Therefore:
If (code And &HFF80) Then
' Unicode
Else
' ANSI
End If
--
Thorsten Albers
albers (a) uni-freiburg.de
Thorsten Albers replied on 03-Feb-09 07:51 AM
Karl E. Peterson <karl@mvps.org> schrieb im Beitrag
*highly*
We all hope that this will change under a coloured president with a semitic
name who came from Indonesia... (feel free to replace 'coloured' by
whatever currently is the political correct word in the USA)
--
Thorsten Albers
albers (a) uni-freiburg.de
Karl E. Peterson replied on 03-Feb-09 01:48 PM
Hi Thorsten --
This is why I asked here. I'd hoped to find folks far more familiar with these
sorts of issues than I am. My first inclination was indeed to simply offer a
distinct 'W' version of the call, and leave it at that. Then, it looked "so easy!"
to get tricky and fold it all into one, that I wondered what I must be missing. Too
good to be true? Yeah, sounds like it, given what you're telling me.
So, assuming I were to create another parallel routine that's specifically intended
for Unicode... Would it also matter to the users of this routine that it support
the navigation keys as well? Or would it be sufficient to let them do navkeys with
the standard routine, then send Unicode chars with the dedicated routine?
Thanks... Karl
--
.NET: It's About Trust!
http://vfred.mvps.org
Karl E. Peterson replied on 03-Feb-09 01:49 PM
We all have a *lot* of hopes these days!
I am personally very ready for change myself! :-)
--
.NET: it is About Trust!
http://vfred.mvps.org
expvb replied on 03-Feb-09 02:10 PM
The way you are doing it is the preferable way. You don't even need to worry
about ANSI<->Unicode conversion because you are using KEYEVENTF_UNICODE.
However, a while ago someone posted in a thread titled "user32.dll function
fails without any error. I am afraid it kills my business." that
KEYEVENTF_UNICODE does not work. My guess is that is due to
In these cases sending WM_CHAR directly could solve that problem, but it
would introduce other complications because the sender need to synchronize
when the characters or control keys need to be inserted(The calls to
SendInput and SendMessageW must not interfere with each other). But this
issue seems less likely and you don't need to worry about it. If someone
says to you it doesn't work, tell them to lookup "IME_PROP_ACCEPT_WIDE_VKEY"
flag.
Karl E. Peterson replied on 03-Feb-09 02:31 PM
Heh, wow... So, there doesn't appear to be a corresponding ImmSetProperty call,
does there? <g>
I think I oughta link to this thread from the source!
Thanks... Karl
--
.NET: It's About Trust!
http://vfred.mvps.org
Thorsten Albers replied on 03-Feb-09 07:08 PM
Karl E. Peterson <karl@mvps.org> schrieb im Beitrag
specifically intended
support
navkeys with
I would use Unicode only for characters (and, of course, Unicode specific
control codes). All keys not producing a character I would send as ANSI and
with their virtual VK_* key codes.
--
Thorsten Albers
albers (a) uni-freiburg.de
Karl E. Peterson replied on 03-Feb-09 07:19 PM
Unicode specific control codes? (Victim of my nationality... <sigh>)
What's the test?
--
.NET: it is About Trust!
http://vfred.mvps.org
expvb replied on 03-Feb-09 07:37 PM
For SendKeys' special keys like {F1} and everything that is specified by {}
and Shift/Alt/Ctrl, use the vbKeyXXX equivalent. For anything else, use
KEYEVENTF_UNICODE.
Karl E. Peterson replied on 03-Feb-09 08:11 PM
Okay, think I'm following. So, continue to watch for the shift key escapes?
They're only useful with the navigation keys, right? No way to flag those with
Unicode characters. Thanks!
--
.NET: It's About Trust!
http://vfred.mvps.org
expvb replied on 03-Feb-09 09:09 PM
http://rawstory.com/news/2008/Fall_from_power_Rumsfeld_relegated_to_0202.html
Karl E. Peterson replied on 03-Feb-09 09:16 PM
OMG! "... tried to ride a bus last week but failed, ..." ROTFLMAO!!! :-D
--
.NET: it is About Trust!
http://vfred.mvps.org
Thorsten Albers replied on 03-Feb-09 09:51 PM
Karl E. Peterson <karl@mvps.org> schrieb im Beitrag
Unicode defines some, e.g. for right-to-left text processing.
--
Thorsten Albers
albers (a) uni-freiburg.de
Thorsten Albers replied on 03-Feb-09 09:55 PM
expvb <nobody@cox.net> schrieb im Beitrag
http://rawstory.com/news/2008/Fall_from_power_Rumsfeld_relegated_to_0202.htm
l
The "we" in "yes, we can!" obviously has to be modified a bit. Some can not
- even if they try...
--
Thorsten Albers
albers (a) uni-freiburg.de
Karl E. Peterson replied on 04-Feb-09 02:16 PM
Ugh... This may end up being an "exercise left for the reader."
--
.NET: it is About Trust!
http://vfred.mvps.org
Ton replied on 21-Feb-09 02:04 AM
Does anyone know why apps running in a DOS window will ignore SendInput with
KEYEVENTF_UNICODE?
I can send chars to the DOS prompt, but if I start "edit", all chars are
ignored.
Thanks for any help,
Tony
Thorsten Albers replied on 21-Feb-09 07:33 AM
Tony <Tony@> schrieb im Beitrag
with
Before sending the key input to a window check by a call to
IsWindowUnicode(), if the window is Unicode enabled at all. If it is not,
it will not handle Unicode input and messages in any case. If it is, it
might be possible that it supports Unicode input and messages.
--
Thorsten Albers
albers (a) uni-freiburg.de
Ton replied on 21-Feb-09 07:01 PM
Thanks for the quick reply.
The window in question is the Command Prompt on XP. It does return TRUE to
IsWindowUnicode, and it works fine. The problem is launching an app within
the Command Prompt window, like "edit".
Once "edit" is running, all keystrokes are ignored.
Does anyone know why?
Thorsten Albers replied on 22-Feb-09 08:04 AM
to
within
Presumably because 'Edit' is not Unicode-enabled? Try to load a Unicode
text in edit and see what happens.
--
Thorsten Albers
albers (a) uni-freiburg.de