[AD] win_set_window doesn't work with keyboard input in Windows |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
I posted this in the Allegro main mailing list, and Trent suggested
that I bring it up here.
Problem:
Under Allegro 4.2.2 on WinXP SP2, attempting to use readkey or ureadkey
with win_set_window does not return the correct values. After the first
successful readkey/ureadkey call, the state of key_shifts will never
change. This manifests by the key returned by one of the readkey
commands always being lowercase. Numlock does not properly translate
numpad keys either.
Details of Allegro Environment:
The 4.2.2 release of Allegro is being built under Visual Studio 2003,
using the Visual Studio projects and solutions found in the
allegro/build/msvc7 directory. The December 2006 install of the DirectX
SDK is being used.
The program itself was also built under Visual Studio 2003.
Reproduction:
The following program is a small test case that can be used to detect
the presence/absence of the bug. The #define switches between the two
build modes. If CAUSE_BUG is 0, then the code will use Allegro's window.
This mode is shown to work. If CAUSE_BUG is not 0, then the code will
create a window and use wnd_set_window. This mode will not work.
Steps (please follow these to reproduce the bug):
1. Build the executable with CAUSE_BUG set to 0.
2. Run the executable.
3. Maneuver the Allegro window and the console window such that they
have minimal overlap. This is for ease of viewing.
4. Click on the Allegro window to give it input focus.
5. Press a few letter keys. Notice that the letters appear in the
console window in lower-case.
6. Hold shift and press a few letters. Notice that the letters appear
in the console window in upper-case.
7. Build the executable with CAUSE_BUG set to 1.
8. Run the executable.
9. Maneuver the two windows such that they have minimal overlap. This
is for ease of viewing.
10. Click on the non-console window to give it input focus.
11. Press a few letter keys. Notice that the letters appear in the
console window in lower-case.
12. Hold shift and press a few letters. Notice that the letters /do
not appear in upper-case/. Hence the bug.
You can also repeat the CAUSE_BUG=1 steps where you press one of the
Shift keys as the first key you use. If you do that, then all of the
letters will be uppercase, even if you do not hold them down. And the
word shift will always be present.
Notes:
While this particular code does not test what happens when the keyboard
is in polling mode, my actual application does use polling and it does
not work there either.
Also, I have recently discovered that mouse input using similar code
does not work. That is, the mouse input code is broken in the same way
as readkey/ureadkey.
Additionally, be advised that the CAUSE_BUG=1 version of the program
creates a window that is not a good Windows window. If the first key you
press is one of the control keys, then
Source Code:
#include <stdio.h>
#include <string.h>
#include <allegro.h>
#include <winalleg.h>
#include <tchar.h>
#define CAUSE_BUG 0
/* helper function for making more room on the screen */
void scroll(void)
{
blit / 2, SCREEN_H-32);
rectfill (255, 255, 255));
}
void CreateConsole()
{
int hConHandle;
intptr_t lStdHandle;
CONSOLE_SCREEN_BUFFER_INFO coninfo;
FILE *fp;
// allocate a console for this app
AllocConsole();
// set the screen buffer to be big enough to let us scroll text
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
coninfo.dwSize.Y = 500;
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
// redirect unbuffered STDOUT to the console
lStdHandle = (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stdout = *fp;
setvbuf ( stdout, NULL, _IONBF, 0 );
// redirect unbuffered STDIN to the console
lStdHandle = (intptr_t)GetStdHandle(STD_INPUT_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "r" );
*stdin = *fp;
setvbuf ( stdin, NULL, _IONBF, 0 );
// redirect unbuffered STDERR to the console
lStdHandle = (intptr_t)GetStdHandle(STD_ERROR_HANDLE);
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
fp = _fdopen( hConHandle, "w" );
*stderr = *fp;
setvbuf ( stderr, NULL, _IONBF, 0 );
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point
to console as well
// std::ios::sync_with_stdio();
}
void RemoveConsole()
{
FreeConsole();
}
static HWND hMyWnd = NULL;
static HINSTANCE hMyInstance = NULL;
static const TCHAR wndClassName[] = _T("UtilGL");
LRESULT CALLBACK MyWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) // Check For Windows Messages
{
case WM_SYSCOMMAND: // Intercept System Commands
{
switch (wParam) // Check System Calls
{
case SC_SCREENSAVE: // Screensaver Trying To Start?
case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
return 0; // Prevent From Happening
}
break; // Exit
}
case WM_CLOSE: // Did We Receive A Close Message?
{
PostQuitMessage(0); // Send A Quit Message
return 0; // Jump Back
}
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hMyWnd, &ps);
EndPaint(hMyWnd, &ps);
return 0;
}
}
// Pass All Unhandled Messages To DefWindowProc
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
void MakeWindow()
{
hMyInstance = GetModuleHandle(NULL);
//First, we create the WNDClass.
WNDCLASS myWndClass;
myWndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw
On Size, And Own DC For Window.
myWndClass.lpfnWndProc = (WNDPROC) MyWndProc; // WndProc Handles Messages
myWndClass.cbClsExtra = 0; // No Extra Window Data
myWndClass.cbWndExtra = 0; // No Extra Window Data
myWndClass.hInstance = hMyInstance; // Set The Instance
myWndClass.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon
myWndClass.hCursor = LoadCursor(NULL, IDC_ARROW); // Load The Arrow Pointer
myWndClass.hbrBackground = NULL; // No Background Required For GL
myWndClass.lpszMenuName = NULL; // We Don't Want A Menu
myWndClass.lpszClassName = wndClassName; // Set The Class Name
if (!RegisterClass(&myWndClass)) // Attempt To Register The Window Class
{
exit (-1);
}
//Set our style bits.
DWORD dwExStyle; // Window Extended Style
DWORD dwStyle; // Window Style
{
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window Extended Style
dwStyle=WS_OVERLAPPEDWINDOW; // Windows Style
}
RECT windowRect; // Grabs Rectangle Upper Left / Lower Right Values
windowRect.left=(long)0; // Set Left Value To 0
windowRect.right=(long)320; // Set Right Value To Requested Width
windowRect.top=(long)0; // Set Top Value To 0
windowRect.bottom=(long)240; // Set Bottom Value To Requested Height
//Create the real size based on the size that may be imposed on us
by our window style.
AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);
SIZE realWndSize;
realWndSize.cx = windowRect.right - windowRect.left;
realWndSize.cy = windowRect.bottom - windowRect.top;
HWND hDesktop = GetDesktopWindow();
RECT desktopRect;
GetWindowRect(hDesktop, &desktopRect);
int iScreenWidth = desktopRect.right - desktopRect.left;
int iScreenHeight = desktopRect.bottom - desktopRect.top;
POINT wndPosition;
//Determine the window's position.
{
//Center y.
wndPosition.y = (iScreenHeight - realWndSize.cy) / 2;
}
{
//Right side of screen.
wndPosition.x = iScreenWidth - realWndSize.cx;
}
if (!(hMyWnd=CreateWindowEx(dwExStyle, // Extended Style For The Window
wndClassName, // Class Name
_T("Some Window eh"), // Window Title
dwStyle | // Defined Window Style
WS_CLIPSIBLINGS | // Required Window Style
WS_CLIPCHILDREN, // Required Window Style
wndPosition.x, wndPosition.y, // Window Position
realWndSize.cx, realWndSize.cy, // Window Size
NULL, // No Parent Window
NULL, // No Menu
hMyInstance, // Instance
NULL))) // Dont Pass Anything To WM_CREATE
{
UnregisterClass(wndClassName, hMyInstance);
exit (-1);
}
ShowWindow(hMyWnd, SW_SHOW); // Show The Window
SetForegroundWindow(hMyWnd); // Slightly Higher Priority
SetFocus(hMyWnd); // Sets Keyboard Focus To The Window
}
void KillWindow()
{
DestroyWindow(hMyWnd);
hMyWnd = NULL;
UnregisterClass(wndClassName, hMyInstance);
}
int main(void)
{
char buf[128];
#if CAUSE_BUG
//Create our window.
MakeWindow();
//Set it into Allegro.
win_set_window (hMyWnd);
#endif
if (allegro_init () != 0)
return 1;
install_keyboard ();
install_timer ();
#if CAUSE_BUG
#else
if (set_gfx_mode (GFX_AUTODETECT_WINDOWED, 320, 240, 0, 0) != 0) {
if (set_gfx_mode (GFX_SAFE, 640, 480, 0, 0) != 0) {
set_gfx_mode (GFX_TEXT, 0, 0, 0, 0);
allegro_message );
return 1;
}
}
#endif
CreateConsole();
// set_palette(desktop_palette);
// clear_to_color(screen, makecol(255, 255, 255));
/* key qualifiers are stored in the key_shifts variable. Note that this
* version of the code uses ureadkey() instead of readkey(): that is
* necessary if you want to access Unicode characters from outside
* the normal ASCII range, for example to support Russian or Chinese.
*/
char oldLeftShift = key [KEY_LSHIFT];
do {
while(::keypressed ())
{
int k = ureadkey (NULL);
buf[0] = 0;
if (key_shifts (buf, "shift ");
if (key_shifts (buf, "ctrl ");
if (key_shifts (buf, "alt ");
if (key_shifts (buf, "lwin ");
if (key_shifts (buf, "rwin ");
if (key_shifts (buf, "menu ");
if (key_shifts (buf, "command ");
usprintf (buf), "'%c' [0x%02x]", k ? k : ' ', k);
if (key_shifts (buf, " caps");
if (key_shifts (buf, " num");
if (key_shifts (buf, " scrl");
printf ("%s\n", buf);
}
if(oldLeftShift != key [KEY_LSHIFT])
{
if(key [KEY_LSHIFT])
printf ("Left shift pressed!\n");
else
printf ("Left shift released!\n");
}
oldLeftShift = key [KEY_LSHIFT];
} while (!key [KEY_ESC]);
clear_keybuf ();
#if CAUSE_BUG
KillWindow();
#endif
RemoveConsole();
return 0;
}
END_OF_MAIN ()