[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 ()




Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/