Application Hangs When Switching In/Out
Kris Asick

I know I'm doing something wrong, but I'm not entirely sure what.

Basically, before reading the lengthy amount of code below, here's what I'm trying to do:

  • I'm writing an input wrapper for the Keyboard, Mouse and Joystick.

  • I'm trying to use my own window instead of Allegro's built-in window.

  • I still want access to Allegro's graphics handling.

This is what I've accomplished:

  • Keyboard input works fine.

  • Mouse input works fine but is still incomplete.

  • Graphics work fine both windowed or fullscreen.

And here's the problem:

  • If the program loses the focus, it locks up.

What am I doing wrong? ???

1// Gemini's DirectInput Testing Program
2 
3#define ALLEGRO_NO_MAGIC_MAIN
4 
5#define APPLICATION_NAME "Gemini's DirectInput Testing Program"
6#define GEMINI_WND_CLASS "GWNDCLASS1"
7 
8#include <allegro.h>
9#include <winalleg.h>
10#include <stdio.h>
11#include <stdlib.h>
12 
13#include "g-dinput.h"
14 
15HINSTANCE app_hInst;
16HWND app_hWnd;
17 
18BITMAP *buffer, *cursor;
19 
20 
21 
22LRESULT CALLBACK G_WindowProc (HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
23{
24 switch (msg)
25 {
26 case WM_CREATE: return 0;
27 case WM_DESTROY: PostQuitMessage(0); return 0;
28 case WM_KEYDOWN: case WM_KEYUP: case WM_SYSKEYDOWN: case WM_SYSKEYUP: return 0;
29 case WM_PAINT: return 0;
30 }
31 
32 return DefWindowProc(hWnd, msg, wParam, lParam);
33}
34 
35void G_HandleWindowsMessages (void)
36{
37 MSG msg;
38 
39 while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
40 {
41 TranslateMessage(&msg);
42 DispatchMessage(&msg);
43 }
44}
45 
46 
47 
48void Switch_In_Callback (void)
49{
50 GDINPUT_ResetThread();
51}
52 
53void g_main (void)
54{
55 char s[512];
56 int z, zz, c;
57 
58 set_color_depth(32);
59 set_gfx_mode(GFX_AUTODETECT_WINDOWED,640,480,0,0);
60 set_display_switch_callback(SWITCH_IN,Switch_In_Callback);
61 
62 if (GDINPUT_Initialize(app_hInst,app_hWnd))
63 {
64 allegro_message("Unable to start DirectInput driver.");
65 exit(1);
66 }
67 if (GDINPUT_Init_Keyboard())
68 {
69 allegro_message("Unable to start DirectInput Keyboard device.");
70 GDINPUT_Shutdown();
71 exit(1);
72 }
73 if (GDINPUT_Init_Mouse(0,0,screen->w-1,screen->h-1,is_windowed_mode()))
74 {
75 allegro_message("Unable to start DirectInput Mouse device.");
76 GDINPUT_Shutdown();
77 exit(1);
78 }
79 GDINPUT_SetMousePos(screen->w/2,screen->h/2);
80 
81 buffer = create_bitmap(640,480);
82 cursor = create_bitmap(25,25);
83 
84 clear_to_color(cursor,bitmap_mask_color(cursor));
85 putpixel(cursor,12,12,makecol(255,255,255));
86 line(cursor,1,12,9,12,makecol(255,255,255));
87 line(cursor,15,12,23,12,makecol(255,255,255));
88 line(cursor,12,1,12,9,makecol(255,255,255));
89 line(cursor,12,15,12,23,makecol(255,255,255));
90 for (z = 0; z < 25; z++) for (zz = 0; zz < 25; zz++)
91 {
92 if (getpixel(cursor,z,zz) == bitmap_mask_color(cursor))
93 {
94 if ((getpixel(cursor,z-1,zz) | getpixel(cursor,z+1,zz) | getpixel(cursor,z,zz-1)
95 | getpixel(cursor,z,zz+1)) != bitmap_mask_color(cursor))
96 putpixel(cursor,z,zz,0);
97 }
98 }
99 
100 do {
101 memset(s,0,sizeof(s));
102 clear_bitmap(buffer);
103 GDINPUT_Poll_Keyboard();
104 GDINPUT_Poll_Mouse();
105 textprintf_ex(buffer,font,8,8,makecol(255,255,0),-1,"Gemini's DirectInput Wrapper Testing Program");
106 textprintf_ex(buffer,font,16,24,makecol(255,255,255),-1,"Key States");
107 for (z = 0; z < 16; z++) textprintf_ex(buffer,font,40+z*24,40,makecol(255,255,255),-1,"0%x",z);
108 for (z = 0; z < 16; z++) textprintf_ex(buffer,font,16,56+z*16,makecol(255,255,255),-1,"%x0",z);
109 for (z = 0; z < 256; z++)
110 {
111 if (gkey[z])
112 {
113 c = makecol(255,64,64);
114 if (!s[0])
115 sprintf(s,"%s",gkey_name_16[z]);
116 else
117 sprintf(s,"%s, %s",s,gkey_name_16[z]);
118 }
119 else
120 c = makecol(96,96,96);
121 textprintf_ex(buffer,font,40+(z%16)*24,56+(z/16)*16,c,-1,"%2x",gkey[z]);
122 }
123 if (s[0]) textprintf_ex(buffer,font,8,440,makecol(0,255,255),-1,"Keys: %s",s);
124 textprintf_right_ex(buffer,font,640,0,makecol(255,192,0),-1,"%d",gdinput_thread_loop);
125 textprintf_right_ex(buffer,font,640,8,makecol(255,0,0),-1,"%d",gdinput_reset_count);
126 draw_sprite(buffer,cursor,gmouse.x-12,gmouse.y-12);
127 vsync();
128 blit(buffer,screen,0,0,0,0,640,480);
129 G_HandleWindowsMessages();
130 Sleep(0);
131 } while (!gkey[GKEY_ESCAPE]);
132
133 GDINPUT_Shutdown();
134}
135 
136int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
137{
138 WNDCLASSEX g_winClass;
139 HWND g_hWnd;
140 
141 app_hInst = hInstance;
142 
143 g_winClass.cbSize = sizeof(WNDCLASSEX);
144 g_winClass.style = CS_HREDRAW | CS_VREDRAW;
145 g_winClass.lpfnWndProc = G_WindowProc;
146 g_winClass.cbClsExtra = 0;
147 g_winClass.cbWndExtra = 0;
148 g_winClass.hInstance = hInstance;
149 g_winClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
150 g_winClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
151 g_winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
152 g_winClass.hbrBackground = NULL;
153 g_winClass.lpszMenuName = NULL;
154 g_winClass.lpszClassName = GEMINI_WND_CLASS;
155 
156 if (!RegisterClassEx(&g_winClass)) return 0;
157 
158 if (!(g_hWnd = CreateWindowEx(NULL,GEMINI_WND_CLASS,APPLICATION_NAME,
159 WS_OVERLAPPEDWINDOW | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
160 100,100,800,600,NULL,NULL,hInstance,NULL))) return 0;
161 
162 app_hWnd = g_hWnd;
163 
164 ShowWindow(g_hWnd,SW_SHOWNORMAL);
165 SetForegroundWindow(g_hWnd);
166 UpdateWindow(g_hWnd);
167 
168 win_set_window(g_hWnd);
169 allegro_init();
170 
171 g_main();
172 
173 return 0;
174}

(NOTE: Unrecognized commands probably come from my DirectInput wrapper. Since the problem is likely messaging related I've excluded it, but will post it if no one can find anything wrong with the above code.)

Also, just a quick note, many of the messages I'm normally supposed to handle are being handled by Allegro. When you set up a custom window, Allegro still processes its message handler before calling your own, and half of the messages in it still function properly (such as WM_PAINT) even if you're using your own window. (Granted, WM_PAINT for example, only functions if you've called set_gfx_mode().)

EDIT: Another quick note: I know the window is bigger than what set_gfx_mode() is being set to. This was to test some stuff and I haven't changed them back yet.

EDIT: Yet another quick note: I tried removing all references to my input wrapper and the hang problem persisted, so the problem's definitely not related to that.

--------------------------------------------------------------------------------

EDIT (6:52 AM, Several Hours Later):

Solved! 8-)
...wish I could take the credit. ;D

Apparently, as I suspected, I wasn't the first person to try to attempt this. In the "allegro\tests\win" folder is a program called "dxwindow", which features a fully functional, user-created window, working perfectly, using Allegro's graphics system. After comparing the differences between my code and it, the solution was all of one line:

set_display_switch_mode(SWITCH_BACKGROUND);

My code works flawlessly now, and I have the amount of control I wanted. (Such as being able to manipulate the mouse cursor without loading the Allegro mouse drivers.)

In the several hour long process of trying to solve this issue I learned some more about the Windows messaging system and how much Allegro handles on its own, so at least those hours weren't completely lost to frustration.

--- Kris Asick (Gemini)
--- http://www.pixelships.com

Thread #590992. Printed from Allegro.cc