http://wiki.allegro.cc/AllegroExamples 以上是英文例子站点。
by Shawn Hargreaves,allegro的作者
目录: 1 Allegro 例子
1.1 exhello
1.2 exmem
1.3 expat
1.4 expal
1.5 exflame
1.6 exbuf
1.7 exflip
1.8 exfixed
1.9 exfont
1.10exmouse
1.11extimer
1.12exkeys
这个例子展示了如何处理键盘输入。
#include <stdio.h>
#include <string.h>
#include <allegro.h>
char *key_names[] =
{
"(none)", "KEY_A", "KEY_B", "KEY_C",
"KEY_D", "KEY_E", "KEY_F", "KEY_G",
"KEY_H", "KEY_I", "KEY_J", "KEY_K",
"KEY_L", "KEY_M", "KEY_N", "KEY_O",
"KEY_P", "KEY_Q", "KEY_R", "KEY_S",
"KEY_T", "KEY_U", "KEY_V", "KEY_W",
"KEY_X", "KEY_Y", "KEY_Z", "KEY_0",
"KEY_1", "KEY_2", "KEY_3", "KEY_4",
"KEY_5", "KEY_6", "KEY_7", "KEY_8",
"KEY_9", "KEY_0_PAD", "KEY_1_PAD", "KEY_2_PAD",
"KEY_3_PAD", "KEY_4_PAD", "KEY_5_PAD", "KEY_6_PAD",
"KEY_7_PAD", "KEY_8_PAD", "KEY_9_PAD", "KEY_F1",
"KEY_F2", "KEY_F3", "KEY_F4", "KEY_F5",
"KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9",
"KEY_F10", "KEY_F11", "KEY_F12", "KEY_ESC",
"KEY_TILDE", "KEY_MINUS", "KEY_EQUALS", "KEY_BACKSPACE",
"KEY_TAB", "KEY_OPENBRACE", "KEY_CLOSEBRACE", "KEY_ENTER",
"KEY_COLON", "KEY_QUOTE", "KEY_BACKSLASH", "KEY_BACKSLASH2",
"KEY_COMMA", "KEY_STOP", "KEY_SLASH", "KEY_SPACE",
"KEY_INSERT", "KEY_DEL", "KEY_HOME", "KEY_END",
"KEY_PGUP", "KEY_PGDN", "KEY_LEFT", "KEY_RIGHT",
"KEY_UP", "KEY_DOWN", "KEY_SLASH_PAD", "KEY_ASTERISK",
"KEY_MINUS_PAD", "KEY_PLUS_PAD", "KEY_DEL_PAD", "KEY_ENTER_PAD",
"KEY_PRTSCR", "KEY_PAUSE", "KEY_ABNT_C1", "KEY_YEN",
"KEY_KANA", "KEY_CONVERT", "KEY_NOCONVERT", "KEY_AT",
"KEY_CIRCUMFLEX", "KEY_COLON2", "KEY_KANJI", "KEY_EQUALS_PAD",
"KEY_BACKQUOTE", "KEY_SEMICOLON", "KEY_COMMAND", "KEY_UNKNOWN1",
"KEY_UNKNOWN2", "KEY_UNKNOWN3", "KEY_UNKNOWN4", "KEY_UNKNOWN5",
"KEY_UNKNOWN6", "KEY_UNKNOWN7", "KEY_UNKNOWN8", "KEY_LSHIFT",
"KEY_RSHIFT", "KEY_LCONTROL", "KEY_RCONTROL", "KEY_ALT",
"KEY_ALTGR", "KEY_LWIN", "KEY_RWIN", "KEY_MENU",
"KEY_SCRLOCK", "KEY_NUMLOCK", "KEY_CAPSLOCK", "KEY_MAX"
};
/* 键盘回调函数. 我们都知道通过回调函数来绘制到屏幕会带来麻烦的
* 不要在你的程序中这么做 ;)
*/
void keypress_handler(int scancode)
{
int i, x, y, color;
char str[64];
i = scancode & 0x7f;
x = SCREEN_W - 100 * 3 + (i % 3) * 100;
y = SCREEN_H / 2 + (i / 3 - 21) * 10;
color = scancode & 0x80 ? makecol(255, 255, 0) : makecol(128, 0, 0);
rectfill(screen, x, y, x + 95, y + 8, color);
ustrzncpy(str, sizeof(str), scancode_to_name(i), 12);
textprintf_ex(screen, font, x + 1, y + 1, makecol(0, 0, 0), -1, "%s", str);
}
END_OF_FUNCTION(keypress_handler)
/* 帮助器函数,为了在屏幕上弄更多的小格子 */
void scroll(void)
{
blit(screen, screen, 0, 32, 0, 24, SCREEN_W / 2, SCREEN_H-32);
rectfill(screen, 0, SCREEN_H-16, SCREEN_W / 2, SCREEN_H-1, makecol(255, 255, 255));
}
int main(void)
{
char buf[128];
int k;
if (allegro_init() != 0)
return 1;
install_keyboard();
install_timer();
if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 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("Unable to set any graphic mode/n%s/n", allegro_error);
return 1;
}
}
set_palette(desktop_palette);
clear_to_color(screen, makecol(255, 255, 255));
/* 绘制按键初始化状态的格子来模拟按键未按下状态 */
for (k = 0; k < KEY_MAX; k++)
keypress_handler (k + 0x80);
/* 加载我们的键盘回调函数. */
LOCK_FUNCTION(keypress_handler);
keyboard_lowlevel_callback = keypress_handler;
acquire_screen();
textprintf_centre_ex(screen, font, SCREEN_W/2, 8, makecol(0, 0, 0), makecol(255, 255, 255),
"Driver: %s", keyboard_driver->name);
/* 使用readkey()来响应键盘输入 */
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Press some keys (ESC to finish)");
scroll();
do {
release_screen();
k = readkey();
acquire_screen();
scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"readkey() returned %-6d (0x%04X)", k, k);
} while ((k & 0xFF) != 27);
/* ASCII码在返回值的低字节 */
scroll(); scroll(); scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Press some more keys (ESC to finish)");
scroll();
do {
release_screen();
k = readkey();
acquire_screen();
scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"ASCII code is %d", k&0xFF);
} while ((k&0xFF) != 27);
/* 硬件扫描码在返回值的高字节 */
scroll(); scroll(); scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Press some more keys (ESC to finish)");
scroll();
do {
release_screen();
k = readkey();
acquire_screen();
scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Scan code is %d (%s)", k>>8, key_names[k>>8]);
} while ((k&0xFF) != 27);
/* 按键的扩展修饰状态储存在变量key_shifts. 注意,在这个版本中ureadkey()
* 取代了readkey():如果你想要在程序中访问ASCII码范围以外的Unicode字符集,
* 比如支持俄语或中文,你就必须这样做
*/
scroll(); scroll(); scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Press some more keys (ESC to finish)");
scroll();
do {
release_screen();
k = ureadkey(NULL);
acquire_screen();
buf[0] = 0;
if (key_shifts & KB_SHIFT_FLAG) strcat(buf, "shift ");
if (key_shifts & KB_CTRL_FLAG) strcat(buf, "ctrl ");
if (key_shifts & KB_ALT_FLAG) strcat(buf, "alt ");
if (key_shifts & KB_LWIN_FLAG) strcat(buf, "lwin ");
if (key_shifts & KB_RWIN_FLAG) strcat(buf, "rwin ");
if (key_shifts & KB_MENU_FLAG) strcat(buf, "menu ");
if (key_shifts & KB_COMMAND_FLAG) strcat(buf, "command ");
usprintf(buf+strlen(buf), "'%c' [0x%02x]", k ? k : ' ', k);
if (key_shifts & KB_CAPSLOCK_FLAG) strcat(buf, " caps");
if (key_shifts & KB_NUMLOCK_FLAG) strcat(buf, " num");
if (key_shifts & KB_SCROLOCK_FLAG) strcat(buf, " scrl");
scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255), buf);
} while (k != 27);
/* 虚拟的扫描码在allegro.h定义,类似KEY_*的形式 */
scroll(); scroll(); scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255), "Press F6");
scroll();
release_screen();
k = readkey();
acquire_screen();
while ((k>>8) != KEY_F6 && (k>>8) != KEY_ESC) {
scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Wrong key, stupid! I said press F6");
release_screen();
k = readkey();
acquire_screen();
}
/* 当检测到多个按键被同时按下时,使用key[]数组 */
scroll(); scroll(); scroll();
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255),
"Press a combination of numbers");
scroll(); scroll();
release_screen();
do {
if (key[KEY_0]) buf[0] = '0'; else buf[0] = ' ';
if (key[KEY_1]) buf[1] = '1'; else buf[1] = ' ';
if (key[KEY_2]) buf[2] = '2'; else buf[2] = ' ';
if (key[KEY_3]) buf[3] = '3'; else buf[3] = ' ';
if (key[KEY_4]) buf[4] = '4'; else buf[4] = ' ';
if (key[KEY_5]) buf[5] = '5'; else buf[5] = ' ';
if (key[KEY_6]) buf[6] = '6'; else buf[6] = ' ';
if (key[KEY_7]) buf[7] = '7'; else buf[7] = ' ';
if (key[KEY_8]) buf[8] = '8'; else buf[8] = ' ';
if (key[KEY_9]) buf[9] = '9'; else buf[9] = ' ';
buf[10] = 0;
textprintf_ex(screen, font, 8, SCREEN_H-16, makecol(0, 0, 0), makecol(255, 255, 255), buf);
rest(1);
} while (!keypressed() || (readkey() >> 8) != KEY_ESC);
clear_keybuf();
keyboard_lowlevel_callback = NULL;
return 0;
}
END_OF_MAIN()
----------------------------------------------------------------------------
1、void keypress_handler(int scancode)
这是一个回调函数,它接收一个码(ASCII 或者Unicode)作为参数,实现的功能是根据此码的状态在屏幕上模拟按键的状态。
但是显然在作为回调函数之前,它被当作一个普通的函数在调用。在这个过程中,Shawn Hargreaves并没有锁屏,即acquire_screen() + release_screen()。也许他是有原因的,或者他真的忘了,至少我在VS2005+WINXP下加了也没什么特别的。
2、LOCK_FUNCTION(keypress_handler);
keyboard_lowlevel_callback = keypress_handler;
公式化应用,也许所有的回调函数都应该锁起来调用。keyboard_lowlevel_callback 返回低位,并将此参数传递给回调函数。
3、Shawn Hargreaves使用了5个do-while结构,以便展示使用各种方法来响应按键信息。
do
k = readkey();
"readkey() returned %-6d (0x%04X)",k,k
while ((k & 0xFF) != 27);
在这个模式下,显示的信息是readkey()的实际返回值。
k & 0xFF 可以用于提取低位的值。
do
k = readkey();
"ASCII code is %d", k&0xFF
while ((k & 0xFF) != 27);
没什么好说的...
do
k = readkey();
"Scan code is %d (%s)", k>>8, key_names[k>>8]
while ((k & 0xFF) != 27);
k>>8,readkey()的高8位是扫描值,从0开始。
do
k = ureadkey(NULL); // 不是readkey();
while (k != 27);
在ASCII码的范围内,状态键+正常键产生的值与正常键产生的值是一样的,但是Unicode码的范围要大的多,因此需要使用ureadkey(NULL)来处理Unicode的输入。这时状态键+正常键产生的码将不在与正常键产生的码相同。
do
if (key[KEY_0])(这就是我要的~)
while (!keypressed() || (readkey() >> 8) != KEY_ESC)
这是最常用的模式,即不使用readkey(),或者ureadkey(NULL),而使用虚拟键。
你也可以改写为while (!keypressed() || !key[KEY_ESC]);