|
|
/*****************************************************************************
* * 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)
|