Modify Allegro to use WM_KEYUP/DOWN messages instead of DirectInput.

This commit is contained in:
David Capello 2010-10-17 21:55:31 -03:00
parent 57b54ad050
commit a877d52048
12 changed files with 197 additions and 799 deletions

View File

@ -4,3 +4,5 @@ patched for ASE by David Capello.
Changes:
- Mouse driver for Windows was modified to use WM_MOUSEMOVE instead of
DirectInput (like in Allegro 5).
- Keyboard driver for Windows was modified to use WM_KEYDOWN/UP messages
instead of DirectInput (like in Allegro 5).

View File

@ -120,10 +120,6 @@ AL_FUNC(int, _win_input_register_event, (HANDLE event_id, void (*event_handler)(
AL_FUNC(void, _win_input_unregister_event, (HANDLE event_id));
/* keyboard routines */
AL_FUNC(int, key_dinput_acquire, (void));
AL_FUNC(int, key_dinput_unacquire, (void));
/* mouse routines */
AL_VAR(HCURSOR, _win_hcursor);

View File

@ -77,12 +77,6 @@ AL_VAR(SYSTEM_DRIVER, system_directx);
/*******************************************/
/************ keyboard drivers *************/
/*******************************************/
#define KEYBOARD_DIRECTX AL_ID('D','X',' ',' ')
/*******************************************/
/*************** gfx drivers ***************/

View File

@ -82,8 +82,6 @@ typedef struct WIN_GFX_DRIVER {
AL_VAR(WIN_GFX_DRIVER *, win_gfx_driver);
AL_FUNC(void, win_grab_input, (void));
/* external window support */
AL_FUNC(HWND, win_get_window, (void));

View File

@ -237,9 +237,6 @@ static void finalize_fullscreen_init(void)
/* set the default switching policy */
set_display_switch_mode(SWITCH_AMNESIA);
/* grab input devices */
win_grab_input();
}

View File

@ -404,9 +404,6 @@ static struct BITMAP *init_directx_ovl(int w, int h, int v_w, int v_h, int color
/* set default switching policy */
set_display_switch_mode(SWITCH_PAUSE);
/* grab input devices */
win_grab_input();
_exit_critical();
return gfx_directx_forefront_bitmap;

View File

@ -772,9 +772,6 @@ static struct BITMAP *init_directx_win(int w, int h, int v_w, int v_h, int color
/* set default switching policy */
set_display_switch_mode(SWITCH_PAUSE);
/* grab input devices */
win_grab_input();
_exit_critical();
return gfx_directx_forefront_bitmap;

View File

@ -113,8 +113,6 @@ void _win_switch_in(void)
_win_app_foreground = TRUE;
key_dinput_acquire();
if (win_gfx_driver && win_gfx_driver->switch_in)
win_gfx_driver->switch_in();
@ -145,8 +143,6 @@ void _win_switch_out(void)
_win_app_foreground = FALSE;
key_dinput_unacquire();
if (win_gfx_driver && win_gfx_driver->switch_out)
win_gfx_driver->switch_out();

View File

@ -513,9 +513,6 @@ static struct BITMAP *gfx_gdi_init(int w, int h, int v_w, int v_h, int color_dep
/* set the default switching policy */
set_display_switch_mode(SWITCH_PAUSE);
/* grab input devices */
win_grab_input();
_exit_critical();
return gdi_screen;

View File

@ -1,32 +1,15 @@
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
* /\____/
* \_/__/
*
* Windows keyboard driver.
*
* By Stefan Schimanski, hacked up by Peter Wang and Elias Pschernig.
*
* See readme.txt for copyright information.
*/
/*
Mouse driver for ASE
by David Capello
#define DIRECTINPUT_VERSION 0x0300
Based on code of Stefan Schimanski, Peter Wang, Elias Pschernig,
and Milan Mimica.
*/
#include "allegro.h"
#include "allegro/internal/aintern.h"
#include "allegro/platform/aintwin.h"
#ifndef SCAN_DEPEND
#include <process.h>
#include <dinput.h>
#endif
#ifndef ALLEGRO_WINDOWS
#error something is wrong with the makefile
#endif
@ -36,130 +19,86 @@
#define PREFIX_E "al-wkey ERROR: "
#define DINPUT_BUFFERSIZE 256
static HANDLE key_input_event = NULL;
static HANDLE key_input_processed_event = NULL;
static LPDIRECTINPUT key_dinput = NULL;
static LPDIRECTINPUTDEVICE key_dinput_device = NULL;
#define KEY_UNKNOWN KEY_MAX
/* lookup table for converting DIK_* scancodes into Allegro KEY_* codes */
/* this table was from pckeys.c */
static const unsigned char hw_to_mycode[256] = {
/* 0x00 */ 0, KEY_ESC, KEY_1, KEY_2,
/* 0x04 */ KEY_3, KEY_4, KEY_5, KEY_6,
/* 0x08 */ KEY_7, KEY_8, KEY_9, KEY_0,
/* 0x0C */ KEY_MINUS, KEY_EQUALS, KEY_BACKSPACE, KEY_TAB,
/* 0x10 */ KEY_Q, KEY_W, KEY_E, KEY_R,
/* 0x14 */ KEY_T, KEY_Y, KEY_U, KEY_I,
/* 0x18 */ KEY_O, KEY_P, KEY_OPENBRACE, KEY_CLOSEBRACE,
/* 0x1C */ KEY_ENTER, KEY_LCONTROL, KEY_A, KEY_S,
/* 0x20 */ KEY_D, KEY_F, KEY_G, KEY_H,
/* 0x24 */ KEY_J, KEY_K, KEY_L, KEY_SEMICOLON,
/* 0x28 */ KEY_QUOTE, KEY_TILDE, KEY_LSHIFT, KEY_BACKSLASH,
/* 0x2C */ KEY_Z, KEY_X, KEY_C, KEY_V,
/* 0x30 */ KEY_B, KEY_N, KEY_M, KEY_COMMA,
/* 0x34 */ KEY_STOP, KEY_SLASH, KEY_RSHIFT, KEY_ASTERISK,
/* 0x38 */ KEY_ALT, KEY_SPACE, KEY_CAPSLOCK, KEY_F1,
/* 0x3C */ KEY_F2, KEY_F3, KEY_F4, KEY_F5,
/* 0x40 */ KEY_F6, KEY_F7, KEY_F8, KEY_F9,
/* 0x44 */ KEY_F10, KEY_NUMLOCK, KEY_SCRLOCK, KEY_7_PAD,
/* 0x48 */ KEY_8_PAD, KEY_9_PAD, KEY_MINUS_PAD, KEY_4_PAD,
/* 0x4C */ KEY_5_PAD, KEY_6_PAD, KEY_PLUS_PAD, KEY_1_PAD,
/* 0x50 */ KEY_2_PAD, KEY_3_PAD, KEY_0_PAD, KEY_DEL_PAD,
/* 0x54 */ KEY_PRTSCR, 0, KEY_BACKSLASH2, KEY_F11,
/* 0x58 */ KEY_F12, 0, 0, KEY_LWIN,
/* 0x5C */ KEY_RWIN, KEY_MENU, 0, 0,
/* 0x60 */ 0, 0, 0, 0,
/* 0x64 */ 0, 0, 0, 0,
/* 0x68 */ 0, 0, 0, 0,
/* 0x6C */ 0, 0, 0, 0,
/* 0x70 */ KEY_KANA, 0, 0, KEY_ABNT_C1,
/* 0x74 */ 0, 0, 0, 0,
/* 0x78 */ 0, KEY_CONVERT, 0, KEY_NOCONVERT,
/* 0x7C */ 0, KEY_YEN, 0, 0,
/* 0x80 */ 0, 0, 0, 0,
/* 0x84 */ 0, 0, 0, 0,
/* 0x88 */ 0, 0, 0, 0,
/* 0x8C */ 0, 0, 0, 0,
/* 0x90 */ 0, KEY_AT, KEY_COLON2, 0,
/* 0x94 */ KEY_KANJI, 0, 0, 0,
/* 0x98 */ 0, 0, 0, 0,
/* 0x9C */ KEY_ENTER_PAD, KEY_RCONTROL, 0, 0,
/* 0xA0 */ 0, 0, 0, 0,
/* 0xA4 */ 0, 0, 0, 0,
/* 0xA8 */ 0, 0, 0, 0,
/* 0xAC */ 0, 0, 0, 0,
/* 0xB0 */ 0, 0, 0, 0,
/* 0xB4 */ 0, KEY_SLASH_PAD, 0, KEY_PRTSCR,
/* 0xB8 */ KEY_ALTGR, 0, 0, 0,
/* 0xBC */ 0, 0, 0, 0,
/* 0xC0 */ 0, 0, 0, 0,
/* 0xC4 */ 0, KEY_PAUSE, 0, KEY_HOME,
/* 0xC8 */ KEY_UP, KEY_PGUP, 0, KEY_LEFT,
/* 0xCC */ 0, KEY_RIGHT, 0, KEY_END,
/* 0xD0 */ KEY_DOWN, KEY_PGDN, KEY_INSERT, KEY_DEL,
/* 0xD4 */ 0, 0, 0, 0,
/* 0xD8 */ 0, 0, 0, KEY_LWIN,
/* 0xDC */ KEY_RWIN, KEY_MENU, 0, 0,
/* 0xE0 */ 0, 0, 0, 0,
/* 0xE4 */ 0, 0, 0, 0,
/* 0xE8 */ 0, 0, 0, 0,
/* 0xEC */ 0, 0, 0, 0,
/* 0xF0 */ 0, 0, 0, 0,
/* 0xF4 */ 0, 0, 0, 0,
/* 0xF8 */ 0, 0, 0, 0,
/* 0xFC */ 0, 0, 0, 0
};
/* Used in scancode_to_name. */
static LONG reverse_mapping[KEY_MAX];
/* dinput_err_str:
* Returns a DirectInput error string.
*/
#ifdef DEBUGMODE
static char* dinput_err_str(long err)
/* lookup table for converting virtualkey VK_* codes into Allegro KEY_* codes */
/* Last unknown key sequence: 39*/
static const unsigned char hw_to_mycode[256] =
{
static char err_str[64];
/* 0x00 */ 0, KEY_UNKNOWN+0, KEY_UNKNOWN+1, KEY_UNKNOWN+2,
/* 0x04 */ KEY_UNKNOWN+3, KEY_UNKNOWN+4, KEY_UNKNOWN+5, 0,
/* 0x08 */ KEY_BACKSPACE, KEY_TAB, 0, 0,
/* 0x0C */ KEY_UNKNOWN+39, KEY_ENTER, 0, 0,
/* 0x10 */ 0/*L or R shift*/, 0/*L or R ctrl*/, 0/*L or R alt*/, KEY_PAUSE,
/* 0x14 */ KEY_CAPSLOCK, KEY_KANA, 0, KEY_UNKNOWN+6,
/* 0x18 */ KEY_UNKNOWN+7, KEY_KANJI, 0, KEY_ESC,
/* 0x1C */ KEY_CONVERT, KEY_NOCONVERT, KEY_UNKNOWN+8, KEY_UNKNOWN+9,
/* 0x20 */ KEY_SPACE, KEY_PGUP, KEY_PGDN, KEY_END,
/* 0x24 */ KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT,
/* 0x28 */ KEY_DOWN, KEY_UNKNOWN+10, KEY_UNKNOWN+11, KEY_UNKNOWN+12,
/* 0x2C */ KEY_PRTSCR, KEY_INSERT, KEY_DEL, KEY_UNKNOWN+13,
/* 0x30 */ KEY_0, KEY_1, KEY_2, KEY_3,
/* 0x34 */ KEY_4, KEY_5, KEY_6, KEY_7,
/* 0x38 */ KEY_8, KEY_9, 0, 0,
/* 0x3C */ 0, 0, 0, 0,
/* 0x40 */ 0, KEY_A, KEY_B, KEY_C,
/* 0x44 */ KEY_D, KEY_E, KEY_F, KEY_G,
/* 0x48 */ KEY_H, KEY_I, KEY_J, KEY_K,
/* 0x4C */ KEY_L, KEY_M, KEY_N, KEY_O,
/* 0x50 */ KEY_P, KEY_Q, KEY_R, KEY_S,
/* 0x54 */ KEY_T, KEY_U, KEY_V, KEY_W,
/* 0x58 */ KEY_X, KEY_Y, KEY_Z, KEY_LWIN,
/* 0x5C */ KEY_RWIN, KEY_UNKNOWN+14, 0, 0,
/* 0x60 */ KEY_0_PAD, KEY_1_PAD, KEY_2_PAD, KEY_3_PAD,
/* 0x64 */ KEY_4_PAD, KEY_5_PAD, KEY_6_PAD, KEY_7_PAD,
/* 0x68 */ KEY_8_PAD, KEY_9_PAD, KEY_ASTERISK, KEY_PLUS_PAD,
/* 0x6C */ KEY_UNKNOWN+15, KEY_MINUS_PAD, KEY_UNKNOWN+16, KEY_SLASH_PAD,
/* 0x70 */ KEY_F1, KEY_F2, KEY_F3, KEY_F4,
/* 0x74 */ KEY_F5, KEY_F6, KEY_F7, KEY_F8,
/* 0x78 */ KEY_F9, KEY_F10, KEY_F11, KEY_F12,
/* 0x7C */ KEY_UNKNOWN+17, KEY_UNKNOWN+18, KEY_UNKNOWN+19, KEY_UNKNOWN+20,
/* 0x80 */ KEY_UNKNOWN+21, KEY_UNKNOWN+22, KEY_UNKNOWN+23, KEY_UNKNOWN+24,
/* 0x84 */ KEY_UNKNOWN+25, KEY_UNKNOWN+26, KEY_UNKNOWN+27, KEY_UNKNOWN+28,
/* 0x88 */ 0, 0, 0, 0,
/* 0x8C */ 0, 0, 0, 0,
/* 0x90 */ KEY_NUMLOCK, KEY_SCRLOCK, 0, 0,
/* 0x94 */ 0, 0, 0, 0,
/* 0x98 */ 0, 0, 0, 0,
/* 0x9C */ 0, 0, 0, 0,
/* 0xA0 */ KEY_LSHIFT, KEY_RSHIFT, KEY_LCONTROL, KEY_RCONTROL,
/* 0xA4 */ KEY_ALT, KEY_ALTGR, 0, 0,
/* 0xA8 */ 0, 0, 0, 0,
/* 0xAC */ 0, 0, 0, 0,
/* 0xB0 */ 0, 0, 0, 0,
/* 0xB4 */ 0, 0, 0, 0,
/* 0xB8 */ 0, 0, KEY_SEMICOLON, KEY_EQUALS,
/* 0xBC */ KEY_COMMA, KEY_MINUS, KEY_STOP, KEY_SLASH,
/* 0xC0 */ KEY_TILDE, 0, 0, 0,
/* 0xC4 */ 0, 0, 0, 0,
/* 0xC8 */ 0, 0, 0, 0,
/* 0xCC */ 0, 0, 0, 0,
/* 0xD0 */ 0, 0, 0, 0,
/* 0xD4 */ 0, 0, 0, 0,
/* 0xD8 */ 0, 0, 0, KEY_OPENBRACE,
/* 0xDC */ KEY_BACKSLASH, KEY_CLOSEBRACE, KEY_QUOTE, 0,
/* 0xE0 */ 0, 0, KEY_BACKSLASH2, 0,
/* 0xE4 */ 0, KEY_UNKNOWN+29, 0, 0,
/* 0xE8 */ 0, 0, 0, 0,
/* 0xEC */ 0, 0, 0, 0,
/* 0xF0 */ 0, 0, 0, 0,
/* 0xF4 */ 0, 0, KEY_UNKNOWN+30, KEY_UNKNOWN+31,
/* 0xF8 */ KEY_UNKNOWN+32, KEY_UNKNOWN+33, KEY_UNKNOWN+34, KEY_UNKNOWN+35,
/* 0xFC */ KEY_UNKNOWN+36, KEY_UNKNOWN+37, KEY_UNKNOWN+38, 0
};
switch (err) {
case DIERR_NOTACQUIRED:
_al_sane_strncpy(err_str, "the device is not acquired", sizeof(err_str));
break;
case DIERR_INPUTLOST:
_al_sane_strncpy(err_str, "access to the device was lost", sizeof(err_str));
break;
case DIERR_INVALIDPARAM:
_al_sane_strncpy(err_str, "the device does not have a selected data format", sizeof(err_str));
break;
#ifdef DIERR_OTHERAPPHASPRIO
/* this is not a legacy DirectX 3 error code */
case DIERR_OTHERAPPHASPRIO:
_al_sane_strncpy(err_str, "can't acquire the device in background", sizeof(err_str));
break;
#endif
default:
_al_sane_strncpy(err_str, "unknown error", sizeof(err_str));
}
return err_str;
}
#else
#define dinput_err_str(hr) "\0"
#endif
/* Update the key_shifts.
*/
static void update_shifts(BYTE * keystate)
static void update_shifts(BYTE* keystate)
{
/* TODO: There must be a more efficient way to maintain key_modifiers? */
/* Can't we just deprecate key_shifts, now that pckeys.c is gone? EP */
@ -180,654 +119,147 @@ static void update_shifts(BYTE * keystate)
modifiers |= KB_CAPSLOCK_FLAG;
_key_shifts = modifiers;
}
/* handle_key_press: [input thread]
/* _al_win_kbd_handle_key_press:
* Does stuff when a key is pressed.
*/
static void handle_key_press(unsigned char scancode)
void _al_win_kbd_handle_key_press(int scode, int vcode, BOOL repeated)
{
int mycode;
int unicode;
int n;
UINT vkey;
BYTE keystate[256];
WCHAR chars[16];
int my_code;
int ccode;
BYTE ks[256];
WCHAR buf[8];
vkey = MapVirtualKey(scancode, 1);
GetKeyboardState(keystate);
update_shifts(keystate);
/* TODO: shouldn't we base the mapping on vkey? */
mycode = hw_to_mycode[scancode];
if (mycode == 0)
return;
/* MapVirtualKey always returns the arrow key VKEY, so adjust
it if num lock is on */
if (keystate[VK_NUMLOCK]) {
switch (scancode) {
case DIK_NUMPAD0:
vkey = VK_NUMPAD0;
break;
case DIK_NUMPAD1:
vkey = VK_NUMPAD1;
break;
case DIK_NUMPAD2:
vkey = VK_NUMPAD2;
break;
case DIK_NUMPAD3:
vkey = VK_NUMPAD3;
break;
case DIK_NUMPAD4:
vkey = VK_NUMPAD4;
break;
case DIK_NUMPAD5:
vkey = VK_NUMPAD5;
break;
case DIK_NUMPAD6:
vkey = VK_NUMPAD6;
break;
case DIK_NUMPAD7:
vkey = VK_NUMPAD7;
break;
case DIK_NUMPAD8:
vkey = VK_NUMPAD8;
break;
case DIK_NUMPAD9:
vkey = VK_NUMPAD9;
break;
case DIK_DECIMAL:
vkey = VK_DECIMAL;
break;
}
}
/* what's life without a few special cases */
switch (scancode) {
case DIK_DIVIDE:
vkey = VK_DIVIDE;
break;
case DIK_MULTIPLY:
vkey = VK_MULTIPLY;
break;
case DIK_SUBTRACT:
vkey = VK_SUBTRACT;
break;
case DIK_ADD:
vkey = VK_ADD;
break;
case DIK_NUMPADENTER:
vkey = VK_RETURN;
}
/* TODO: is there an advantage using ToUnicode? maybe it would allow
* Chinese and so on characters? For now, always ToAscii is used. */
//n = ToUnicode(vkey, scancode, keystate, chars, 16, 0);
n = ToAscii(vkey, scancode, keystate, (WORD *)chars, 0);
if (n == 1)
{
WCHAR wstr[2];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (LPCSTR)chars, n, wstr, 2);
unicode = wstr[0];
}
if (!GetKeyboardState(&ks[0]))
ccode = 0; /* shound't really happen */
else if (ToUnicode(vcode, scode, ks, buf, 8, 0) == 1)
ccode = buf[0];
else
{
/* Don't generate key presses for modifier keys or dead keys */
if (mycode >= KEY_MODIFIERS || n != 0)
unicode = -1;
ccode = 0;
/* Windows doesn't differentiate between the left and right versions
of the modifiers. To compensate we read the current keyboard state
and use that information to determine which key was actually
pressed. We check the last known state of the modifier in question
and if it is not down we know that is the key that was pressed. */
if (vcode == VK_SHIFT || vcode == VK_CONTROL || vcode == VK_MENU) {
if ((ks[VK_LCONTROL] & 0x80) && !key[KEY_LCONTROL])
vcode = VK_LCONTROL;
else if ((ks[VK_RCONTROL] & 0x80) && !key[KEY_RCONTROL])
vcode = VK_RCONTROL;
else if ((ks[VK_LSHIFT] & 0x80) && !key[KEY_LSHIFT])
vcode = VK_LSHIFT;
else if ((ks[VK_RSHIFT] & 0x80) && !key[KEY_RSHIFT])
vcode = VK_RSHIFT;
else if ((ks[VK_LMENU] & 0x80) && !key[KEY_ALT])
vcode = VK_LMENU;
else if ((ks[VK_RMENU] & 0x80) && !key[KEY_ALTGR])
vcode = VK_RMENU;
else
unicode = 0;
}
/* When alt key is pressed, any key always must return ASCII 0 in Allegro. */
if (unicode > 0 && (keystate[VK_LMENU] & 0x80)) {
unicode = 0;
}
_handle_key_press(unicode, mycode);
}
/* handle_key_release: [input thread]
* Does stuff when a key is released. The keyboard event source
* should be locked.
*/
static void handle_key_release(unsigned char scancode)
{
int mycode = hw_to_mycode[scancode];
if (mycode == 0)
return;
{
BYTE keystate[256];
GetKeyboardState(keystate);
update_shifts(keystate);
}
_handle_key_release(mycode);
}
/* key_dinput_handle_scancode: [input thread]
* Handles a single scancode.
*/
static void key_dinput_handle_scancode(unsigned char scancode, int pressed)
{
HWND allegro_wnd = win_get_window();
static int ignore_three_finger_flag = FALSE;
/* ignore special Windows keys (alt+tab, alt+space, (ctrl|alt)+esc) */
if (((scancode == DIK_TAB) && (_key_shifts & KB_ALT_FLAG))
|| ((scancode == DIK_SPACE) && (_key_shifts & KB_ALT_FLAG))
|| ((scancode == DIK_ESCAPE) && (_key_shifts & (KB_CTRL_FLAG | KB_ALT_FLAG))))
return;
/* alt+F4 triggers a WM_CLOSE under Windows */
if ((scancode == DIK_F4) && (_key_shifts & KB_ALT_FLAG)) {
if (pressed)
PostMessage(allegro_wnd, WM_CLOSE, 0, 0);
return;
}
/* Special case KEY_PAUSE as flip-flop key. */
if (scancode == DIK_PAUSE) {
if (!pressed)
return;
if (key[KEY_PAUSE])
pressed = 0;
else
pressed = 1;
}
/* if not foreground, filter out press codes and handle only release codes */
if (!wnd_sysmenu || !pressed) {
/* three-finger salute for killing the program */
if (three_finger_flag && (_key_shifts & KB_CTRL_FLAG) && (_key_shifts & KB_ALT_FLAG)) {
if (scancode == 0x00) {
/* when pressing CTRL-ALT-DEL, Windows launches CTRL-ALT-EVERYTHING */
ignore_three_finger_flag = TRUE;
}
else if (!ignore_three_finger_flag && (scancode == DIK_END || scancode == DIK_NUMPAD1)) {
/* we can now safely assume the user hit CTRL-ALT-END as opposed to CTRL-ALT-DEL */
_TRACE(PREFIX_I "Terminating application\n");
abort();
}
else if (ignore_three_finger_flag && scancode == 0xff) {
/* Windows is finished with CTRL-ALT-EVERYTHING - lets return to normality */
ignore_three_finger_flag = FALSE;
_key_shifts = 0;
}
}
/* Ignore repeats for Caps Lock */
if (vcode == VK_CAPITAL && repeated && key[KEY_CAPSLOCK])
return;
if (pressed)
handle_key_press(scancode);
else
handle_key_release(scancode);
}
my_code = hw_to_mycode[vcode];
update_shifts(ks);
_handle_key_press(ccode, my_code);
}
/* key_dinput_handle: [input thread]
* Handles queued keyboard input.
/* _al_win_kbd_handle_key_release:
* Does stuff when a key is released.
*/
static void key_dinput_handle(void)
void _al_win_kbd_handle_key_release(int vcode)
{
static DIDEVICEOBJECTDATA scancode_buffer[DINPUT_BUFFERSIZE];
unsigned long int waiting_scancodes;
HRESULT hr;
unsigned long int i;
int my_code;
BYTE ks[256];
/* the whole buffer is free */
waiting_scancodes = DINPUT_BUFFERSIZE;
/* We need to read the latest key states so we can tell which
modifier was released. */
GetKeyboardState(&ks[0]);
/* fill the buffer */
hr = IDirectInputDevice_GetDeviceData(key_dinput_device,
sizeof(DIDEVICEOBJECTDATA),
scancode_buffer,
&waiting_scancodes,
0);
if (vcode == VK_SHIFT && key[KEY_LSHIFT] && !(ks[VK_LSHIFT] & 0x80))
vcode = VK_LSHIFT;
else if (vcode == VK_SHIFT && key[KEY_RSHIFT] && !(ks[VK_RSHIFT] & 0x80))
vcode = VK_RSHIFT;
else if (vcode == VK_CONTROL && key[KEY_LCONTROL] && !(ks[VK_LCONTROL] & 0x80))
vcode = VK_LCONTROL;
else if (vcode == VK_CONTROL && key[KEY_RCONTROL] && !(ks[VK_RCONTROL] & 0x80))
vcode = VK_RCONTROL;
else if (vcode == VK_MENU && key[KEY_ALT] && !(ks[VK_LMENU] & 0x80))
vcode = VK_LMENU;
else if (vcode == VK_MENU && key[KEY_ALTGR] && !(ks[VK_RMENU] & 0x80))
vcode = VK_RMENU;
else if(vcode == VK_MENU)
return;
/* was device lost ? */
if ((hr == DIERR_NOTACQUIRED) || (hr == DIERR_INPUTLOST)) {
/* reacquire device */
_TRACE(PREFIX_W "keyboard device not acquired or lost\n");
wnd_schedule_proc(key_dinput_acquire);
}
else if (FAILED(hr)) { /* other error? */
_TRACE(PREFIX_E "unexpected error while filling keyboard scancode buffer\n");
}
else {
/* normally only this case should happen */
for (i = 0; i < waiting_scancodes; i++) {
key_dinput_handle_scancode((unsigned char) scancode_buffer[i].dwOfs,
scancode_buffer[i].dwData & 0x80);
}
}
my_code = hw_to_mycode[vcode];
update_shifts(ks);
SetEvent(key_input_processed_event);
_handle_key_release(my_code);
/* Windows only sends a WM_KEYUP message for the Shift keys when
both have been released. If one of the Shift keys is still reported
as down, we need to release it as well. */
if (my_code == KEY_LSHIFT && key[KEY_RSHIFT])
_al_win_kbd_handle_key_release(VK_RSHIFT);
else if (my_code == KEY_RSHIFT && key[KEY_LSHIFT])
_al_win_kbd_handle_key_release(VK_LSHIFT);
}
/* key_dinput_acquire: [window thread]
* Acquires the keyboard device. This must be called after a
* window switch for example if the device is in foreground
* cooperative level.
*/
int key_dinput_acquire(void)
static int key_winapi_init(void)
{
HRESULT hr;
BYTE keystate[256];
if (key_dinput_device) {
/* Read the current Windows keyboard state */
GetKeyboardState(keystate);
update_shifts(keystate);
hr = IDirectInputDevice_Acquire(key_dinput_device);
if (FAILED(hr)) {
_TRACE(PREFIX_E "acquire keyboard failed: %s\n", dinput_err_str(hr));
return -1;
}
/* Initialize keyboard state */
SetEvent(key_input_event);
return 0;
}
else
return -1;
}
/* key_dinput_unacquire: [window thread]
* Unacquires the keyboard device.
*/
int key_dinput_unacquire(void)
{
int key;
if (key_dinput_device) {
IDirectInputDevice_Unacquire(key_dinput_device);
/* release all keys */
for (key=0; key<256; key++)
if (key != KEY_PAUSE)
key_dinput_handle_scancode((unsigned char) key, FALSE);
return 0;
}
else
return -1;
}
/* key_dinput_exit: [primary thread]
* Shuts down the DirectInput keyboard device.
*/
static int key_dinput_exit(void)
{
if (key_dinput_device) {
/* unregister event handler first */
_win_input_unregister_event(key_input_event);
/* unacquire device */
wnd_call_proc(key_dinput_unacquire);
/* now it can be released */
IDirectInputDevice_Release(key_dinput_device);
key_dinput_device = NULL;
}
/* release DirectInput interface */
if (key_dinput) {
IDirectInput_Release(key_dinput);
key_dinput = NULL;
}
/* close event handle */
if (key_input_event) {
CloseHandle(key_input_event);
key_input_event = NULL;
}
BYTE ks[256];
GetKeyboardState(&ks[0]);
update_shifts(ks);
return 0;
}
/* get_reverse_mapping:
* Build a table that maps Allegro "scancodes" to arguments to
* GetKeyNameText() that will return the name of the key.
* The format of the argument is given in the MSDN library, e.g. the
* `lparam' argument for the WM_KEYDOWN message. Most importantly:
* bits 16-23:
* Specifies the scan code.
* bit 24:
* Specifies whether the key is an extended key, such as the right-hand
* ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard.
* The value is 1 if it is an extended key; otherwise, it is 0.
*
* We used to attempt to derive this table from `hw_to_mycode' but it is not
* straight forward. For example to get the name of the right Ctrl key we
* need to pass the same scancode as for the left Ctrl key, but with the
* extended key flag set. The values below come from printing out the
* value of the `lparam' argument for each WM_KEYDOWN message received.
* There is code in wwnd.c to help someone else do this for more keys.
*/
static void get_reverse_mapping(void)
static void key_winapi_exit(void)
{
#define REV reverse_mapping
REV[KEY_A] = 0x01E0000;
REV[KEY_B] = 0x0300000;
REV[KEY_C] = 0x02E0000;
REV[KEY_D] = 0x0200000;
REV[KEY_E] = 0x0120000;
REV[KEY_F] = 0x0210000;
REV[KEY_G] = 0x0220000;
REV[KEY_H] = 0x0230000;
REV[KEY_I] = 0x0170000;
REV[KEY_J] = 0x0240000;
REV[KEY_K] = 0x0250000;
REV[KEY_L] = 0x0260000;
REV[KEY_M] = 0x0320000;
REV[KEY_N] = 0x0310000;
REV[KEY_O] = 0x0180000;
REV[KEY_P] = 0x0190000;
REV[KEY_Q] = 0x0100000;
REV[KEY_R] = 0x0130000;
REV[KEY_S] = 0x01F0000;
REV[KEY_T] = 0x0140000;
REV[KEY_U] = 0x0160000;
REV[KEY_V] = 0x02F0000;
REV[KEY_W] = 0x0110000;
REV[KEY_X] = 0x02D0000;
REV[KEY_Y] = 0x0150000;
REV[KEY_Z] = 0x02C0000;
REV[KEY_0] = 0x00B0000;
REV[KEY_1] = 0x0020000;
REV[KEY_2] = 0x0030000;
REV[KEY_3] = 0x0040000;
REV[KEY_4] = 0x0050000;
REV[KEY_5] = 0x0060000;
REV[KEY_6] = 0x0070000;
REV[KEY_7] = 0x0080000;
REV[KEY_8] = 0x0090000;
REV[KEY_9] = 0x00A0000;
REV[KEY_0_PAD] = 0x0520000;
REV[KEY_1_PAD] = 0x04F0000;
REV[KEY_2_PAD] = 0x0500000;
REV[KEY_3_PAD] = 0x0510000;
REV[KEY_4_PAD] = 0x04B0000;
REV[KEY_5_PAD] = 0x04C0000;
REV[KEY_6_PAD] = 0x04D0000;
REV[KEY_7_PAD] = 0x0470000;
REV[KEY_8_PAD] = 0x0480000;
REV[KEY_9_PAD] = 0x0490000;
REV[KEY_F1] = 0x03B0000;
REV[KEY_F2] = 0x03C0000;
REV[KEY_F3] = 0x03D0000;
REV[KEY_F4] = 0x03E0000;
REV[KEY_F5] = 0x03F0000;
REV[KEY_F6] = 0x0400000;
REV[KEY_F7] = 0x0410000;
REV[KEY_F8] = 0x0420000;
REV[KEY_F9] = 0x0430000;
REV[KEY_F10] = 0x0440000;
REV[KEY_F11] = 0x0570000;
REV[KEY_F12] = 0x0580000;
REV[KEY_ESC] = 0x0010000;
REV[KEY_TILDE] = 0x0290000;
REV[KEY_MINUS] = 0x00C0000;
REV[KEY_EQUALS] = 0x00D0000;
REV[KEY_BACKSPACE] = 0x00E0000;
REV[KEY_TAB] = 0x00F0000;
REV[KEY_OPENBRACE] = 0x01A0000;
REV[KEY_CLOSEBRACE] = 0x01B0000;
REV[KEY_ENTER] = 0x01C0000;
REV[KEY_COLON] = 0x0270000;
REV[KEY_QUOTE] = 0x0280000;
REV[KEY_BACKSLASH] = 0x02B0000;
/* KEY_BACKSLASH2 */
REV[KEY_COMMA] = 0x0330000;
REV[KEY_STOP] = 0x0340000;
REV[KEY_SLASH] = 0x0350000;
REV[KEY_SPACE] = 0x0390000;
REV[KEY_INSERT] = 0x1520000;
REV[KEY_DEL] = 0x1530000;
REV[KEY_HOME] = 0x1470000;
REV[KEY_END] = 0x14F0000;
REV[KEY_PGUP] = 0x1490000;
REV[KEY_PGDN] = 0x1510000;
REV[KEY_LEFT] = 0x14B0000;
REV[KEY_RIGHT] = 0x14D0000;
REV[KEY_UP] = 0x1480000;
REV[KEY_DOWN] = 0x1500000;
REV[KEY_SLASH_PAD] = 0x1350000;
REV[KEY_ASTERISK] = 0x0370000;
REV[KEY_MINUS_PAD] = 0x04A0000;
REV[KEY_PLUS_PAD] = 0x04E0000;
REV[KEY_DEL_PAD] = 0x0530000;
REV[KEY_ENTER_PAD] = 0x11C0000;
/* XXX doesn't work
REV[KEY_PRTSCR] = 0x570000;
*/
REV[KEY_PAUSE] = 0x0450000;
/* XXX Japanese keys missing
REV[KEY_ABNT_C1] =
REV[KEY_YEN] =
REV[KEY_KANA] =
REV[KEY_CONVERT] =
REV[KEY_NOCONVERT] =
REV[KEY_AT] =
REV[KEY_CIRCUMFLEX] =
REV[KEY_COLON2] =
REV[KEY_KANJI] =
*/
REV[KEY_LSHIFT] = 0x02A0000;
REV[KEY_RSHIFT] = 0x0360000;
REV[KEY_LCONTROL] = 0x01D0000;
REV[KEY_RCONTROL] = 0x11D0000;
REV[KEY_ALT] = 0x0380000;
REV[KEY_ALTGR] = 0x1380000;
REV[KEY_LWIN] = 0x15B0000;
REV[KEY_RWIN] = 0x15C0000;
REV[KEY_MENU] = 0x15D0000;
REV[KEY_SCRLOCK] = 0x0460000;
REV[KEY_NUMLOCK] = 0x1450000;
REV[KEY_CAPSLOCK] = 0x03A0000;
#undef REV
/* Do nothing. */
}
/* key_dinput_init: [primary thread]
* Sets up the DirectInput keyboard device.
*/
static int key_dinput_init(void)
#define KEYBOARD_WINAPI AL_ID('W','A','P','I')
static KEYBOARD_DRIVER keyboard_winapi =
{
HRESULT hr;
HWND allegro_wnd = win_get_window();
DIPROPDWORD property_buf_size =
{
/* the header */
{
sizeof(DIPROPDWORD), // diph.dwSize
sizeof(DIPROPHEADER), // diph.dwHeaderSize
0, // diph.dwObj
DIPH_DEVICE, // diph.dwHow
},
/* the data */
DINPUT_BUFFERSIZE, // dwData
};
/* Get DirectInput interface */
hr = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER, &IID_IDirectInput, &key_dinput);
if (FAILED(hr))
goto Error;
hr = IDirectInput_Initialize(key_dinput, allegro_inst, DIRECTINPUT_VERSION);
if (FAILED(hr))
goto Error;
/* Create the keyboard device */
hr = IDirectInput_CreateDevice(key_dinput, &GUID_SysKeyboard, &key_dinput_device, NULL);
if (FAILED(hr))
goto Error;
/* Set data format */
hr = IDirectInputDevice_SetDataFormat(key_dinput_device, &c_dfDIKeyboard);
if (FAILED(hr))
goto Error;
/* Set buffer size */
hr = IDirectInputDevice_SetProperty(key_dinput_device, DIPROP_BUFFERSIZE, &property_buf_size.diph);
if (FAILED(hr))
goto Error;
/* Set cooperative level */
hr = IDirectInputDevice_SetCooperativeLevel(key_dinput_device, allegro_wnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (FAILED(hr))
goto Error;
/* Enable event notification */
key_input_event = CreateEvent(NULL, FALSE, FALSE, NULL);
hr = IDirectInputDevice_SetEventNotification(key_dinput_device, key_input_event);
if (FAILED(hr))
goto Error;
/* Register event handler */
if (_win_input_register_event(key_input_event, key_dinput_handle) != 0)
goto Error;
get_reverse_mapping();
/* Acquire the device */
wnd_call_proc(key_dinput_acquire);
return 0;
Error:
key_dinput_exit();
return -1;
}
/* key_directx_init: [primary thread]
*/
static int key_directx_init(void)
{
/* keyboard input is handled by the window thread */
key_input_processed_event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (key_dinput_init() != 0) {
/* something has gone wrong */
_TRACE(PREFIX_E "keyboard handler init failed\n");
CloseHandle(key_input_processed_event);
return -1;
}
/* the keyboard handler has successfully set up */
_TRACE(PREFIX_I "keyboard handler starts\n");
return 0;
}
/* key_directx_exit: [primary thread]
*/
static void key_directx_exit(void)
{
if (key_dinput_device) {
/* command keyboard handler shutdown */
_TRACE(PREFIX_I "keyboard handler exits\n");
key_dinput_exit();
/* now we can free all resources */
CloseHandle(key_input_processed_event);
}
}
/* key_directx_wait_for_input: [primary thread]
*/
static void key_directx_wait_for_input(void)
{
WaitForSingleObject(key_input_processed_event, INFINITE);
}
/* static void key_directx_stop_wait: [primary thread]
*/
static void key_directx_stop_wait(void)
{
SetEvent(key_input_processed_event);
}
/* scancode_to_name:
* Converts the given scancode to a description of the key.
*/
static AL_CONST char *key_directx_scancode_to_name(const int scancode)
{
static char name[256];
TCHAR str[256];
WCHAR wstr[256];
ASSERT(scancode >= 0 && scancode < KEY_MAX);
if (GetKeyNameText(reverse_mapping[scancode], str, sizeof str)) {
/* let Windows translate from the current encoding into UTF16 */
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstr, sizeof wstr);
/* translate from utf16 to Allegro's current encoding */
uconvert((char *)wstr, U_UNICODE, name, U_CURRENT, sizeof name);
/* why oh why doesn't everybody just use UTF8/16 */
return name;
}
else
return _keyboard_common_names[scancode];
}
static KEYBOARD_DRIVER keyboard_directx =
{
KEYBOARD_DIRECTX,
KEYBOARD_WINAPI,
0,
0,
"DirectInput keyboard",
"WinAPI keyboard",
1,
key_directx_init,
key_directx_exit,
NULL, NULL, NULL,
key_directx_wait_for_input,
key_directx_stop_wait,
key_winapi_init,
key_winapi_exit,
NULL,
key_directx_scancode_to_name
NULL,
NULL,
NULL,
NULL,
NULL,
NULL
};
_DRIVER_INFO _keyboard_driver_list[] =
{
{KEYBOARD_DIRECTX, &keyboard_directx, TRUE},
{KEYBOARD_WINAPI, &keyboard_winapi, TRUE},
{0, NULL, 0}
};

View File

@ -349,8 +349,6 @@ static void sys_directx_save_console_state(void)
static void sys_directx_restore_console_state(void)
{
HWND allegro_wnd = win_get_window();
/* unacquire input devices */
wnd_schedule_proc(key_dinput_unacquire);
/* reset switch mode */
_win_reset_switch_mode();

View File

@ -95,6 +95,9 @@ void _al_win_mouse_handle_button(HWND hwnd, int button, BOOL down, int x, int y,
void _al_win_mouse_handle_wheel(HWND hwnd, int z, BOOL abs);
void _al_win_mouse_handle_move(HWND hwnd, int x, int y);
/* In wkeybd.c */
void _al_win_kbd_handle_key_press(int scode, int vcode, BOOL repeated);
void _al_win_kbd_handle_key_release(int vcode);
/* init_window_modules:
@ -185,18 +188,6 @@ static LRESULT CALLBACK directx_wnd_proc(HWND wnd, UINT message, WPARAM wparam,
return retval;
}
/* See get_reverse_mapping() in wkeybd.c to see what this is for. */
if (FALSE && (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)) {
static char name[256];
TCHAR str[256];
WCHAR wstr[256];
GetKeyNameText(lparam, str, sizeof str);
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, str, -1, wstr, sizeof wstr);
uconvert((char *)wstr, U_UNICODE, name, U_CURRENT, sizeof name);
_TRACE(PREFIX_I" key[%s] = 0x%08lx;\n", name, lparam & 0x1ff0000);
}
switch (message) {
case WM_CREATE:
@ -294,17 +285,6 @@ static LRESULT CALLBACK directx_wnd_proc(HWND wnd, UINT message, WPARAM wparam,
}
break;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
/* Disable the default message-based key handler
* in order to prevent conflicts on NT kernels.
*/
if (!user_wnd_proc || _keyboard_installed)
return 0;
break;
case WM_SYSCOMMAND:
if (wparam == SC_MONITORPOWER || wparam == SC_SCREENSAVE) {
if (_screensaver_policy == ALWAYS_DISABLED
@ -393,6 +373,30 @@ static LRESULT CALLBACK directx_wnd_proc(HWND wnd, UINT message, WPARAM wparam,
break;
}
case WM_SYSKEYDOWN: {
int vcode = wparam;
BOOL repeated = (lparam >> 30) & 0x1;
_al_win_kbd_handle_key_press(0, vcode, repeated);
return 0;
}
case WM_KEYDOWN: {
int vcode = wparam;
int scode = (lparam >> 16) & 0xff;
BOOL repeated = (lparam >> 30) & 0x1;
/* We can't use TranslateMessage() because we don't know if it will
produce a WM_CHAR or not. */
_al_win_kbd_handle_key_press(scode, vcode, repeated);
return 0;
}
case WM_SYSKEYUP:
case WM_KEYUP: {
int vcode = wparam;
_al_win_kbd_handle_key_release(vcode);
return 0;
}
}
/* pass message to default window proc */
@ -786,13 +790,3 @@ void win_set_wnd_create_proc(HWND (*proc)(WNDPROC))
{
wnd_create_proc = proc;
}
/* win_grab_input:
* Grabs the input devices.
*/
void win_grab_input(void)
{
wnd_schedule_proc(key_dinput_acquire);
}