Having trouble injecting keyboard events to FLTK - events

I have a system with no keyboard. I can connect a keyboard, but ultimately the inputs come from a custom keypad which is not a HID device, it sends serial data which I can interpret and decode to determine if the user pressed Up, Down, Left, Right, or Enter.
Right now all I have is a Fl_Window, with two Fl_Button widgets. Focus is set for one of the buttons and callbacks are defined for these buttons. I know that if I attach a real keyboard, and use the arrow keys I can change focus from button to button. I do have to hit SPACE to activate a button.
My problem is determining how to cause these key presses using code when I decode the outcome form the embedded key pad. Because in deployment, there will be no actual keyboard.
What I've tried is to invoke int Fl_Window::handle(int) and not really had success. I've also tried to invoke int Fl::handle(int, Fl_Window *) and not had success.
Here are code examples:
if((ret = Fl::handle(FL_Left, window)) == 0)
That compiles, but I find that I get zero back, implying that it did not process the event.
if((ret = Fl_Window::handle(FL_Right)) == 0)
That does not compile, informing me that it "cannot call member function virtual int Fl_Window::handle(int) without object"
I'm thinking that the "int event" actually ought to be FL_KEYDOWN.
That logic leaves me to wonder though how I "set" event_key(). For instance, there are API functions to get that when one has a handler, but I do not wish to get that; I wish to cause that event to occur.
Is my only option here to figure out how to emulate a HID or make some type of virtual HID where I then cause the keyboard events to occur?
I do not feel I require a handler function in my application, I'm fine with the default behaviors which occur and cause my callback functions to be invoked. My problem is that I can't "cause" these events to occur.

You need to assign the desired key to e_keysym, then dispatch a FL_KEYDOWN event using Fl::handle_(). (Fl::handle() will not generate the followup FL_SHORTCUT event.)
Fl::e_keysym = FL_Left;
Fl::handle_(FL_KEYDOWN, window);
// sleep() and/or Fl::wait() as appropriate
Fl::handle_(FL_KEYUP, window);

Related

Win32 App (Aero): Prevent dialog move

I've a dialog based Win32-app on Win7-Aero which only displays a dialog. The dialog should have a title bar. I don't want that the user can move the dialog on the screen.
I've no luck so far... handling WM_NCHITTEST, WM_SYSCOMMAND... setting SWP_NOMOVE.
What is the best way to achieve NoMove? I think DWM changes something on Win7.
You could do this by handling WM_WINDOWPOSCHANGING and when you see an attempted move, change the coordinates back to where they should be. E.g.
switch (uMsg)
{
case WM_WINDOWPOSCHANGING:
if (!(reinterpret_cast<LPWINDOWPOS>(lParam)->flags & SWP_NOMOVE))
{
reinterpret_cast<LPWINDOWPOS>(lParam)->x = g_iMyXCoord;
reinterpret_cast<LPWINDOWPOS>(lParam)->y = g_iMyYCoord;
}
return 0;
}
You would probably need to add some intelligence to this to distinguish between attempted moves by the user, and moves that your own program makes (or that the system makes if necessary - e.g. if a monitor disappears for instance).
Even though you say it doesn't work, I would have thought you could also do this by trapping WM_NCHITTEST and returning HTBORDER whenever HTCAPTION would have been returned - however you would have to do this by sub-classing the window rather than in the DialogProc (because you would need to call the default handler first and then process/change the return value). Same for WM_SYSCOMMAND (to catch moves the user attempts via the system menu).

GetAsyncKeyState() fails to return state of keyboard/mouse, while WM_KEYDOWN messages seem to work fine

I'm writing a game where I use GetAsyncKeyState() for character control like WASD and mouse buttons, and the windows messaging system for menu stuff like text input and cursor control.
Every once in a while, my computer seems to get into this weird state where GetAsyncKeyState() doesn't return anything. It seems to be related to times when my game crashes. Once the computer is in this state, I don't know how to get it out unless I restart the computer.
The windows messaging system still works fine in this case- if I type the 'W' key, I still get a WM_KEYDOWN message and the letter can show in my menu system, but the following method, which normally works, will fail:
bool result = (GetAsyncKeyState(vkey) & 0x8000) != 0;
For all I know, this is being caused by an external program (such as Synergy+, which I use to share mouse/keyboard input between computers), however I haven't been able to prove this yet.
Whatever the cause, I don't want this problem to occur to an end user. Are there any techniques to diagnose and repair a state like this?
EDIT: Perhaps this is some kind of driver issue? I just noticed that when my computer gets in this state, my mouse no longer processes the shortcuts I've assigned to its extra buttons. I don't know enough about how all this works to know what to blame in a case like this.

Modeless dialog keyboard handling (winapi)

I've got an application with a main window which has a bunch of controls, including the spacebar, which is handled by a simple method called onSpacebar(). On top of that main window, I've got a persistent modeless dialog.
I need the spacebar to behave the exact same way, regardless of whether the dialog has focus, or the main window has focus.
This dialog is backed by a DialogProc which looks something like this:
BOOL CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_NOTIFY:
std::cout<< "WM_NOTIFY" <<std::endl;
switch(LOWORD(wParam))
{
// which component caused the message?
case COMP_TREE:
if(((LPNMHDR)lParam)->code == NM_DBLCLK){
onDoubleclk()
}
//...
break;
// other components...
}
break;
case WM_CLOSE:
// the dialog can only be closed when the whole app is closed
//EndDialog(hDlg, IDCANCEL);
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
From what I gather, I should call my onSpacebar() method from within the DialogProc, similarily how I handle the double click. I can see that WM_NOTIFY is received by the dialog when the spacebar is pressed (the phrase WM_NOTIFY is printed to cout), but I can't seem to differentiate the spacebar notification from the other numerous notifications the dialog receives.
Please, tell me how to recognize that the particular WM_NOTIFY was in response to a spacebar keypress.
A WM_NOTIFY message is not the standard way that a window processes key press events. When a key is pressed, your window should be receiving WM_KEYDOWN, WM_KEYUP, and possibly WM_CHAR messages. WM_NOTIFY serves an entirely different purpose altogether: passing on a message from a common control to its parent window.
So the fact that you're receiving a WM_NOTIFY message in response to a key press is a fairly unusual thing, explainable when you understand how focus works (which is key to solving your ultimate question).
In Windows, only one window can be focused at a time, and the currently focused window is the one that receives all keyboard input. Thus, if a dialog box has the focus, it will receive key press notifications. If a child control on that dialog box has the focus, it (not its parent dialog) will receive key press notifications. And there is a focusable child control on a dialog box, it will always receive the focus in preference to its parent dialog, therefore it will also always receive key press notifications.
So the likely explanation for your curious WM_NOTIFY messages is that one of the common controls on your dialog has the focus, it is receiving the space key press event, and after processing it, passing on a notification to its parent window (your dialog) in the form of a WM_NOTIFY message. As you might imagine, this is not a reliable method of detecting that the space bar has been pressed.
Instead, you need to figure out some way of trapping key press notifications before they get sent to the focused control. To do that, you'll need to modify your application's message loop to trap WM_KEYDOWN or WM_KEYUP messages before calling either DispatchMessage or IsDialogMessage.
If the key event corresponds to the space bar, you will call your onSpacebar function and indicate that the message was handled, preventing it from being passed on and processed by another window.
If the key event does not correspond to the space bar, then you will need to handle the message as you usually would, ensuring that it does get passed on and processed by the other window.
Since this approach filters out space key presses at a global level, it solves both the problems of child controls on a dialog stealing the key press and the other modeless dialog. However, you do need to be careful because it's very easy to screw things up so that the user can't navigate your dialog using the keyboard at all.
More fundamentally, I think your idea to handle presses of the space bar is fundamentally flawed. The logic of certain common controls basically requires that they process presses of the space bar. For example, consider a textbox: if you filter out all presses of the space bar at a global level, the user will never be able to type a space in a textbox. If you insist on handling the space bar, you will need to check the focused control in your global handler, and if it's a textbox (or other common control that you wish to receive spaces), pass it on; otherwise, handle it yourself.
Honestly, what I'd do instead is choose a more unique key combination (like, I don't know, Ctrl+Space) and set that up as an accelerator. Presumably, your global message loop is already processing accelerator keys by calling the TranslateAccelerator function, so that would take care of all the dirty work for you. No code is even required—you'd do everything simply by editing the accelerators resource file in your project. The MSDN documentation on keyboard accelerators is here, but you'll probably have an easier time consulting your favorite book on Visual C++.

CGEventCreateKeyboardEvent on Desktop vs MacBook

Ola Folks,
Once again I want to drink from the pool of knowledge shared by people using SO.
I have written a small app for OSX that sends key events to an application. I am targeting OSX 10.5.x and newer. However, the problem exists when I build for 10.6.x as well. Everything works fine except when I send only the modifier keys; Alt, Command, Control and Shift.
The problem is that on the two MacBooks, the events for the modifier keys appear to be cleared as soon as the testers move the cursor using the mouse or touch the touchpad.
On a desktop with XCode installed, everything works fine. Just like it should. On two different MacBooks, the problem occurs. The desktop has a standard 101 key keyboard and a multi-button mouse attached.
When a mouse is connected to the MacBooks, a two button mouse with scrollwheel is used. However, the problem exists when no peripherals are attached and the touchpad is used.
What I expect to happen is that the Modifier Key event is sent to the target application, the user moves the cursor using the mouse / touchpad, press buttons on the mouse / touchpad and/or press keys on the keyboard with the modifier key down event 'active'. Then, when they finish, the key up event for the modifier key is sent.
Here is how I am sending key down events, the Shift key for this example:
case ModKeyShiftDown:
xEventSource = CGEventSourceCreate(kCGEventSourceStatePrivate);
xTheCommand = CGEventCreateKeyboardEvent(xEventSource, kVK_Shift, true);
CGEventSetFlags(xTheCommand, kCGEventFlagMaskAlternate);
CGEventPost(kCGHIDEventTap, xTheCommand);
//CGEventPost(kCGSessionEventTap, xTheCommand);
//CGEventPost(kCGAnnotatedSessionEventTap, xTheCommand);
CFRelease(xTheCommand);
CFRelease(xEventSource);
break;
I have used all three flags for creating the event source (kCGEventSourceStatePrivate, kCGEventSourceStateCombinedSessionState and kCGEventSourceStateHIDSystemState).
I have tried Creating the Keyboard Event with the Event Source as well as null as the first parameter.
I have tried with and without the appropriate flags on the event.
I have tried various combinations of posting the event; kCGHIDEventTap, kCGSessionEventTap and kCGAnnotatedSessionEventTap.
For completeness, here is how I send an up event for the Shift key:
case ModKeyShiftUp:
xEventSource = CGEventSourceCreate(kCGEventSourceStatePrivate);
xTheCommand = CGEventCreateKeyboardEvent(xEventSource, kVK_Shift, false);
CGEventSetFlags(xTheCommand, 0);
CGEventPost(kCGHIDEventTap, xTheCommand);
//CGEventPost(kCGSessionEventTap, xTheCommand);
//CGEventPost(kCGAnnotatedSessionEventTap, xTheCommand);
CFRelease(xTheCommand);
CFRelease(xEventSource);
break;
When the testers trigger a modifier key down event, they can see the cursor change as expected. This lets me know the event is being processed by the target application. However, as soon as they touch the mouse or touchpad, the cursor changes back to a standard cursor and the mouse events are processed as if no modifier key events are active.
I would like to know if there is a problem with the way I am sending the events. I would also like to know if there is an alternate way to send Modifier Key events that is Going To Work.
Sorry if I overtalked this. My excuse is that I only slept a couple of hours. :P
Thanx
-isdi-
Ola,
Interestingly enough, using AXUIElementRef and AXUIElementPostKeyboardEvent seem to work.
For whatever reason, sending key events using the Accessibility object and method above solves the problem for the testers.

Setting Virtual Key/MouseButton State Without Triggering Events

Is it possible to set the virtual key state / mouse button state for all programs on a computer without triggering the associated events at the same time (like setting the left mouse button to be currently pressed without sending a mouse down event). Could this be achieved by setting up a fake keyboard or mouse driver for a fake keyboard or mouse that when queried as to the current state of a key would reply giving an answer of your choice or by any other means?
Edit:
This has to affect programs that I do not have the code for running in other threads ect...
Well, I don't have a complete answer for you but...
The Win32 function SetKeyboard State() changes the state of the keyboard for the thread that called it.
I know this does not affect the entire system, but if you only need the keyboard state changed for applications you are developing, then this could be called by each program, reading in the array passed to it from a temporary file on the harddrive.
Otherwise... don't know of anything else offhand...

Resources