Windows2003-3790/multimedia/directx/dinput/dx8/dll/digenk.c
2020-09-30 16:53:55 +02:00

1887 lines
63 KiB
C

/*****************************************************************************
*
* DIGenK.c
*
* Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
*
* Abstract:
*
* Generic IDirectInputDevice callback for keyboard.
*
* Contents:
*
* CKbd_CreateInstance
*
*****************************************************************************/
#include "dinputpr.h"
/*****************************************************************************
*
* Some holes in windows.h on NT platforms.
*
*****************************************************************************/
#ifndef VK_KANA
#define VK_KANA 0x15
#endif
/*****************************************************************************
*
* The sqiffle for this file.
*
*****************************************************************************/
#define sqfl sqflKbd
/*****************************************************************************
*
* Declare the interfaces we will be providing.
*
* WARNING! If you add a secondary interface, you must also change
* CKbd_New!
*
*****************************************************************************/
Primary_Interface(CKbd, IDirectInputDeviceCallback);
/*****************************************************************************
*
* @doc INTERNAL
*
* @struct KBDSTAT |
*
* Internal instantaneous keyboard status information.
*
* @field BYTE | rgb[DIKBD_CKEYS] |
*
* Array of key states, one for each logical key.
*
*****************************************************************************/
typedef struct KBDSTAT {
BYTE rgb[DIKBD_CKEYS];
} KBDSTAT, *PKBDSTAT;
/*****************************************************************************
*
* @doc EXTERNAL
*
* @topic Special remarks on keyboard scan codes |
*
* There are several aspects of keyboards which applications should
* be aware of. Applications are encouraged to allow users to
* reconfigure keyboard action keys to suit the physical keyboard
* layout.
*
* For the purposes of this discussion, the baseline keyboard
* shall be the US PC Enhanced keyboard. When a key is described
* as "missing", it means that the key is present on the US PC
* Enhanced keyboard but not on the keyboard under discussion.
* When a key is described as "added", it means that the key is
* absent on the US PC Enhanced keyboard but present on the
* keyboard under discussion.
*
* Not all PC Enhanced keyboards support the new Windows keys
* (DIK_LWIN, DIK_RWIN, and DIK_APPS). There is no way to
* determine whether the keys are physically available.
*
* Note that there is no DIK_PAUSE key code. The PC Enhanced
* keyboard does not generate a separate DIK_PAUSE scan code;
* rather, it synthesizes a "Pause" from the DIK_LCONTROL and
* DIK_NUMLOCK scan codes.
*
* Keyboards for laptops or other reduced-footprint computers
* frequently do not implement a full set of keys. Instead,
* some keys (typically numeric keypad keys) are multiplexed
* with other keys, selected by an auxiliary "mode" key which
* does not generate a separate scan code.
*
* If the keyboard subtype indicates a PC XT or PC AT keyboard,
* then the following keys are not available:
* DIK_F11, DIK_F12, and all the extended keys (DIK_* values
* greater than or equal to 0x80). Furthermore, the PC XT
* keyboard lacks DIK_SYSRQ.
*
* Japanese keyboards contain a substantially different set of
* keys from US keyboards. The following keyboard scan codes
* are not available on Japanese keyboards:
* DIK_EQUALS, DIK_APOSTROPHE, DIK_GRAVE, DIK_NUMPADENTER,
* DIK_RCONTROL, DIK_RMENU. Furthermore, most Japanese
* keyboards do not support DIK_RSHIFT. (It is customary
* to use DIK_NUMPADEQUAL in place of DIK_RSHIFT.)
*
* Japanese keyboards contain the following additional keys:
* DIK_F14, DIK_NUMPADEQUAL, DIK_CIRCUMFLEX, DIK_AT, DIK_COLON,
* DIK_UNDERLINE, DIK_XFER, DIK_NFER, DIK_STOP, DIK_KANA, and
* DIK_NUMPADCOMMA.
*
* Note that on Japanese keyboards, the DIK_CAPSLOCK and
* DIK_KANA keys are toggle buttons and not push buttons.
* They generate a down event
* when first pressed, then generate an up event when pressed a
* second time.
* Note that on Windows 2000, the DIK_KANJI key is also treated as a
* toggle.
*
*****************************************************************************/
/*****************************************************************************
*
* @doc INTERNAL
*
* @global KBDTYPE | c_rgktWhich[] |
*
* Array that describes which keyboards support which keys.
*
* The list is optimistic. If any keyboard of the indicated
* type supports the key, then we list it.
*
* Items marks "available for NEC" are keys which are extremely
* unlikely to be used in future versions of the Enhanced
* keyboard and therefore can be used as ersatz scan codes for
* NEC-only keys.
*
* Note: Kana and CAPSLOCK are toggle buttons on NEC keyboards.
* Note: Kana, Kanji and CAPSLOCK are toggle buttons on all NT JPN
* keyboards.
*
*****************************************************************************/
BYTE g_rgbKbdRMap[DIKBD_CKEYS];
typedef BYTE KBDTYPE;
#define KBDTYPE_XT 0x01 /* Key exists on XT class keyboard */
#define KBDTYPE_AT 0x02 /* Key exists on AT class keyboard */
#define KBDTYPE_ENH 0x04 /* Key exists on Enhanced keyboard */
#define KBDTYPE_NEC 0x08 /* Key exists on NEC keyboard */
#define KBDTYPE_ANYKBD 0x0F /* Key exists somewhere in the world */
#define KBDTYPE_NECTGL 0x10 /* Is a toggle-key on NEC keyboard */
#define KBDTYPE_NTTGL 0x20 /* Is a toggle-key on an NT FE keyboard */
#pragma BEGIN_CONST_DATA
#define XT KBDTYPE_XT |
#define AT KBDTYPE_XT |
#define ENH KBDTYPE_ENH |
#define NEC KBDTYPE_NEC |
#define NECTGL KBDTYPE_NECTGL |
#define NTTGL KBDTYPE_NTTGL |
KBDTYPE c_rgktWhich[] = {
0, /* 0x00 - <undef> */
XT AT ENH NEC 0, /* 0x01 - Esc */
XT AT ENH NEC 0, /* 0x02 - 1 */
XT AT ENH NEC 0, /* 0x03 - 2 */
XT AT ENH NEC 0, /* 0x04 - 3 */
XT AT ENH NEC 0, /* 0x05 - 4 */
XT AT ENH NEC 0, /* 0x06 - 5 */
XT AT ENH NEC 0, /* 0x07 - 6 */
XT AT ENH NEC 0, /* 0x08 - 7 */
XT AT ENH NEC 0, /* 0x09 - 8 */
XT AT ENH NEC 0, /* 0x0A - 9 */
XT AT ENH NEC 0, /* 0x0B - 0 */
XT AT ENH NEC 0, /* 0x0C - - */
XT AT ENH 0, /* 0x0D - = */
XT AT ENH NEC 0, /* 0x0E - BkSp */
XT AT ENH NEC 0, /* 0x0F - Tab */
XT AT ENH NEC 0, /* 0x10 - Q */
XT AT ENH NEC 0, /* 0x11 - W */
XT AT ENH NEC 0, /* 0x12 - E */
XT AT ENH NEC 0, /* 0x13 - R */
XT AT ENH NEC 0, /* 0x14 - T */
XT AT ENH NEC 0, /* 0x15 - Y */
XT AT ENH NEC 0, /* 0x16 - U */
XT AT ENH NEC 0, /* 0x17 - I */
XT AT ENH NEC 0, /* 0x18 - O */
XT AT ENH NEC 0, /* 0x19 - P */
XT AT ENH NEC 0, /* 0x1A - [ */
XT AT ENH NEC 0, /* 0x1B - ] */
XT AT ENH NEC 0, /* 0x1C - Enter */
XT AT ENH NEC 0, /* 0x1D - LCtrl */
XT AT ENH NEC 0, /* 0x1E - A */
XT AT ENH NEC 0, /* 0x1F - S */
XT AT ENH NEC 0, /* 0x20 - D */
XT AT ENH NEC 0, /* 0x21 - F */
XT AT ENH NEC 0, /* 0x22 - G */
XT AT ENH NEC 0, /* 0x23 - H */
XT AT ENH NEC 0, /* 0x24 - J */
XT AT ENH NEC 0, /* 0x25 - K */
XT AT ENH NEC 0, /* 0x26 - L */
XT AT ENH NEC 0, /* 0x27 - ; */
XT AT ENH 0, /* 0x28 - ' */
XT AT ENH 0, /* 0x29 - ` */
XT AT ENH NEC 0, /* 0x2A - LShift */
XT AT ENH NEC 0, /* 0x2B - \ */
XT AT ENH NEC 0, /* 0x2C - Z */
XT AT ENH NEC 0, /* 0x2D - X */
XT AT ENH NEC 0, /* 0x2E - C */
XT AT ENH NEC 0, /* 0x2F - V */
XT AT ENH NEC 0, /* 0x30 - B */
XT AT ENH NEC 0, /* 0x31 - N */
XT AT ENH NEC 0, /* 0x32 - M */
XT AT ENH NEC 0, /* 0x33 - , */
XT AT ENH NEC 0, /* 0x34 - . */
XT AT ENH NEC 0, /* 0x35 - / */
XT AT ENH NEC 0, /* 0x36 - RShift */
XT AT ENH NEC 0, /* 0x37 - Num* */
XT AT ENH NEC 0, /* 0x38 - LAlt */
XT AT ENH NEC 0, /* 0x39 - Space */
XT AT ENH NEC NECTGL NTTGL 0, /* 0x3A - CapsLock */
XT AT ENH NEC 0, /* 0x3B - F1 */
XT AT ENH NEC 0, /* 0x3C - F2 */
XT AT ENH NEC 0, /* 0x3D - F3 */
XT AT ENH NEC 0, /* 0x3E - F4 */
XT AT ENH NEC 0, /* 0x3F - F5 */
XT AT ENH NEC 0, /* 0x40 - F6 */
XT AT ENH NEC 0, /* 0x41 - F7 */
XT AT ENH NEC 0, /* 0x42 - F8 */
XT AT ENH NEC 0, /* 0x43 - F9 */
XT AT ENH NEC 0, /* 0x44 - F10 */
XT AT ENH 0, /* 0x45 - NumLock */
XT AT ENH 0, /* 0x46 - ScrLock */
XT AT ENH NEC 0, /* 0x47 - Numpad7 */
XT AT ENH NEC 0, /* 0x48 - Numpad8 */
XT AT ENH NEC 0, /* 0x49 - Numpad9 */
XT AT ENH NEC 0, /* 0x4A - Numpad- */
XT AT ENH NEC 0, /* 0x4B - Numpad4 */
XT AT ENH NEC 0, /* 0x4C - Numpad5 */
XT AT ENH NEC 0, /* 0x4D - Numpad6 */
XT AT ENH NEC 0, /* 0x4E - Numpad+ */
XT AT ENH NEC 0, /* 0x4F - Numpad1 */
XT AT ENH NEC 0, /* 0x50 - Numpad2 */
XT AT ENH NEC 0, /* 0x51 - Numpad3 */
XT AT ENH NEC 0, /* 0x52 - Numpad0 */
XT AT ENH NEC 0, /* 0x53 - Numpad. */
0, /* 0x54 - <undef> */
0, /* 0x55 - <undef> */
ENH 0, /* 0x56 - <undef>. On UK/Germany keyboards, it is <, > and |. */
ENH NEC 0, /* 0x57 - F11 */
ENH NEC 0, /* 0x58 - F12 */
0, /* 0x59 - <undef> */
0, /* 0x5A - <undef> */
0, /* 0x5B - <undef> */
0, /* 0x5C - <undef> */
0, /* 0x5D - <undef> */
0, /* 0x5E - <undef> */
0, /* 0x5F - <undef> */
0, /* 0x60 - <undef> */
0, /* 0x61 - <undef> */
0, /* 0x62 - <undef> */
0, /* 0x63 - <undef> */
NEC 0, /* 0x64 - F13 */
NEC 0, /* 0x65 - F14 */
NEC 0, /* 0x66 - F15 */
0, /* 0x67 - <undef> */
0, /* 0x68 - <undef> */
0, /* 0x69 - <undef> */
0, /* 0x6A - <undef> */
0, /* 0x6B - <undef> */
0, /* 0x6C - <undef> */
0, /* 0x6D - <undef> */
0, /* 0x6E - <undef> */
0, /* 0x6F - <undef> */
NEC NECTGL NTTGL 0, /* 0x70 - Kana */
0, /* 0x71 - <undef> */
0, /* 0x72 - <undef> */
ENH 0, /* 0x73 - <undef>. On Portugese (Brazilian) keyboard, it is /, ? */
0, /* 0x74 - <undef> */
0, /* 0x75 - <undef> */
0, /* 0x76 - <undef> */
0, /* 0x77 - <undef> */
0, /* 0x78 - <undef> */
NEC 0, /* 0x79 - Convert */
0, /* 0x7A - <undef> */
NEC 0, /* 0x7B - Nfer */
0, /* 0x7C - <undef> */
NEC 0, /* 0x7D - Yen */
ENH 0, /* 0x7E - <undef>. On Portugese (Brazilian) keyboard, it is keypad . */
0, /* 0x7F - <undef> */
/* Extended keycodes go here */
0, /* 0x80 - <undef> */
0, /* 0x81 - <undef> */
0, /* 0x82 - <undef> */
0, /* 0x83 - <undef> */
0, /* 0x84 - <undef> */
0, /* 0x85 - <undef> */
0, /* 0x86 - <undef> */
0, /* 0x87 - <undef> */
0, /* 0x88 - <undef> */
0, /* 0x89 - <undef> */
0, /* 0x8A - <undef> */
0, /* 0x8B - <undef> */
0, /* 0x8C - <undef> */
NEC 0, /* 0x8D - Num= */
0, /* 0x8E - <undef> */
0, /* 0x8F - <undef> */
ENH NEC 0, /* 0x90 - ^ */ ///Prev Track
NEC 0, /* 0x91 - @ */
NEC 0, /* 0x92 - : */
NEC 0, /* 0x93 - _ */
NEC NTTGL 0, /* 0x94 - Xfer - AKA Kanji */
NEC 0, /* 0x95 - Stop */
NEC 0, /* 0x96 - AX */
NEC 0, /* 0x97 - Unlabel'd*/
0, /* 0x98 - <undef> */ /* available for NEC */
ENH 0, /* 0x99 - <undef> */ /* available for NEC */ ///Next Track
0, /* 0x9A - <undef> */
0, /* 0x9B - <undef> */
ENH 0, /* 0x9C - NumEnter */
ENH 0, /* 0x9D - RCtrl */
0, /* 0x9E - <undef> */ /* available for NEC */
0, /* 0x9F - <undef> */ /* available for NEC */
ENH 0, /* 0xA0 - <undef> */ /* available for NEC */ ///Mute
ENH 0, /* 0xA1 - <undef> */ /* available for NEC */ ///Calculator
ENH 0, /* 0xA2 - <undef> */ /* available for NEC */ ///Play/Pause
0, /* 0xA3 - <undef> */ /* available for NEC */
ENH 0, /* 0xA4 - <undef> */ /* available for NEC */ ///Stop
0, /* 0xA5 - <undef> */ /* available for NEC */
0, /* 0xA6 - <undef> */ /* available for NEC */
0, /* 0xA7 - <undef> */
0, /* 0xA8 - <undef> */
0, /* 0xA9 - <undef> */
0, /* 0xAA - <undef> */
0, /* 0xAB - <undef> */
0, /* 0xAC - <undef> */ /* available for NEC */
0, /* 0xAD - <undef> */ /* available for NEC */
ENH 0, /* 0xAE - <undef> */ /* available for NEC */ ///Volume -
0, /* 0xAF - <undef> */ /* available for NEC */
ENH 0, /* 0xB0 - <undef> */ /* available for NEC */ ///Volume +
0, /* 0xB1 - <undef> */ /* available for NEC */
ENH 0, /* 0xB2 - <undef> */ /* available for NEC */ ///Web/Home
NEC 0, /* 0xB3 - Num, */
0, /* 0xB4 - <undef> */
ENH NEC 0, /* 0xB5 - Num/ */
0, /* 0xB6 - <undef> */
AT ENH NEC 0, /* 0xB7 - SysRq */
ENH 0, /* 0xB8 - RAlt */
0, /* 0xB9 - <undef> */
0, /* 0xBA - <undef> */
0, /* 0xBB - <undef> */
0, /* 0xBC - <undef> */
0, /* 0xBD - <undef> */
0, /* 0xBE - <undef> */
0, /* 0xBF - <undef> */
0, /* 0xC0 - <undef> */
0, /* 0xC1 - <undef> */
0, /* 0xC2 - <undef> */
0, /* 0xC3 - <undef> */
0, /* 0xC4 - <undef> */
ENH 0, /* 0xC5 - Pause */
0, /* 0xC6 - <undef> */
ENH NEC 0, /* 0xC7 - Home */
ENH NEC 0, /* 0xC8 - UpArrow */
ENH NEC 0, /* 0xC9 - PgUp */
0, /* 0xCA - <undef> */
ENH NEC 0, /* 0xCB - LtArrow */
0, /* 0xCC - <undef> */
ENH NEC 0, /* 0xCD - RtArrow */
0, /* 0xCE - <undef> */
ENH NEC 0, /* 0xCF - End */
ENH NEC 0, /* 0xD0 - DnArrow */
ENH NEC 0, /* 0xD1 - PgDn */
ENH NEC 0, /* 0xD2 - Insert */
ENH NEC 0, /* 0xD3 - Delete */
0, /* 0xD4 - <undef> */
0, /* 0xD5 - <undef> */
0, /* 0xD6 - <undef> */
0, /* 0xD7 - <undef> */
0, /* 0xD8 - <undef> */
0, /* 0xD9 - <undef> */
0, /* 0xDA - <undef> */
ENH NEC 0, /* 0xDB - LWin */
ENH NEC 0, /* 0xDC - RWin */
ENH NEC 0, /* 0xDD - AppMenu */
ENH 0, /* 0xDE - Power */
ENH 0, /* 0xDF - Sleep */
0, /* 0xE0 - <undef> */
0, /* 0xE1 - <undef> */
0, /* 0xE2 - <undef> */
ENH 0, /* 0xE3 - Wake */
0, /* 0xE4 - <undef> */
ENH 0, /* 0xE5 - <undef> */ ///Search
ENH 0, /* 0xE6 - <undef> */ ///Favorites
ENH 0, /* 0xE7 - <undef> */ ///Refresh
ENH 0, /* 0xE8 - <undef> */ ///Stop
ENH 0, /* 0xE9 - <undef> */ ///Forward
ENH 0, /* 0xEA - <undef> */ ///Back
ENH 0, /* 0xEB - <undef> */ ///My Computer
ENH 0, /* 0xEC - <undef> */ ///Mail
ENH 0, /* 0xED - <undef> */ ///Media
0, /* 0xEE - <undef> */
0, /* 0xEF - <undef> */
0, /* 0xF0 - <undef> */
0, /* 0xF1 - <undef> */
0, /* 0xF2 - <undef> */
0, /* 0xF3 - <undef> */
0, /* 0xF4 - <undef> */
0, /* 0xF5 - <undef> */
0, /* 0xF6 - <undef> */
0, /* 0xF7 - <undef> */
0, /* 0xF8 - <undef> */
0, /* 0xF9 - <undef> */
0, /* 0xFA - <undef> */
0, /* 0xFB - <undef> */
0, /* 0xFC - <undef> */
0, /* 0xFD - <undef> */
0, /* 0xFE - <undef> */
0, /* 0xFF - <undef> */
};
#undef XT
#undef AT
#undef ENH
#undef NEC
#if 0
DWORD dwSpecKeys[] = {0x56, 0x64, 0x65, 0x66, 0x73, 0x7e, 0x90, 0x99,
0xa0, 0xa1, 0xa2, 0xa4, 0xae, 0xb0, 0xb2, 0xde,
0xdf, 0xe3, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
0xeb, 0xec, 0xed };
#endif
/*****************************************************************************
*
* @doc INTERNAL
*
* @struct CKbd |
*
* The <i IDirectInputDeviceCallback> object for the
* generic keyboard.
*
* @field IDirectInputDeviceCalllback | didc |
*
* The object (containing vtbl).
*
* @field PMKBDSTAT | pksPhys |
*
* Pointer to physical keyboard status information kept down in the
* VxD.
*
* @field VXDINSTANCE * | pvi |
*
* The DirectInput instance handle.
*
* @field DWORD | dwKbdType |
*
* The device subtype for this keyboard.
*
* @field DWORD | flEmulation |
*
* The emulation flags forced by the application. If any of
* these flags is set (actually, at most one will be set), then
* we are an alias device.
*
* @field DIDATAFORMAT | df |
*
* The dynamically-generated data format based on the
* keyboard type.
*
* @field DIOBJECTDATAFORMAT | rgodf[] |
*
* Object data format table generated as part of the
* <e CKbd.df>.
*
* @comm
*
* It is the caller's responsibility to serialize access as
* necessary.
*
*****************************************************************************/
typedef struct CKbd {
/* Supported interfaces */
IDirectInputDeviceCallback dcb;
PKBDSTAT pksPhys;
VXDINSTANCE *pvi;
DWORD dwKbdType;
DWORD flEmulation;
DIDATAFORMAT df;
DIOBJECTDATAFORMAT rgodf[DIKBD_CKEYS];
} CKbd, DK, *PDK;
#define ThisClass CKbd
#define ThisInterface IDirectInputDeviceCallback
#define riidExpected &IID_IDirectInputDeviceCallback
/*****************************************************************************
*
* CKbd::QueryInterface (from IUnknown)
* CKbd::AddRef (from IUnknown)
* CKbd::Release (from IUnknown)
*
*****************************************************************************/
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | QueryInterface |
*
* Gives a client access to other interfaces on an object.
*
* @parm IN REFIID | riid |
*
* The requested interface's IID.
*
* @parm OUT LPVOID * | ppvObj |
*
* Receives a pointer to the obtained interface.
*
* @returns
*
* Returns a COM error code.
*
* @xref OLE documentation for <mf IUnknown::QueryInterface>.
*
*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | AddRef |
*
* Increments the reference count for the interface.
*
* @returns
*
* Returns the object reference count.
*
* @xref OLE documentation for <mf IUnknown::AddRef>.
*
*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | Release |
*
* Decrements the reference count for the interface.
* If the reference count on the object falls to zero,
* the object is freed from memory.
*
* @returns
*
* Returns the object reference count.
*
* @xref OLE documentation for <mf IUnknown::Release>.
*
*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | QIHelper |
*
* We don't have any dynamic interfaces and simply forward
* to <f Common_QIHelper>.
*
* @parm IN REFIID | riid |
*
* The requested interface's IID.
*
* @parm OUT LPVOID * | ppvObj |
*
* Receives a pointer to the obtained interface.
*
*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | AppFinalize |
*
* We don't have any weak pointers, so we can just
* forward to <f Common_Finalize>.
*
* @parm PV | pvObj |
*
* Object being released from the application's perspective.
*
*****************************************************************************/
#ifdef DEBUG
Default_QueryInterface(CKbd)
Default_AddRef(CKbd)
Default_Release(CKbd)
#else
#define CKbd_QueryInterface Common_QueryInterface
#define CKbd_AddRef Common_AddRef
#define CKbd_Release Common_Release
#endif
#define CKbd_QIHelper Common_QIHelper
#define CKbd_AppFinalize Common_AppFinalize
/*****************************************************************************
*
* @doc INTERNAL
*
* @func void | CKbd_Finalize |
*
* Releases the resources of the device.
*
* @parm PV | pvObj |
*
* Object being released. Note that it may not have been
* completely initialized, so everything should be done
* carefully.
*
*****************************************************************************/
void INTERNAL
CKbd_Finalize(PV pvObj)
{
PDK this = pvObj;
if (this->pvi) {
HRESULT hres;
hres = Hel_DestroyInstance(this->pvi);
AssertF(SUCCEEDED(hres));
}
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @func int | WrappedGetKeyboardType |
*
* GetKeyboardType but wrapped in DEBUG for registry overrides.
*
* @parm int | nTypeFlag |
*
* Which data to return. Only 0, 1 and 2 are supported
*
* @returns
*
* int value requested
*
*****************************************************************************/
#ifndef DEBUG
#ifdef USE_WM_INPUT
#define WrappedGetKeyboardType(x) DIRaw_GetKeyboardType(x)
#else
#define WrappedGetKeyboardType(x) GetKeyboardType(x)
#endif
#else
int INTERNAL WrappedGetKeyboardType
(
int nTypeFlag
)
{
TCHAR ValueName[2];
int TypeRes;
#ifdef USE_WM_INPUT
TypeRes = DIRaw_GetKeyboardType( nTypeFlag );
#else
TypeRes = GetKeyboardType( nTypeFlag );
#endif
if( nTypeFlag < 10 )
{
ValueName[0] = TEXT( '0' ) + nTypeFlag;
ValueName[1] = TEXT( '\0' );
TypeRes = (int)RegQueryDIDword( REGSTR_KEY_KEYBTYPE, ValueName, (DWORD)TypeRes );
SquirtSqflPtszV(sqfl | sqflTrace,
TEXT( "DINPUT: GetKeyboardType(%d) returning 0x%08x" ),
nTypeFlag, TypeRes );
}
else
{
RPF( "Somebody is passing %d to WrappedGetKeyboardType", nTypeFlag );
}
return TypeRes;
}
#endif
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | Acquire |
*
* Tell the device driver to begin data acquisition.
*
* It is the caller's responsibility to have set the
* data format before obtaining acquisition.
*
* @returns
*
* Returns a COM error code. The following error codes are
* intended to be illustrative and not necessarily comprehensive.
*
* <c DI_OK> = <c S_OK>: The operation completed successfully.
*
* <c S_FALSE>: The operation was begun and should be completed
* by the caller by communicating with the <t VXDINSTANCE>.
*
*****************************************************************************/
STDMETHODIMP
CKbd_Acquire(PDICB pdcb)
{
VXDDWORDDATA vdd;
PDK this;
HRESULT hres;
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
/*
* Propagate the state of the potential toggle keys down to
* the VxD. This also alerts the VxD that acquisition is coming,
* so it can reset the state tables if necessary.
*/
vdd.pvi = this->pvi;
vdd.dw = 0;
if( WrappedGetKeyboardType(0) == 7 )
{
/*
* Let the keyboard driver know that this is an FE keyboard
*/
vdd.dw |= 16;
if (GetAsyncKeyState(VK_KANA) < 0) {
vdd.dw |= 1;
}
if (GetAsyncKeyState(VK_CAPITAL) < 0) {
vdd.dw |= 2;
}
if (GetAsyncKeyState(VK_KANJI) < 0) {
vdd.dw |= 8;
}
}
if( this->pvi->fl & VIFL_CAPTURED )
{
vdd.dw |= 4; // Tell the keyboard driver to pre-acquire hooks
}
hres = Hel_Kbd_InitKeys(&vdd);
if( this->pvi->fl & VIFL_CAPTURED )
{
/*
* A bit of work needs to be done at ring 3 now.
* Try to clear any key that is set. Start with VK_BACK as mouse
* buttons and undefined things go before.
* This still covers a lot of undefined VKs but we're less likely
* to do damage clearing something that was undefined than leaving
* keys uncleared.
*/
BYTE vk;
for( vk=VK_BACK; vk<VK_OEM_CLEAR; vk++ )
{
if( ( vk == VK_KANA ) || ( vk == VK_KANJI ) || ( vk == VK_CAPITAL ) )
{
continue;
}
if(GetAsyncKeyState(vk) < 0)
{
keybd_event( vk, 0, KEYEVENTF_KEYUP, 0 );
}
}
}
return S_FALSE;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | GetInstance |
*
* Obtains the DirectInput instance handle.
*
* @parm OUT PPV | ppvi |
*
* Receives the instance handle.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetInstance(PDICB pdcb, PPV ppvi)
{
HRESULT hres;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetInstance, (_ "p", pdcb));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi);
*ppvi = (PV)this->pvi;
hres = S_OK;
ExitOleProcPpvR(ppvi);
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | GetDataFormat |
*
* Obtains the device's preferred data format.
*
* @parm OUT LPDIDEVICEFORMAT * | ppdf |
*
* <t LPDIDEVICEFORMAT> to receive pointer to device format.
*
* @returns
*
* Returns a COM error code. The following error codes are
* intended to be illustrative and not necessarily comprehensive.
*
* <c DI_OK> = <c S_OK>: The operation completed successfully.
*
* <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
* <p lpmdr> parameter is not a valid pointer.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetDataFormat(PDICB pdcb, LPDIDATAFORMAT *ppdf)
{
HRESULT hres;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetDataFormat,
(_ "p", pdcb));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
*ppdf = &this->df;
hres = S_OK;
ExitOleProcPpvR(ppdf);
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | GetDeviceInfo |
*
* Obtain general information about the device.
*
* @parm OUT LPDIDEVICEINSTANCEW | pdiW |
*
* <t DEVICEINSTANCE> to be filled in. The
* <e DEVICEINSTANCE.dwSize> and <e DEVICEINSTANCE.guidInstance>
* have already been filled in.
*
* Secret convenience: <e DEVICEINSTANCE.guidProduct> is equal
* to <e DEVICEINSTANCE.guidInstance>.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetDeviceInfo(PDICB pdcb, LPDIDEVICEINSTANCEW pdiW)
{
HRESULT hres;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetDeviceInfo,
(_ "pp", pdcb, pdiW));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
AssertF(IsValidSizeDIDEVICEINSTANCEW(pdiW->dwSize));
AssertF(IsEqualGUID(&GUID_SysKeyboard , &pdiW->guidInstance) ||
IsEqualGUID(&GUID_SysKeyboardEm , &pdiW->guidInstance) ||
IsEqualGUID(&GUID_SysKeyboardEm2, &pdiW->guidInstance));
pdiW->guidProduct = GUID_SysKeyboard;
pdiW->dwDevType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_KEYBOARD,
this->dwKbdType);
LoadStringW(g_hinst, IDS_STDKEYBOARD, pdiW->tszProductName, cA(pdiW->tszProductName));
LoadStringW(g_hinst, IDS_STDKEYBOARD, pdiW->tszInstanceName, cA(pdiW->tszInstanceName));
hres = S_OK;
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | GetProperty |
*
* Retrieve a device property.
*
* @parm IN LPCDIPROPINFO | ppropi |
*
* Information describing the property being retrieved.
*
* @parm LPDIPROPHEADER | pdiph |
*
* Structure to receive property value.
*
* @returns
*
* <c S_OK> if the operation completed successfully.
*
* <c E_NOTIMPL> nothing happened. The caller will do
* the default thing in response to <c E_NOTIMPL>.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph)
{
HRESULT hres = E_NOTIMPL;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetProperty,
(_ "pxxp", pdcb, ppropi->pguid, ppropi->iobj, pdiph));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
switch((DWORD)(UINT_PTR)(ppropi->pguid))
{
case (DWORD)(UINT_PTR)(DIPROP_KEYNAME):
{
LPDIPROPSTRING pdipstr = (PV)pdiph;
memset( pdipstr->wsz, 0, cbX(pdipstr->wsz) );
hres = DIGetKeyNameText( ppropi->iobj, ppropi->dwDevType, pdipstr->wsz, cA(pdipstr->wsz) );
}
break;
case (DWORD)(UINT_PTR)(DIPROP_SCANCODE):
{
LPDIPROPDWORD pdipdw = (PV)pdiph;
DWORD dwCode;
AssertF( ppropi->iobj < this->df.dwNumObjs );
AssertF( ppropi->dwDevType == this->df.rgodf[ppropi->iobj].dwType );
dwCode = (DWORD)g_rgbKbdRMap[ppropi->iobj];
if( dwCode == 0xC5 ) {
dwCode = 0x451DE1;
} else if( dwCode & 0x80 ) {
dwCode = ((dwCode & 0x7F) << 8) | 0xE0;
}
pdipdw->dwData = dwCode;
hres = S_OK;
}
break;
default:
SquirtSqflPtszV(sqflKbd | sqflBenign ,
TEXT("CKbd_GetProperty(iobj=%08x): E_NOTIMPL on guid: %08x"),
ppropi->iobj, ppropi->pguid);
break;
}
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method void | CKbd | GetCapabilities |
*
* Get keyboard device capabilities.
*
* @parm LPDIDEVCAPS | pdc |
*
* Device capabilities structure to receive result.
*
* @returns
* <c S_OK> on success.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetCapabilities(PDICB pdcb, LPDIDEVCAPS pdc)
{
HRESULT hres;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetCapabilities,
(_ "pp", pdcb, pdc));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
pdc->dwDevType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_KEYBOARD,
this->dwKbdType);
pdc->dwFlags = DIDC_ATTACHED;
if (this->flEmulation) {
pdc->dwFlags |= DIDC_ALIAS;
}
AssertF(pdc->dwAxes == 0);
AssertF(pdc->dwPOVs == 0);
pdc->dwButtons = this->df.dwNumObjs;
hres = S_OK;
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method void | CKbd | GetPhysicalState |
*
* Read the physical keyboard state into <p pksOut>.
*
* Note that it doesn't matter if this is not atomic.
* If a key goes down or up while we are reading it,
* we will get a mix of old and new data. No big deal.
*
* @parm PDK | this |
*
* The object in question.
*
* @parm PKBDSTATE | pksOut |
*
* Where to put the keyboard state.
* @returns
* None.
*
*****************************************************************************/
void INLINE
CKbd_GetPhysicalState(PDK this, PKBDSTAT pksOut)
{
AssertF(this->pksPhys);
*pksOut = *this->pksPhys;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | GetDeviceState |
*
* Obtains the state of the keyboard device.
*
* It is the caller's responsibility to have validated all the
* parameters and ensure that the device has been acquired.
*
* @parm OUT LPVOID | lpvData |
*
* Keyboard data in the preferred data format.
*
* @returns
*
* Returns a COM error code. The following error codes are
* intended to be illustrative and not necessarily comprehensive.
*
* <c DI_OK> = <c S_OK>: The operation completed successfully.
*
* <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
* <p lpmdr> parameter is not a valid pointer.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetDeviceState(PDICB pdcb, LPVOID pvData)
{
HRESULT hres;
PDK this;
PKBDSTAT pkstOut = pvData;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetDeviceState,
(_ "pp", pdcb, pvData));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
/*
* ISSUE-2001/03/29-timgill older apps may need compat behaviour
* We never used to check whether or not the device was still
* acquired since without exclusive mode there would be no reason for
* the device not to be.
* To keep behavior the same for older apps it might be better to
* only fail if VIFL_CAPTURED is not set but just checking VIFL_ACQUIRED
* is good enough for now, maybe for ever.
*/
// if( !(this->pvi->fl & VIFL_CAPTURED)
// || (this->pvi->fl & VIFL_ACQUIRED) )
if( this->pvi->fl & VIFL_ACQUIRED )
{
CKbd_GetPhysicalState(this, pkstOut);
hres = S_OK;
} else {
RPF( "Keyboard VxD flags: 0x%08x", this->pvi->fl );
hres = DIERR_INPUTLOST;
}
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | GetObjectInfo |
*
* Obtain the friendly name of an object, passwed by index
* into the preferred data format.
*
* @parm IN LPCDIPROPINFO | ppropi |
*
* Information describing the object being accessed.
*
* @parm IN OUT LPDIDEVICEOBJECTINSTANCEW | pdidioiW |
*
* Structure to receive information. The
* <e DIDEVICEOBJECTINSTANCE.guidType>,
* <e DIDEVICEOBJECTINSTANCE.dwOfs>,
* and
* <e DIDEVICEOBJECTINSTANCE.dwType>
* fields have already been filled in.
*
* @returns
*
* Returns a COM error code.
*
*****************************************************************************/
STDMETHODIMP
CKbd_GetObjectInfo(PDICB pdcb, LPCDIPROPINFO ppropi,
LPDIDEVICEOBJECTINSTANCEW pdidoiW)
{
HRESULT hres = S_OK;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::GetObjectInfo,
(_ "pxp", pdcb, ppropi->iobj, pdidoiW));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEW(pdidoiW->dwSize));
if (ppropi->iobj < this->df.dwNumObjs) {
AssertF(this->rgodf == this->df.rgodf);
AssertF(ppropi->dwDevType == this->rgodf[ppropi->iobj].dwType);
AssertF(ppropi->dwDevType & DIDFT_BUTTON);
#if 0
/*
* We keep using this code only to make it consistent with old code,
* otherwise we would use the new code.
* Someday, we may change to use the new code. It is more accurate,
* especially for Japanese Keyboard, and for future devices.
*/
LoadStringW(g_hinst,
IDS_KEYBOARDOBJECT +
DIDFT_GETINSTANCE(ppropi->dwDevType),
pdidoiW->tszName, cA(pdidoiW->tszName));
#else
{
memset( pdidoiW->tszName, 0, cbX(pdidoiW->tszName) );
hres = DIGetKeyNameText(ppropi->iobj, ppropi->dwDevType, pdidoiW->tszName, cA(pdidoiW->tszName) );
}
#endif
} else {
hres = E_INVALIDARG;
}
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | SetCooperativeLevel |
*
* Notify the device of the cooperative level.
*
* @parm IN HWND | hwnd |
*
* The window handle.
*
* @parm IN DWORD | dwFlags |
*
* The cooperativity level. We do not support exclusive access.
*
* @returns
*
* Returns a COM error code.
*
*****************************************************************************/
STDMETHODIMP
CKbd_SetCooperativeLevel(PDICB pdcb, HWND hwnd, DWORD dwFlags)
{
HRESULT hres;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::SetCooperativityLevel,
(_ "pxx", pdcb, hwnd, dwFlags));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
AssertF(this->pvi);
AssertF(DIGETEMFL(this->pvi->fl) == 0 ||
DIGETEMFL(this->pvi->fl) == DIEMFL_KBD ||
DIGETEMFL(this->pvi->fl) == DIEMFL_KBD2);
/*
* We don't allow background exclusive access.
* This is actually not a real problem to support; we just don't feel like it
* because it's too dangerous.
*/
if (!(this->pvi->fl & DIMAKEEMFL(DIEMFL_KBD2))) {
if (dwFlags & DISCL_EXCLUSIVE) {
if (dwFlags & DISCL_FOREGROUND) {
this->pvi->fl |= VIFL_CAPTURED;
this->pvi->fl |= VIFL_NOWINKEY;
hres = S_OK;
} else { /* Disallow exclusive background */
hres = E_NOTIMPL;
}
} else {
this->pvi->fl &= ~VIFL_CAPTURED;
this->pvi->fl &= ~VIFL_NOWINKEY;
hres = S_OK;
if (dwFlags & DISCL_NOWINKEY) {
if (dwFlags & DISCL_FOREGROUND) {
this->pvi->fl |= VIFL_NOWINKEY;
} else {
RPF("Kbd::SetCooperativeLevel: NOWINKEY not supported in Backgroud mode.");
hres = E_NOTIMPL;
}
}
}
} else {
/*
* Emulation level 2 does not support background access.
*/
if ((this->pvi->fl & DIMAKEEMFL(DIEMFL_KBD2)) &&
(dwFlags & DISCL_BACKGROUND)) {
hres = E_NOTIMPL;
} else {
this->pvi->fl &= ~VIFL_NOWINKEY;
hres = S_OK;
if (dwFlags & DISCL_NOWINKEY) {
if (dwFlags & DISCL_FOREGROUND) {
this->pvi->fl |= VIFL_NOWINKEY;
} else {
RPF("Kbd::SetCooperativeLevel: NOWINKEY not supported in Backgroud mode.");
hres = E_NOTIMPL;
}
}
}
}
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | RunControlPanel |
*
* Run the keyboard control panel.
*
* @parm IN HWND | hwndOwner |
*
* The owner window.
*
* @parm DWORD | dwFlags |
*
* Flags.
*
*****************************************************************************/
#pragma BEGIN_CONST_DATA
TCHAR c_tszKeyboard[] = TEXT("keyboard");
#pragma END_CONST_DATA
STDMETHODIMP
CKbd_RunControlPanel(PDICB pdcb, HWND hwnd, DWORD dwFlags)
{
HRESULT hres;
PDK this;
EnterProcI(IDirectInputDeviceCallback::Kbd::RunControlPanel,
(_ "pxx", pdcb, hwnd, dwFlags));
/*
* This is an internal interface, so we can skimp on validation.
*/
this = _thisPvNm(pdcb, dcb);
hres = hresRunControlPanel(c_tszKeyboard);
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | BuildDefaultActionMap |
*
* Validate the passed action map, blanking out invalid ones.
*
* @parm LPDIACTIONFORMATW | pActionFormat |
*
* Actions to map.
*
* @parm DWORD | dwFlags |
*
* Flags used to indicate mapping preferences.
*
* @parm REFGUID | guidInst |
*
* Device instance GUID.
*
* @returns
*
* <c E_NOTIMPL>
*
*****************************************************************************/
STDMETHODIMP
CKbd_BuildDefaultActionMap
(
PDICB pdcb,
LPDIACTIONFORMATW paf,
DWORD dwFlags,
REFGUID guidInst
)
{
HRESULT hres;
PDK this;
/*
* This is an internal interface, so we can skimp on validation.
*/
EnterProcI(IDirectInputDeviceCallback::CKbd::BuildDefaultActionMap,
(_ "ppxG", pdcb, paf, dwFlags, guidInst));
this = _thisPvNm(pdcb, dcb);
hres = CMap_BuildDefaultSysActionMap ( paf, dwFlags, DIPHYSICAL_KEYBOARD,
guidInst, &this->df, 0 /* Mouse button instance, ignored for kbds */ );
ExitOleProcR();
return hres;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method DWORD | CKbd | InitJapanese |
*
* Initialize the Japanese keyboard goo.
*
* Annoying quirk! On Windows 95, Japanese keyboards generate
* their own scan codes. But on Windows NT, they generate
* "nearly AT-compatible" scan codes.
*
* @returns
*
* KBDTYPE_ANYKBD or KBDTYPE_ANYKBD + KBDTYPE_NECTGL.
*
*****************************************************************************/
DWORD INTERNAL
CKbd_InitJapanese(PDK this, PVXDDEVICEFORMAT pdevf)
{
DWORD dwSubType;
UINT idKbd;
DWORD dwRc;
#ifdef WINNT
#define WIN9X_RC( rc )
#else
#define WIN9X_RC( rc ) dwRc = ( rc )
#endif
dwSubType = WrappedGetKeyboardType(1);
if (HIBYTE(dwSubType) == 0x0D) { /* NEC PC98 series */
switch (LOBYTE(dwSubType)) {
case 1:
default:
idKbd = IDDATA_KBD_NEC98;
this->dwKbdType = DI8DEVTYPEKEYBOARD_NEC98;
WIN9X_RC( KBDTYPE_ANYKBD + KBDTYPE_NECTGL );
break;
case 4:
idKbd = IDDATA_KBD_NEC98LAPTOP;
this->dwKbdType = DI8DEVTYPEKEYBOARD_NEC98LAPTOP;
WIN9X_RC( KBDTYPE_ANYKBD + KBDTYPE_NECTGL );
break;
case 5:
idKbd = IDDATA_KBD_NEC98_106;
this->dwKbdType = DI8DEVTYPEKEYBOARD_NEC98106;
WIN9X_RC( KBDTYPE_ANYKBD + KBDTYPE_NECTGL );
break;
}
/*
* If the scan code for ESC is 1, then we're on an
* NEC98 keyboard that acts AT-like.
*/
CAssertF(IDDATA_KBD_NEC98_NT - IDDATA_KBD_NEC98 ==
IDDATA_KBD_NEC98LAPTOP_NT - IDDATA_KBD_NEC98LAPTOP);
CAssertF(IDDATA_KBD_NEC98_NT - IDDATA_KBD_NEC98 ==
IDDATA_KBD_NEC98_106_NT - IDDATA_KBD_NEC98_106);
if (MapVirtualKey(VK_ESCAPE, 0) == DIK_ESCAPE) {
idKbd += IDDATA_KBD_NEC98_NT - IDDATA_KBD_NEC98;
}
} else {
switch (dwSubType) {
case 0:
this->dwKbdType = DI8DEVTYPEKEYBOARD_PCENH;
dwRc = KBDTYPE_ENH;
goto done; /* Yuck */
case 1:
idKbd = IDDATA_KBD_JAPANAX;
this->dwKbdType = DI8DEVTYPEKEYBOARD_JAPANAX;
WIN9X_RC( KBDTYPE_ANYKBD );
break;
case 13:
case 14:
case 15:
idKbd = IDDATA_KBD_J3100;
this->dwKbdType = DI8DEVTYPEKEYBOARD_J3100;
WIN9X_RC( KBDTYPE_ANYKBD );
break;
case 4: /* Rumored to be Epson */
case 5: /* Rumored to be Fujitsu */
case 7: /* Rumored to be IBMJ */
case 10: /* Rumored to be Matsushita */
case 18: /* Rumored to be Toshiba */
default:
idKbd = IDDATA_KBD_JAPAN106;
this->dwKbdType = DI8DEVTYPEKEYBOARD_JAPAN106;
WIN9X_RC( KBDTYPE_ANYKBD );
break;
}
}
#undef WIN9X_RC
#ifdef WINNT
/*
* ISSUE-2001/03/29-timgill Japanese keyboard assumption needs testing
* All Japanese keyboards on NT have toggle keys
* Except subtype zero? Needs test
*/
dwRc = KBDTYPE_ANYKBD + KBDTYPE_NTTGL;
#endif
/*
* Now load up the translation table goo.
*/
pdevf->dwExtra = (DWORD)(UINT_PTR)pvFindResource(g_hinst, idKbd, RT_RCDATA);
if (pdevf->dwExtra == 0) {
dwRc = 0;
}
done:;
return dwRc;
}
/*****************************************************************************
*
* @doc INTERNAL
*
* @method HRESULT | CKbd | Init |
*
* Initialize the object by establishing the data format
* based on the keyboard type. Anything we don't recognize,
* we treat as a PC Enhanced keyboard.
*
* @parm REFGUID | rguid |
*
* The instance GUID we are being asked to create.
*
*****************************************************************************/
HRESULT INTERNAL
CKbd_Init(PDK this, REFGUID rguid)
{
DWORD dwDevType;
UINT ib;
HRESULT hres;
VXDDEVICEFORMAT devf;
EnterProc(CKbd_Init, (_ "pG", this, rguid));
#ifdef DEBUG
/*
* Check that the Japan tables aren't messed up.
*/
{
UINT idk;
for (idk = IDDATA_KBD_NEC98; idk <= IDDATA_KBD_J3100; idk++) {
BYTE rgb[DIKBD_CKEYS];
HANDLE hrsrc;
LPBYTE pb;
ZeroX(rgb);
/*
* Make sure the table exists.
*/
hrsrc = FindResource(g_hinst, (LPTSTR)(LONG_PTR)(idk), RT_RCDATA);
AssertF(hrsrc);
pb = LoadResource(g_hinst, hrsrc);
/*
* Walk the table and make sure each thing that exists
* in the translation table also exists in our master table.
* Also make sure that it isn't a dup with something else
* in the same table.
*/
/*
* Note, however, that the JAPAN106 keyboard contains
* dups so we can save having to write an entire
* translation table. And then NEC98_NT tables contain
* lots of dups out of sheer laziness.
*/
for (ib = 0; ib < DIKBD_CKEYS; ib++) {
if (pb[ib]) {
AssertF(c_rgktWhich[pb[ib]] & KBDTYPE_ANYKBD);
AssertF(fLorFF(idk == IDDATA_KBD_JAPAN106 && ib == 0x73,
rgb[pb[ib]] == 0));
rgb[pb[ib]] = 1;
}
}
}
}
#endif
this->df.dwSize = cbX(DIDATAFORMAT);
this->df.dwObjSize = cbX(DIOBJECTDATAFORMAT);
this->df.dwDataSize = sizeof(KBDSTAT);
this->df.rgodf = this->rgodf;
this->dwKbdType = WrappedGetKeyboardType(0);
/*
* Create the object with the most optimistic data format.
* This allows apps to access new keys without having to rev DINPUT.
*
* However, leave out the following scan codes because some keyboards
* generate them spuriously:
*
* 0xB6
*
* If you hold the right shift key and then press an
* extended arrow key, then release both, some keyboards
* generate the following:
*
* 0x36 - right shift down
* 0xE0 0xB6 - extended right shift up (?)
* 0xE0 0x4B - extended left arrow down
* 0xE0 0xCB - extended left arrow up
* 0xE0 0x36 - extended right shift down (?)
* 0xE6 - right shift up
*
* The stray 0xE0 0x36 needs to be ignored.
*
* 0xAA
*
* Same as 0xB6, but with the left shift key.
*
*
*/
for (ib = 0; ib < DIKBD_CKEYS; ib++) {
if (ib != 0xAA && ib != 0xB6) {
this->rgodf[ib].pguid = &GUID_Key;
this->rgodf[ib].dwOfs = ib;
this->rgodf[ib].dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE(ib);
AssertF(this->rgodf[ib].dwFlags == 0);
}
}
devf.cObj = DIKBD_CKEYS;
devf.cbData = cbX(KBDSTAT);
devf.rgodf = this->rgodf;
/*
* But first a word from our sponsor: Figure out if this keyboard
* needs a translation table.
*/
devf.dwExtra = 0; /* Assume no translation */
if (this->dwKbdType != 7) { /* Not a yucky Japanese keyboard */
switch (this->dwKbdType) {
case DI8DEVTYPEKEYBOARD_PCXT: dwDevType = KBDTYPE_XT; break;
case DI8DEVTYPEKEYBOARD_PCAT: dwDevType = KBDTYPE_AT; break;
default:
case DI8DEVTYPEKEYBOARD_PCENH: dwDevType = KBDTYPE_ENH; break;
}
} else { /* Yucky Japanese keyboard */
dwDevType = CKbd_InitJapanese(this, &devf);
if (!dwDevType) {
goto justfail;
}
}
/*
* And now a word from our other sponsor: Figure out the
* emulation flags based on the GUID.
*/
AssertF(GUID_SysKeyboard .Data1 == 0x6F1D2B61);
AssertF(GUID_SysKeyboardEm .Data1 == 0x6F1D2B82);
AssertF(GUID_SysKeyboardEm2.Data1 == 0x6F1D2B83);
switch (rguid->Data1) {
default:
case 0x6F1D2B61:
AssertF(IsEqualGUID(rguid, &GUID_SysKeyboard));
AssertF(this->flEmulation == 0);
break;
case 0x6F1D2B82:
AssertF(IsEqualGUID(rguid, &GUID_SysKeyboardEm));
this->flEmulation = DIEMFL_KBD;
break;
case 0x6F1D2B83:
AssertF(IsEqualGUID(rguid, &GUID_SysKeyboardEm2));
this->flEmulation = DIEMFL_KBD2;
break;
}
devf.dwEmulation = this->flEmulation;
hres = Hel_Kbd_CreateInstance(&devf, &this->pvi);
if (SUCCEEDED(hres)) {
UINT cobj;
BYTE rgbSeen[DIKBD_CKEYS];
AssertF(this->pvi);
AssertF(this->df.dwFlags == 0);
AssertF(this->df.dwNumObjs == 0);
/*
* Japanese keyboards have many-to-one mappings, so
* we need to filter out the dups or we end up in big
* trouble.
*/
ZeroX(rgbSeen);
/*
* Now create the real data format.
*
* We shadow this->df.dwNumObjs in cobj so that the compiler
* can enregister it.
*
* Note that we filter through the translation table if there
* is one.
*/
cobj = 0;
for (ib = 0; ib < DIKBD_CKEYS; ib++) {
BYTE bScan = devf.dwExtra ? ((LPBYTE)devf.dwExtra)[ib] : ib;
if ((c_rgktWhich[bScan] & dwDevType) && !rgbSeen[bScan]) {
PODF podf = &this->rgodf[cobj];
rgbSeen[bScan] = 1;
podf->pguid = &GUID_Key;
podf->dwOfs = bScan;
/*
* To make a mapping talbe for original scan code from DIK_* code.
*/
g_rgbKbdRMap[cobj] = (BYTE) ib;
if( dwDevType == KBDTYPE_ENH ) { //how about Japanese KBD?
if( ib == 0x45 || ib == 0xC5) {
g_rgbKbdRMap[cobj] = (ib & 0x7F) | (ib ^ 0x80);
}
}
if (c_rgktWhich[bScan] & dwDevType & (KBDTYPE_NECTGL|KBDTYPE_NTTGL) ) {
podf->dwType = DIDFT_TGLBUTTON | DIDFT_MAKEINSTANCE(bScan);
} else {
podf->dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE(bScan);
}
AssertF(podf->dwFlags == 0);
cobj++;
this->df.dwNumObjs++;
}
}
this->pksPhys = this->pvi->pState;
} else {
justfail:;
hres = E_FAIL;
}
ExitOleProc();
return hres;
}
/*****************************************************************************
*
* CKbd_New (constructor)
*
*****************************************************************************/
STDMETHODIMP
CKbd_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvObj)
{
HRESULT hres;
EnterProcI(IDirectInputDeviceCallback::Kbd::<constructor>,
(_ "Gp", riid, ppvObj));
AssertF(IsEqualGUID(rguid, &GUID_SysKeyboard) ||
IsEqualGUID(rguid, &GUID_SysKeyboardEm) ||
IsEqualGUID(rguid, &GUID_SysKeyboardEm2));
hres = Common_NewRiid(CKbd, punkOuter, riid, ppvObj);
if (SUCCEEDED(hres)) {
/* Must use _thisPv in case of aggregation */
PDK this = _thisPv(*ppvObj);
if (SUCCEEDED(hres = CKbd_Init(this, rguid))) {
} else {
Invoke_Release(ppvObj);
}
}
ExitOleProcPpvR(ppvObj);
return hres;
}
/*****************************************************************************
*
* The long-awaited vtbls and templates
*
*****************************************************************************/
#pragma BEGIN_CONST_DATA
#define CKbd_Signature 0x2044424B /* "KBD " */
Interface_Template_Begin(CKbd)
Primary_Interface_Template(CKbd, IDirectInputDeviceCallback)
Interface_Template_End(CKbd)
Primary_Interface_Begin(CKbd, IDirectInputDeviceCallback)
CKbd_GetInstance,
CDefDcb_GetVersions,
CKbd_GetDataFormat,
CKbd_GetObjectInfo,
CKbd_GetCapabilities,
CKbd_Acquire,
CDefDcb_Unacquire,
CKbd_GetDeviceState,
CKbd_GetDeviceInfo,
CKbd_GetProperty,
CDefDcb_SetProperty,
CDefDcb_SetEventNotification,
CKbd_SetCooperativeLevel,
CKbd_RunControlPanel,
CDefDcb_CookDeviceData,
CDefDcb_CreateEffect,
CDefDcb_GetFFConfigKey,
CDefDcb_SendDeviceData,
CDefDcb_Poll,
CDefDcb_GetUsage,
CDefDcb_MapUsage,
CDefDcb_SetDIData,
CKbd_BuildDefaultActionMap,
Primary_Interface_End(CKbd, IDirectInputDeviceCallback)