CGEventPost - possible bug when simulating keyboard events? - macos

I have a very simple chunk of code that is designed to simulate keyboard events. The simple example below should type "Cz" - the shift key goes down, the c key goes down, c comes up and shift comes up. Then the z key goes down and up.
It seems that sometimes the order gets muddled though. When I create a timer to call this routine every second, the output should be CzCzCzCz.... But here's what I get:
CZcZCZCzczCzczCzczCZCZCzCz
I'll run it again:
CzCzCzCzCZCzCZCzCZCzCZCzCZCzCzCz
Different. And equally wrong.
The code:
e1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, true);
CGEventPost(kCGSessionEventTap, e1);
CFRelease(e1);
e2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, true);
CGEventPost(kCGSessionEventTap, e2);
CFRelease(e2);
e3 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)8, false);
CGEventPost(kCGSessionEventTap, e3);
CFRelease(e3);
e4 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, e4);
CFRelease(e4);
e7 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true);
CGEventPost(kCGSessionEventTap, e7);
CFRelease(e7);
e8 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false);
CGEventPost(kCGSessionEventTap, e8);
CFRelease(e8);
Is there something I'm missing in how to implement the keydown and keyup for the shift key? I think this might be a bug - where would I report it?

I have found a reliable way to post modified keyboard events - it does not follow the example in Apple's documentation (which doesn't work) but seems to make sense, and most importantly, WORKS.
Rather than sending 'shift key down' and 'shift key up' messages (as instructed in the docs), you need to set a modifier flag on the keypress. Here's how to output an uppercase Z.
CGEventRef event1, event2;
event1 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, true);//'z' keydown event
CGEventSetFlags(event1, kCGEventFlagMaskShift);//set shift key down for above event
CGEventPost(kCGSessionEventTap, event1);//post event
I'm then releasing the 'z' key for completeness (also setting the shift-flag on, though not sure if this is correct).
event2 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)6, false);
CGEventSetFlags(event2, kCGEventFlagMaskShift);
CGEventPost(kCGSessionEventTap, event2);
Finally (and bizarrely) you DO need to send the 'key up' event for the shift key:
e5 = CGEventCreateKeyboardEvent(NULL, (CGKeyCode)56, false);
CGEventPost(kCGSessionEventTap, e5);
Don't forget to release your events once you're done with them.
I hope this is useful to someone - it took me a long time to get this to work.

The cleanest way for this is bitwise OR'ing the current modifier flags with the flag of your desired modifier(s) , e.g.:
CGEventFlags flags = kCGEventFlagMaskShift;
CGEventRef ev;
CGEventSourceRef source = CGEventSourceCreate (kCGEventSourceStateCombinedSessionState);
//press down
ev = CGEventCreateKeyboardEvent (source, keyCode, true);
CGEventSetFlags(ev,flags | CGEventGetFlags(ev)); //combine flags
CGEventPost(kCGHIDEventTap,ev);
CFRelease(ev);
//press up
ev = CGEventCreateKeyboardEvent (source, keyCode, false);
CGEventSetFlags(ev,flags | CGEventGetFlags(ev)); //combine flags
CGEventPost(kCGHIDEventTap,ev);
CFRelease(ev);
CFRelease(source);

Like another comment referring to other solutions here, after using uppercase with the Shift mask, a successive call would cause any further intended non-shifted character to be turned into an shifted characters. I figured the call to CGEventCreateKeyboardEvent was somehow saving previous masks, so I purposefully clear the mask of the modifier:
CGEventRef event1, event2;
CGEventSourceRef source = CGEventSourceCreate (kCGEventSourceStateCombinedSessionState);
CGEventFlags flags;
event1 = CGEventCreateKeyboardEvent (source, keyCode, true);
if (upper)
flags = kCGEventFlagMaskShift | CGEventGetFlags(event1);
else
flags = ~kCGEventFlagMaskShift & CGEventGetFlags(event1);
CGEventSetFlags(event1, flags);
CGEventPost(kCGHIDEventTap,event1);
event2 = CGEventCreateKeyboardEvent (source, keyCode, false);
if (upper)
flags = kCGEventFlagMaskShift | CGEventGetFlags(event2);
else
flags = ~kCGEventFlagMaskShift & CGEventGetFlags(event2);
CGEventSetFlags(event2, flags);
CGEventPost(kCGHIDEventTap,event2);
CFRelease(event1);
CFRelease(event2);
CFRelease(source);

I had a similar problem recently. Instead of passing NULL as the first argument of CGEventCreateKeyboardEvent, create an event source like this:
CGEventSourceRef eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
and use it while you are creating and posting events. CFRelease it when you are done with it.

Any relation to this guy's bug?

reliable workaround:
+(void)runScript:(NSString*)scriptText
{
NSDictionary *error = nil;
NSAppleEventDescriptor *appleEventDescriptor;
NSAppleScript *appleScript;
appleScript = [[NSAppleScript alloc] initWithSource:scriptText];
appleEventDescriptor = [appleScript executeAndReturnError:&error];
}
[self runScript:#"tell application \"System Events\" to key code "c" using shift down"];
[self runScript:#"tell application \"System Events\" to key code "z"];

Related

Icon added to notification tray disappears on mouse over

I want my application to have an icon in the notification area in Windows 7. I used Shell_NotifyIcon to add the icon. The icon appears, but when I bring the mouse pointer over the icon, the icon disappears. The application is running the whole time. The icon isn't hidden, it just disappears.
Shell_NotifyIcon returns a non-zero value, which means it succeeds.
Here's the relevant code:
static const int ID_TRAYICON = 300;
static const int MSG_TRAYICON = WM_USER + 1;
NOTIFYICONDATA nid;
void InitTrayIconData()
{
memset(&nid, 0, sizeof(NOTIFYICONDATA));
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = ID_TRAYICON;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = MSG_TRAYICON;
nid.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
//nid.uVersion = NOTIFYICON_VERSION_4;
lstrcpy(nid.szTip, TEXT("Data Aggregator in-dev version"));
}
Then while processing the WM_CREATE message:
InitTrayIconData();
Shell_NotifyIcon(NIM_ADD, &nid);
And while processing WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nid);
I've also noticed that for some reason the MSG_TRAYICON message is never called.
I figured it out. When I called InitTrayIconData() in WM_CREATE, the global hwnd hadn't been assigned the value returned from CreateWindowEx yet (the WM_CREATE message wasn't sent after the CreateWindowEx call, but during it, which I didn't know). So the line,
nid.hWnd = hwnd;
just equated nid.hWnd to nullptr (which is what I had initialized hwnd to).
I fixed the problem by passing the hwnd argument in WndProc to the InitTrayIconData(), so it would use that hwnd instead of the global hwnd.
This happens when the system can't communicate with the application that owns the notification icon.
Normally this is because the process has terminated abnormally. In your case you state that the process is running the whole time. Thus I can only conclude that the window handle associated with the notification icon has been destroyed, or is not responding to messages correctly. That diagnosis also tallies with your observation that you do not receive MSG_TRAYICON.

How to create virtual keyboard in osx?

I want to create a virtual keyboard in osx. Is it possible? I mean can I make a program that gives same signals than real keyboard. Example of this kind of keyboard would be onscreen keyboard, or keybord viewer (does it have necessary interface btw).
How low should I start? Should I make a device driver e.g. virtual (wireless) keyboard? Or does cocoa etc. have the necessary stuff?
The requirements I have are:
- a list of tuples (time, key_down/key_up, key_code) corresponds to person typing
- virtual keyboard should work side by side with the real one (like touchpad and bluetooh mouse)
- this should work with every program. Hardest examples I can find are: Terminal+vim, remote desktop, games like starcraft
Sample code and links are more than welcome.
edit: The main point is to have programmatic access to keystrokes. There are similar programs but they are with closed source (e.g. http://www.assistiveware.com/keystrokes.php). I want to know what is the best way to make this kind of program.
edit 2: Now I got this party started. Below is a copy-edit-paste-try-something-else code that basically includes all necessary parts to make a virtual keyboard. In this case, every time I press 'a' the virtual keyboard presses 'z'. There is a bug, that there is multiple 'z's added...
#import <ApplicationServices/ApplicationServices.h>
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
UniChar unicodeString[101];
UniCharCount unicharCount;
char chars[2];
int i,j,charsLen;
CGEventRef zDown;
CGEventRef zUp;
zDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, true);
zUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)6, false);
//printf("%u %u\n", (uint32_t)type, (uint32_t) event);
CGEventKeyboardGetUnicodeString(event, 100, &unicharCount, unicodeString);
for (i=0; i < unicharCount; i++)
{
if (unicodeString[i] > 127) {
chars[0] = (unicodeString[i] >> 8) & (1 << 8) - 1;
chars[1] = unicodeString[i] & (1 << 8) - 1;
charsLen = 2;
} else {
charsLen = 1;
chars[0] = unicodeString[i];
}
//for (j = 0; j < charsLen; j++) printf("%c", chars[j]);
}
if (chars[0] == 'a')
{
CGEventPost(kCGHIDEventTap, zDown);
CGEventPost(kCGHIDEventTap, zUp);
}
return event;
}
int main (int argc, const char * argv[]) {
CFMachPortRef eventTap;
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, myCGEventCallback, NULL);
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
return 0;
}
br,
Juha
You could do this using Quartz Event Taps, which provides a:
...C API for event taps, which are
filters used to observe and alter the
stream of low-level user input events
in Mac OS X
On the Mac, there is the keyboard view. Why can't you use that?

ToAscii/ToUnicode in a keyboard hook destroys dead keys

It seems that if you call ToAscii() or ToUnicode() while in a global WH_KEYBOARD_LL hook, and a dead-key is pressed, it will be 'destroyed'.
For example, say you've configured your input language in Windows as Spanish, and you want to type an accented letter á in a program. Normally, you'd press the single-quote key (the dead key), then the letter "a", and then on the screen an accented á would be displayed, as expected.
But this doesn't work if you call ToAscii() or ToUnicode() in a low-level keyboard hook function. It seems that the dead key is destroyed, and so no accented letter á shows up on screen. Removing a call to the above functions resolves the issue... but unfortunately, I need to be able to call those functions.
I Googled for a while, and while a lot of people seemed to have this issue, no good solution was provided.
Any help would be much appreciated!
EDIT: I'm calling ToAscii() to convert the virtual-key code and scan code received in my LowLevelKeyboardProc hook function into the resulting character that will be displayed on screen for the user.
I tried MapVirtualKey(kbHookData->vkCode, 2), but this isn't as "complete" a function as ToAscii(); for example, if you press Shift + 2, you'll get '2', not '#' (or whatever Shift + 2 will produce for the user's keyboard layout/language).
ToAscii() is perfect... until a dead-key is pressed.
EDIT2: Here's the hook function, with irrelevant info removed:
LRESULT CALLBACK keyboard_LL_hook_func(int code, WPARAM wParam, LPARAM lParam) {
LPKBDLLHOOKSTRUCT kbHookData = (LPKBDLLHOOKSTRUCT)lParam;
BYTE keyboard_state[256];
if (code < 0) {
return CallNextHookEx(keyHook, code, wParam, lParam);
}
WORD wCharacter = 0;
GetKeyboardState(&keyboard_state);
int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode,
keyboard_state, &wCharacter, 0);
/* If ta == -1, a dead-key was pressed. The dead-key will be "destroyed"
* and you'll no longer be able to create any accented characters. Remove
* the call to ToAscii() above, and you can then create accented characters. */
return CallNextHookEx(keyHook, code, wParam, lParam);
}
Quite an old thread. Unfortunately it didn't contain the answer I was looking for and none of the answers seemed to work properly. I finally solved the problem by checking the MSB of the MapVirtualKey function, before calling ToUnicode / ToAscii. Seems to be working like a charm:
if(!(MapVirtualKey(kbHookData->vkCode, MAPVK_VK_TO_CHAR)>>(sizeof(UINT)*8-1) & 1)) {
ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode,
keyboard_state, &wCharacter, 0);
}
Quoting MSDN on the return value of MapVirtualKey, if MAPVK_VK_TO_CHAR is used:
[...] Dead keys (diacritics) are indicated by setting the top bit of the return value. [...]
stop using ToAscii() and use ToUncode()
remember that ToUnicode may return you nothing on dead keys - this is why they are called dead keys.
Any key will have a scancode or a virtual key code but not necessary a character.
You shouldn't combine the buttons with characters - assuming that any key/button has a text representation (Unicode) is wrong.
So:
for input text use the characters reported by Windows
for checking button pressed (ex. games) use scancodes or virtual keys (probably virtual keys are better).
for keyboard shortcuts use virtual key codes.
Call 'ToAscii' function twice for a correct processing of dead-key, like in:
int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode,
keyboard_state, &wCharacter, 0);
int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode,
keyboard_state, &wCharacter, 0);
If (ta == -1)
...
Calling the ToAscii or ToUnicode twice is the answer.
I found this and converted it for Delphi, and it works!
cnt:=ToUnicode(VirtualKey, KeyStroke, KeyState, chars, 2, 0);
cnt:=ToUnicode(VirtualKey, KeyStroke, KeyState, chars, 2, 0); //yes call it twice
I encountered this issue while creating a key logger in C# and none of the above answers worked for me.
After a deep blog searching, I stumbled across this keyboard listener which handles dead keys perfectly.
Here is a full code which covers dead keys and shortcut keys using ALT + NUMPAD, basically a full implementation of a TextField input handling:
[DllImport("user32.dll")]
public static extern int ToUnicode(uint virtualKeyCode, uint scanCode, byte[] keyboardState, [Out, MarshalAs(UnmanagedType.LPWStr, SizeConst = 64)] StringBuilder receivingBuffer, int bufferSize, uint flags);
private StringBuilder _pressCharBuffer = new StringBuilder(256);
private byte[] _pressCharKeyboardState = new byte[256];
public bool PreFilterMessage(ref Message m)
{
var handled = false;
if (m.Msg == 0x0100 || m.Msg == 0x0102)
{
bool isShiftPressed = (ModifierKeys & Keys.Shift) != 0;
bool isControlPressed = (ModifierKeys & Keys.Control) != 0;
bool isAltPressed = (ModifierKeys & Keys.Alt) != 0;
bool isAltGrPressed = (ModifierKeys & Keys.RMenu) != 0;
for (int i = 0; i < 256; i++)
_pressCharKeyboardState[i] = 0;
if (isShiftPressed)
_pressCharKeyboardState[(int)Keys.ShiftKey] = 0xff;
if (isAltGrPressed)
{
_pressCharKeyboardState[(int)Keys.ControlKey] = 0xff;
_pressCharKeyboardState[(int)Keys.Menu] = 0xff;
}
if (Control.IsKeyLocked(Keys.CapsLock))
_pressCharKeyboardState[(int)Keys.CapsLock] = 0xff;
Char chr = (Char)0;
int ret = ToUnicode((uint)m.WParam.ToInt32(), 0, _pressCharKeyboardState, _pressCharBuffer, 256, 0);
if (ret == 0)
chr = Char.ConvertFromUtf32(m.WParam.ToInt32())[0];
if (ret == -1)
ToUnicode((uint)m.WParam.ToInt32(), 0, _pressCharKeyboardState, _pressCharBuffer, 256, 0);
else if (_pressCharBuffer.Length > 0)
chr = _pressCharBuffer[0];
if (m.Msg == 0x0102 && Char.IsWhiteSpace(chr))
chr = (Char)0;
if (ret >= 0 && chr > 0)
{
//DO YOUR STUFF using either "chr" as special key (UP, DOWN, etc..)
//either _pressCharBuffer.ToString()(can contain more than one character if dead key was pressed before)
//and don't forget to set the "handled" to true, so nobody else can use the message afterwards
}
}
return handled;
}
It is known that ToUnicode() and its older counterpart ToAscii() can change keyboard state of the current thread and thus mess with dead keys and ALT+NUMPAD keystrokes:
As ToUnicodeEx translates the virtual-key code, it also changes the
state of the kernel-mode keyboard buffer. This state-change affects
dead keys, ligatures, alt+numpad key entry, and so on. It might also
cause undesired side-effects if used in conjunction with
TranslateMessage (which also changes the state of the kernel-mode
keyboard buffer).
To avoid that you can do your ToUnicode() call in a separate thread (it will have a separate keyboard state) or use a special flag in wFlags param that is documented in ToUnicode() docs:
If bit 2 is set, keyboard state is not changed (Windows 10, version
1607 and newer)
Or you can prepare sc->char mapping table beforehand and update it on language change event.
I think it should work with ToAscii() too but better not use this old ANSI codepage-dependant method. Use ToUnicode() API instead that can even return ligatures and UTF-16 surrogate pairs - if keyboard layout have them. Some do.
See Asynchronous input vs synchronous input, a quick introduction
for the reason behind this.
I copy the vkCode in a queue and do the conversion from another thread
#HOOKPROC
def keyHookKFunc(code,wParam,lParam):
global gkeyQueue
gkeyQueue.append((code,wParam,kbd.vkCode))
return windll.user32.CallNextHookEx(0,code,wParam,lParam)
This has the advantage of not delaying key processing by the os
This works for me
byte[] keyState = new byte[256];
//Remove this if using
//GetKeyboardState(keyState);
//Add only the Keys you want
keysDown[(int)Keys.ShiftKey] = 0x80; // SHIFT down
keysDown[(int)Keys.Menu] = 0x80; // ALT down
keysDown[(int)Keys.ControlKey] = 0x80; // CONTROL down
//ToAscii should work fine
if (ToAscii(myKeyboardStruct.VirtualKeyCode, myKeyboardStruct.ScanCode, keyState, inBuffer, myKeyboardStruct.Flags) == 1)
{
//do something
}

limit of 64 ownerdraw createwindow buttons

I want to create an array of 256 colored buttons with the owner draw extended style to a dialog box created with the visual studio dialog design tool. I added a loop to the WM_INITDIALOG message handler in the dialog procedure to do this:
for (i=0; i<=255; i++)
{
int xp, yp;
HWND status;
xp = rect_pos.left+16*(i%16);
yp = rect_pos.top+16*(i>>4);
status = CreateWindow (
TEXT("button"),
"\0",
WS_CHILD|WS_VISIBLE|BS_OWNERDRAW|BS_PUSHBUTTON,
xp,
yp,
15,
15,
hDlg,
(HMENU) 5000+i, // id used to report events
hInst,
NULL
);
if (status == NULL)
xp =7;
}
I added a message handler for the WM_CTLCOLORBTN message.
case WM_CTLCOLORBTN:
{
int zz;
zz = GetWindowLong ((HWND) lParam, GWL_ID); // window identifier
zz -= 5000;
if ((zz >= 0) && (zz <= 255))
{
HBRUSH BS;
SetTextColor ((HDC) wParam, Collector.Color);
SetBkColor ((HDC) wParam, Collector.Color);
return ((LRESULT) Collector.Brush);
}
break;
}
It more or less works but only the first 64 buttons are displayed. I intend to use a different brush to color each button but for debug puproses, I substituted a single well defined brush. I've debugged the code and satisfied myself the x/y coordinates are proper for each button and that the ID provided in the hMenu createwindow call is proper. I watched all 256 buttons get colored in the WM_CTLCOLORBTN handler. I included a check to make sure the createwindow call does not return failure (NULL). I can get either 4 rows of 16 buttons or 4 columns of 16 buttons by interchanging the x/y parameters on the createwindow call.
If I remove the BS_OWNERDRAW bit from the createwindow call, all 256 buttons are drawn.
It's as if there a limit of 64 buttons with BS_OWNERDRAW :-(
Any help would be greatly appreciated!
TIA, Mike
Are you handling the WM_DRAWITEM message in conjunction with the BS_OWNERDRAW style?
In your case, it seems surprising to me that any buttons are displayed while using the BS_OWNERDRAW style, while BS_PUSHBUTTON is set.
As mentioned in the following link to the documentation for BS_OWNERDRAW, you need to handle WM_DRAWITEM and avoid specifying any other BS_ button styles.
Button Styles from MSDN
Also curious is that the WM_CTLCOLORBUTTON message may be received and then ignored for buttons containing the BS_PUSHBUTTON style. Check out the following link for the documentation on that window message.
WM_CTLCOLORBUTTON from MSDN
From what I can see in your code snippet, most likely you will want to do the following:
Set BS_OWNERDRAW when creating the child buttons.
Handle WM_DRAWITEM on the dialog and draw the button in its correct state. Note that you don't have to handle WM_CTLCOLORBUTTON, just use the Brushes and Fonts and modify the DC as you wish inside your WM_DRAWITEM handler.
Also, depending on your application, you might benefit from making your own window class to represent a grid of buttons on your own, and just drawing the items to taste. This is preferable if you're just displaying internal state and not really looking for the user to manage or interact with a grid of buttons.
Thanks to all who gave advice and help. I now have this working to my satisfaction. I have successfully colored the buttons and surrounded them with a black outline if selected or if they have the input focus. I'll add some code snippets below to show the final state of things but here is synopsis. First, I believe there is some legacy code in my system which makes owner drawn buttons respond to the WM_CTLCOLORBTN for the first child 64 buttons created. Second, I believe the only thing one needs to do is create the buttons, respond properly to the WM_DRAWITEM and WM_COMMAND/BN_CLICKED messages.
Here are the code snippets from my dialog box handler.
In the WM_INITDIALOG code -- create the buttons
for (i=0; i<=255; i++)
{
int xp, yp;
HWND status;
xp = rect_pos.left+16*(i&0x0F);
yp = rect_pos.top+16*(i>>4);
status = CreateWindow
(
TEXT("button"),
"\0",
WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_OWNERDRAW,
xp,
yp,
15,
15,
hDlg,
(HMENU) (5000+i), // id used to report events
hInst,
NULL
);
if (status == NULL)
xp =7;
SetFocus (status);
}
Respond to the WM_DRAWITEM message
case WM_DRAWITEM: // Owner drawn botton
{
LPDRAWITEMSTRUCT lpDrawItem;
HBRUSH BS, BS_Old;
HPEN PN_Old;
int sz=15;
int cntl;
cntl = LOWORD (wParam) - 5000;
lpDrawItem = (LPDRAWITEMSTRUCT) lParam;
if (lpDrawItem->CtlType != ODT_BUTTON)
return FALSE;
BS = CreateSolidBrush (ColorRef[cntl]);
if (lpDrawItem->itemState & (ODS_SELECTED | ODS_FOCUS))
{
sz = 14;
PN_Old = (HPEN) SelectObject(lpDrawItem->hDC, GetStockObject(BLACK_PEN));
}
else
PN_Old = (HPEN) SelectObject(lpDrawItem->hDC, GetStockObject(NULL_PEN));
BS_Old = (HBRUSH) SelectObject(lpDrawItem->hDC, BS);
Rectangle (lpDrawItem->hDC, 0, 0, sz, sz);
SelectObject(lpDrawItem->hDC, PN_Old);
SelectObject(lpDrawItem->hDC, BS_Old);
DeleteObject (BS);
return true;
}
and finally in the WM_COMMAND code
if (HIWORD(wParam) == BN_CLICKED)
{
if ((LOWORD(wParam) >= 5000) && (LOWORD(wParam) <=5255))
{
Color[0] = ColorRef[LOWORD(wParam)-5000] & 0xFF;
Color[1] = (ColorRef[LOWORD(wParam)-5000] >> 16) & 0xFF;
Color[2] = (ColorRef[LOWORD(wParam)-5000] >> 8 ) & 0xFF;
InvalidateRect (hDlg, NULL, TRUE);
goto Set_Color;
}
}

Transferring Win32 API WndProc Key messages from one window to the other

I'm developing for Windows Mobile in C++, and I'm running into a problem - I added my window
class, and in it I the keyboard input with my WndProc implementation. The problem is
that I'm getting the wrong codes, and identifying keys such as the func key incorrectly, and to make it worse, the values I'm getting (the wParam of the WM_KEYDOWN message) as different values between the two phones I have here for testing - who knows what will happen on other phones.
After playing around with it for ages, I found out that if I only create a window from the
predefined "EDIT" class, I actually do get the input correctly (in terms of letters/keys).
So the problem must not be in the phone, but rather the modes of getting messages (a bit of a newbie in win32, excuse me for lack of knowledge). I tried playing around with input modes, but sending a message to my window using EM_NUMBERS and the such, always failed.
So what I would want to do (though I'm open for suggestions), is somehow just get the characters from some hidden EDIT window, and forward them to my window. (Though I still need my window to have the focus so it would react correctly to messages different from WM_KEYDOWN and the like)
Is there any way to do this?
This is the 3'rd time I'm asking regarding this issue, i am eternally grateful to everyone who tried to help so far (though would be even more grateful if i had managed to solve my problem)
Here are the relevant code excerpts:
Class registration :
WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ROADMAP));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
window creation
if (width == -1) width = CW_USEDEFAULT;
if (height == -1) height = CW_USEDEFAULT;
RoadMapMainWindow = CreateWindow(g_szWindowClass, szTitle, OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, width, height,
NULL, NULL, g_hInst, NULL);
MessageLoop
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
WNDPROC excerpt :
case WM_KEYDOWN:
{
WORD Code = (WORD)wParam;
int iRepeatTimes = (lParam & 0x0000FFFF);
int iScanCode = (lParam & 0x00FF0000) >> 16;
BOOL bALT_IsDown = (lParam & 0x20000000)? TRUE: FALSE;
BOOL bAlreadyPressed= (lParam & 0x40000000)? TRUE: FALSE;
BOOL bNowReleased = (lParam & 0x80000000)? TRUE: FALSE;
return DefWindowProc(hWnd, message, wParam, lParam);
}
The wParam of WM_KEYDOWN is a virtual key code that is not really constrained to be an ascii (or unicode) character - its simply a code that uniquely identifies the key on the platform.
If you want the 'text' - you want to wait for the WM_CHAR message - the wParam of WM_CHAR will be the actual character value that the user entered.
More Info - in your application loop - where you call TranslateMessage - it is actually the job of TranslateMessage to spot WM_KEYDOWN messages and synthesize and post the corresponding WM_CHAR messages.
TranslateAccelerator seems to be the only thing that can interfere with posted messages.
Of course, sometimes very unusual behaviour can manifest if the windows message proc is (or is not) handing messages to DefWindowProc at the wrong time. Why for example do you have an explicit call to DefWindowProc in your WM_KEYDOWN handler? The easiest way to handle that correctly is to have DefWindowProc as the last thing your window proc does so that all messages, handled and unhandled, go there by default. the exceptional case would be messages where you want to prevent DefWindowProc getting the message (WM_PAINT if you handle it for example).
You also keep mentioning trying to use Edit_SetInputMode - Edit_SetInputMode sends a message to the window: EM_SETINPUTMODE - which is a message only understood by EDIT controls. As you have registered your own window class, 'EM_SETINPUTMODE` is going to do nothing.
I've not had any problems like you describe, so I'd really like to see a bare-bones set of code that repros this. It is known that some phones get spurrious user-range messages but these shouldn't be affecting you at the level you're at. The fact that you're getting wrong codes for something so basic indicates to me that you must have something wrong in your window creation or message handling code.
I am just guessing, but maybe your app is an Ansi app? That could maybe explain that different codepages give you different keycodes. So have you tried to make it all Unicode in the project settings, and define the string constants accordingly? And did you try ctacke's suggestion to make a really basic app?

Resources