Ruby Win32Api get single character non-blocking - ruby

I'm trying to write a simple game working with two threads, one thread to get input from the user, and another thread to animate some scenes. I'm able to get characters without pressing ENTER just fine, but it blocks in the animating thread until the user presses a key. Does anyone know of a way to get a character from the keyboard non-blocking?

If you're looking to checkup on a handful of specific keys, GetAsyncKeyState() can be used to poll for state. Otherwise, you should implement a message loop and handle WM_CHAR messages in your application.
You can access raw win32 functions with a library similar to the following if your environment doesn't already support the win32 functions you need.
RAA - win32-api # raa.ruby-lang.org
Here are relevant links for GetAsyncKeyState().
GetAsyncKeyState() # MSDN
Virtual-Key Codes # MSDN (used as values for GetAsyncKeyState and other functions)
If you decide to go with a message loop, you'll need to implement it on the same thread that hosts the window for your application. A short explanation is available here:
Message Loop in Microsoft Windows # Wikipedia
As shown at that link, there isn't a whole lot to a message loop. Your framework may already have one running behind the scenes to host the window containing your graphics. If this is the case, you don't need a 2nd thread for input; but you will need to intercept and handle windows messages for that host window.
If you have to implement a message loop on your own, you can use the skeleton at the wikipedia link. The DispatchMessage call will direct a windows message to the appropriate window handler. You will need to look for a matching stub or handler for windows messages in your ruby framework, and handle WM_CHAR from there.
DispatchMessage # MSDN
WM_CHAR # MSDN
If you wish to know when keys are pressed/depressed, then you will want to handle WM_KEYUP and WM_KEYDOWN messages.
WM_KEYUP # MSDN
WM_KEYDOWN # MSDN
Also note, GetAsyncKeyState() can be called and returns key state even while another application is in the foreground. Handle WM_ACTIVATE and WM_SETFOCUS/WM_KILLFOCUS messages so that your application ignores or defers checks while a different window is active if you only care about key state while your window is the primary foreground window.
WM_ACTIVATE # MSDN
WM_SETFOCUS # MSDN
WM_KILLFOCUS # MSDN

I have used rubygame for this. It gives you the ability to attach functions to keyboard events with minimal code. RubySDL and GoSu will give you similar functionality.
If you don't want to go that route with game related gems take a look at this on how to check if data is available in IO object. This could be use to poll the keyboard.

Related

Translate sequences of virtual keycodes into the resulting character message

My understanding is that TranslateMessage collates a sequence of key events and adds a WM_CHAR message to the queue if it results in a character. So on my computer what happens when I press Alt+1234 (6 relevant events/messages, including releasing the Alt) is the single character "Ê" comes out (in certain places).
Let's say I have a sequence of virtual key codes and related keypress data generated from the LL keyboard hook. Is there some way of using the Windows OS logic to translate this sequence into a real character? For example, could I construct contrived MSG structures, call TranslateMessage on them and then catch the WM_CHAR ensuing events? That seems very outside of Windows' expectations; haven't tried it yet but it seems like it could cause all kinds of subtle problems.
The cleanest solution I can think of so far is just to re-implement the logic myself to figure out the characters from the virtual codes. This is unfortunate of course since Windows internals already seem to know how to do this! Is there a better way?
I am aware of the existence of MapVirtualKeyA but this does not seem to handle a sequence of virtual key codes.
I am also aware that it is possible to do a hook on all GetMessage calls which could be used just to grab the WM_CHAR messages from every process. However this seems an extremely heavy solution: I need to make a separate DLL unlike for the WH_KEYBOARD_LL hook and then use some sort of IPC to send the characters back to my host process. Also MSDN explicitly says that you should avoid doing global hooks this for anything outside debugging and I need this to work on production machines.
I am also also aware of KeysConverter in .NET (I am fine to use .NET for this) but again this does not seem to deal with sequences of virtual keys like given above.

Is KillTimer really necessary?

This may seem to be a duplicate question for Is KillTimer necessary?, but i would like to confirm this with credible source.
Does destroying window really free the resource allocated by the OS for the timer? (does DestroyWindowsTimers really get called let alone if such function actually exists? if so, where?)
No, it is not necessary. From the documentation of DestroyWindow (with emphasis added):
The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).
Doing a google search the only actual real looking reference to it looked to be some Win2k source code. The url ended with /Censorship/win2k_sources/private/.../timers.c, I'm assuming from the source code leak a while back. I did not look at the code, nor will I post a link here.
That function most likely exist - something like that almost has to exist for timers linked to window handles - since the timer message is delivered to a specific window handle.
I can't see anywhere in the documentation that states that you don't have to call KillTimer to get rid of a timer. So based on the documented contract, you need to call KillTimer. In practice Windows will probably clean it up for you, but since that is undocumented behavior you should write your code to follow the documented behavior and call KillTimer on all your timers.

Filtering the Windows message queue

I've got a routine that looks something like this, in pseudocode:
while PeekMessage(Message, 0, 0, 0, PM_REMOVE)
HandleMessageAppropriately(Message)
Basically, it goes through and pulls all messages out of the queue and dispatches them. I can't change this routine.
I've got a scenario in which this routine, if it's being called under certain conditions and there's a message in the queue representing the user having hit ESC at exactly the wrong moment, it can cause the program to crash. (Gotta love race conditions.)
I can't change the routine above, but I can change the code that calls it. Is there any way that I can do something immediately before this is run that will say "go through the message queue and remove all keyboard input messages where the user hit ESC, without affecting the rest of the items in the queue or changing their order"?
You can use the range parameters in PeekMessage to restrict to the WM_CHAR message only, and PM_NOREMOVE to leave the message queue intact if the character isn't ESC; if the message needs to be removed, repeat the process with the PM_REMOVE flag. Unfortunately there's no way to look past the first WM_CHAR in the queue.
This is the exact equivalent to the infamous DoEvents call that got so many VB6 programmers in trouble. Because surely the ESC keypress is closing a window, leaving code running in a loop without a user interface anymore. The outcome is invariably poor.
You don't mess around with this, you call EnableWindow(hWnd, FALSE) before you enter this loop to disable input on the window that shouldn't be closed. Now you don't care anymore what's in the message queue. The exact same thing that dialogs do.
Don't paper over a modal loop. Make it modal, make it obvious to the user too.
You may be best to hook the call to PeekMessages and replace it with a version that does what you need.
You could use madshi's hooking routines but it's not hard - I've published a simple hook routine here on Stack Overflow.
If the code was running in an executable module that you compile then you could compile a customised version of Windows.pas that replaced PeekMessage. Of course I'm guessing that you code is Delphi.

Can abusing RegisterWindowMessage lead to resource exhaustion?

MSDN advises that RegisterWindowMessage() function is only used for registering messages to be sent between the processes. If a message is needed for sending within one process it can be safely selected from the range WM_APP through 0xBFFF.
However in our codebase I often see that RegisterWindowMessage() is used for messages only sent within one process. I suppose that this was done because of perceived simplicity of using RegisterWindowMessage() since it doesn't require manually distributing the message identifiers in the WM_APP..0xBFFF range.
Do I understand correctly that if many applications are run on one machine and they all call RegisterWindowMessage() with different strings they could exhaust the range of message identifiers allowed to return by RegisterWindowMessage() and for some of them it will just return a value indicating a failure? What could be a valid reason for using RegisterWindowMessage() messages in cases where WM_APP..0xBFFF range messages would suffice?
IMHO there is no valid reason to use RegisterWindowMessage if you are only sending messages to yourself
There is no (documented) way to un-register a message, so after your app quits, that registered message will stay in the atom table until reboot/logoff (I can't remember exactly where this atom table is stored, the window station or terminal server session instance probably)
The reason you need to use RegisterWindowMessage even when messaging to yourself is that it protects you from the idiot who broadcasts messages in the WM_APP + N range.
Yes, this does happen.
Abusing RegisterWindowMessage can potentially make a windows box unusuable. This is especially true if the window message names are dynamically generated and a bug causes out of control windows message allocation. In this case the global atom table in your windows station/ desktop will fill up and any process using User32.dll (basically, any app) will fail to start, create windows, etc.
There is a bug out there in Delphi / Borland products that registers messages that start with ControlOfsXXXXXX where XXXX is a memory address (or other dynamic modifier). Apps that are started and stopped frequently will register multiple ControlOfsXXXX atoms and eventually exhaust atom space. For more details see:
http://blogs.msdn.com/b/ntdebugging/archive/2012/01/31/identifying-global-atom-table-leaks.aspx
And
https://forums.embarcadero.com/thread.jspa?threadID=47678
A possible advantage is that Spy++ can display more informative text, therefore debugging is a bit easier. Compare
<00058> 00330CA2 S message:0x0419 [User-defined:WM_USER+25] wParam:00000000 lParam:00000000
with
<00129> 004F0DA0 S message:0xC2B0 [Registered:"AFX_WM_ONCHANGE_ACTIVE_TAB"] wParam:00000001 lParam:02B596E8
Of course, in principle there is a chance to run out of message IDs. On the other hand, in the source code of the MFC Feature Pack there are 52 calls to RegisterWindowMessage. So there are still 16300 IDs left for other applications.

How advisable is not having a message loop in WinMain?

This may be the simplest win32 program ever ..
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR cmdLine, int show)
{
MessageBox(0, "Hello world..", "Salutations!", MB_OK);
return 0;
}
.. which makes no calls whatsoever to the usual GetMessage() call. My question is this: if my program doesn't process any window messages, can the OS cope with that? I.e., does it cause memory leaks? Or some other resource that wouldn't be apparent unless I ran it 16K times?
In a broader sense, exactly how 'dependent' is Win32 on applications taking care of their messages? I would hope that when the compiler links the executable as a windows program, that the run-time would be capable of cleaning up any kind of message queue, be it emptied or not.
Just a technicality, but you do have a window, and you do have a message loop, just not in your code.
The call to MessageBox() creates a window (of class #32770) and runs a local message loop, not returning to your code till the message loop drops out, presumably when WM_NCDESTROY is sent. I think it's the same message loop that runs in response to DialogBox().
But you could substitute your call to MessageBox() with anything else that really doesn't create a message loop, and you'll still be fine. Windows doesn't care if you have a message loop, although some functionality (primarily UI related) is difficult or impossible to use without it. In fact, you don't have to link to user32 at all, and some apps that have no user interface don't.
Now if you create a window and don't process messages for it in some way, Windows XP and up will replace your window with a "ghost" window that has a white client area and Task Manager will tell the user that the application is not responding.
Although it seems so at first, the message loop is not magic or a strictly required part of Windows boilerplate. It is highly ingrained as a standard in most Windows applications, though, because it's the best way to handle the dispatching of window messages. The "event-driven" nature of most Windows applications makes us forget sometimes that Windows applications were originally designed to be single-threaded, and in this model, it is code running within that single thread, not some unseen force within the operating system, that must make every function call within our code. The addition of multithreading changed that somewhat, but the basic model still remains the same.
EDIT
A note about message queues:
As is mentioned elsewhere, a message queue is only created (and on a per-thread basis) when a window is created by that thread. Your example program, upon creating a message box, does create a message queue. But this queue need not be empty when your application exits. This queue is just a memory structure. It's a block of memory that can hold a certain number of message objects (specifying destination hWnd, message id, wParam, lParam, system time when message was posted, mouse position when message was posted, and some data that allows the derivation of keyboard and mouse button state when the message was posted), along with pointers to the head and tail of the queue (I assume it's a circular queue). When the application exits, this memory, like all memory belonging to the process, is summarily freed.
There are, of course, other things that must be cleaned up outside your process. The OS must keep a table of all existing windows, for example, along with the thread and process that created them. Of course, these are all cleaned up automatically as well.
Since you don't have a window, you don't need a message loop. In Win32 the messages are sent to windows, not to applications.
You do have a message loop - MessageBox is a modal dialog and therefore contains a message loop within.
You don't have to create windows. But still, there are some kind of messages, like
WM_TIMER
WM_TIMECHANGE
WM_CLIPBOARDUPDATE
WM_COPYDATA
WM_POWER
that you may need. So, a ghost window hanging around wouldn't be bad.
If you don't have a window, then that is fine, but if you do then you need to make sure that you pump messages for it. Otherwise the system can hang on broadcast messages waiting for you to respond. This is important for things like COM which create hidden windows for message processing. If your main thread does not pump messages (e.g., by calling WaitForSingleObject) then calls to your COM objects will not be processed, and any programs which send broadcasts will appear to hang.
I have read somewhere (and can't find the reference) is that Windows will create a message queue on demand. If you never call a function that looks for a message queue, one will never be created. And this occurs on a per-thread basis.

Resources