419 lines
14 KiB
C
419 lines
14 KiB
C
/***************************************************************************/
|
|
/* Description: KeybDI.c, part of CPA INO library */
|
|
/* Keyboard specific implementation */
|
|
/* */
|
|
/* Author: F. Jentey */
|
|
/* Last Update: 05/03/97 */
|
|
/* 30/07/97 Direct Input */
|
|
/***************************************************************************/
|
|
|
|
|
|
#include <locale.h>
|
|
#include "INO\errINO.h"
|
|
#include "InitDI.h"
|
|
#include "INOInit.h"
|
|
#include "Keyboard.h"
|
|
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
Globale vars
|
|
***************************************************************************/
|
|
|
|
/* Keyboard config variables : get the country keyboard config */
|
|
char INO_LayoutName[KL_NAMELENGTH];
|
|
HKL INO_LayoutHandle;
|
|
|
|
/* Table for virtual key code use for ASCII conversion */
|
|
/* INO_acDikToVirtual is used for the numeric pad, coz */
|
|
/* MapVirtualKeyEx() doesn't Verr Num state. */
|
|
BYTE INO_acVirtualKeyCodeTab[256];
|
|
BYTE INO_acDikToVirtual[256];
|
|
|
|
/* Store the key use in the game */
|
|
unsigned short INO_ActiveKey[128];
|
|
unsigned short INO_ActiveKeyNumber;
|
|
|
|
|
|
|
|
|
|
/**********************************************************************************/
|
|
/* This fonction returns the ASCII code corresponding to a key code if this key */
|
|
/* is printable. */
|
|
/**********************************************************************************/
|
|
short INO_fn_wDikToAscii(short wKeyCode, INO_tdhDevice hDev)
|
|
{
|
|
unsigned long VirtualKeyCode;
|
|
long iResult;
|
|
unsigned short a_uwASCIICode[2];
|
|
|
|
/* Get the VirtualKey code of the key */
|
|
/* We suppose all DIK code correspond to scan code. */
|
|
/* For numeric pad key, use the dik to virtual key */
|
|
/* code translation table. */
|
|
if ( (((wKeyCode>0x46) && (wKeyCode<0x54)) || (wKeyCode==0xb5)) &&
|
|
(GetKeyState(VK_NUMLOCK) & INO_C_ucKeyToggled) )
|
|
VirtualKeyCode = INO_acDikToVirtual[wKeyCode];
|
|
else
|
|
VirtualKeyCode = MapVirtualKeyEx(wKeyCode, 1, INO_LayoutHandle);
|
|
|
|
/* La fameuse modif qui tue - Elie */
|
|
if ( (VirtualKeyCode == 0) ||
|
|
(VirtualKeyCode == VK_CAPITAL) ||
|
|
(VirtualKeyCode == VK_SCROLL) ||
|
|
(VirtualKeyCode == VK_NUMLOCK) ||
|
|
(VirtualKeyCode == VK_SHIFT) ||
|
|
(VirtualKeyCode == VK_CONTROL) ||
|
|
(VirtualKeyCode == VK_MENU) ||
|
|
((VirtualKeyCode >= VK_F1) && (VirtualKeyCode<=VK_F24))
|
|
)
|
|
return (0);
|
|
|
|
/* Fill the INO_acVirtualKeyCodeTab array with SHIFT, ALT and CTRL state */
|
|
INO_acVirtualKeyCodeTab[VK_SHIFT] = INO_C_ucKeyDown &
|
|
( M_KeyState(hDev,C_ucKey_LSHIFT) |
|
|
M_KeyState(hDev,C_ucKey_RSHIFT) );
|
|
INO_acVirtualKeyCodeTab[VK_CONTROL] = INO_C_ucKeyDown &
|
|
( M_KeyState(hDev,C_ucKey_LCTRL) |
|
|
M_KeyState(hDev,C_ucKey_RCTRL) );
|
|
INO_acVirtualKeyCodeTab[VK_MENU] = INO_C_ucKeyDown &
|
|
( M_KeyState(hDev,C_ucKey_LALT) |
|
|
M_KeyState(hDev,C_ucKey_RALT) );
|
|
INO_acVirtualKeyCodeTab[VK_CAPITAL] = GetKeyState(VK_CAPITAL) & INO_C_ucKeyToggled;
|
|
|
|
/* Deuxieme modif qui tue - Elie */
|
|
/* INO_acVirtualKeyCodeTab[VK_NUMLOCK] = GetKeyState(VK_NUMLOCK) & INO_C_ucKeyToggled;*/
|
|
|
|
iResult = ToAsciiEx(VirtualKeyCode, wKeyCode, INO_acVirtualKeyCodeTab, a_uwASCIICode,0 , INO_LayoutHandle);
|
|
switch (iResult)
|
|
{
|
|
case 0:
|
|
return (0);
|
|
case 1:
|
|
iResult = (int)(a_uwASCIICode[0] & 0xFF);
|
|
/*if (!isprint(iResult) /*&& iswprint(iResult) ) */
|
|
/* return (0);*/
|
|
break;
|
|
case 2:
|
|
return (0);
|
|
}
|
|
return ((short)iResult);
|
|
}
|
|
|
|
|
|
/* Remove an active key. An error occurs when the specified key isn't */
|
|
/* active.By default, all keys are active, but you can remove some keys */
|
|
/* if they aren't used to speed up the fn_wKbRead function. */
|
|
short INO_fn_wRemoveActiveKey(short wKeyCode)
|
|
{
|
|
short i,j;
|
|
|
|
for (i=0 ;i<INO_ActiveKeyNumber; i++)
|
|
{
|
|
if (INO_ActiveKey[i] == wKeyCode)
|
|
{
|
|
for (j=i+1; j<INO_ActiveKeyNumber; j++)
|
|
INO_ActiveKey[j-1] = INO_ActiveKey[j];
|
|
INO_ActiveKeyNumber--;
|
|
return (1);
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
/* Add a key to be managed. There is an error if the specified key is */
|
|
/* already active. */
|
|
short INO_fn_wAddActiveKey(short wKeyCode)
|
|
{
|
|
short i;
|
|
|
|
if (INO_ActiveKeyNumber > 127)
|
|
{
|
|
/* TO DO: error message */
|
|
return (0);
|
|
}
|
|
/* Test if key is already active */
|
|
for (i=0 ;i<INO_ActiveKeyNumber; i++)
|
|
{
|
|
if (INO_ActiveKey[i] == wKeyCode)
|
|
return (0);
|
|
}
|
|
INO_ActiveKey[INO_ActiveKeyNumber] = wKeyCode;
|
|
INO_ActiveKeyNumber++;
|
|
return (0);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
INITIALISATION
|
|
*********************************************************************/
|
|
|
|
/* Init keyboard capabilities. */
|
|
short INO_fn_wInitKeyboardCaps(INO_tdhDevice hDev)
|
|
{
|
|
short wASCIIForKeyA, i;
|
|
short wDev;
|
|
unsigned long ulSubType;
|
|
|
|
for (i=0; i<INO_C_wNbMaxDevice; i++)
|
|
if (INO_g_a_stDIDevice[i].m_hDevice == hDev) break;
|
|
if (i == INO_C_wNbMaxDevice) return (0);
|
|
wDev = i;
|
|
|
|
ulSubType = INO_fn_wFillDeviceCaps(hDev);
|
|
if (!ulSubType)
|
|
return(0);
|
|
memset(INO_ActiveKey,0,sizeof(unsigned short)*128);
|
|
INO_ActiveKeyNumber = 0;
|
|
|
|
/* For ASCII conversion */
|
|
GetKeyboardLayoutName(INO_LayoutName);
|
|
INO_LayoutHandle = LoadKeyboardLayout(INO_LayoutName,KLF_ACTIVATE);
|
|
|
|
/* Set the default active Key (All keys) */
|
|
for ( i=0x01 ; i<0x58 ; i++ )
|
|
INO_fn_wAddActiveKey(i);
|
|
INO_fn_wAddActiveKey(0x69); /* Pause */
|
|
INO_fn_wAddActiveKey(0x9c);
|
|
INO_fn_wAddActiveKey(0x9d);
|
|
INO_fn_wAddActiveKey(0xb5);
|
|
INO_fn_wAddActiveKey(0xb7);
|
|
INO_fn_wAddActiveKey(0xb8);
|
|
INO_fn_wAddActiveKey(0xc7);
|
|
INO_fn_wAddActiveKey(0xc5); /* Num Lock */
|
|
INO_fn_wAddActiveKey(0xc8);
|
|
INO_fn_wAddActiveKey(0xc9);
|
|
INO_fn_wAddActiveKey(0xcb);
|
|
INO_fn_wAddActiveKey(0xcd);
|
|
INO_fn_wAddActiveKey(0xcf);
|
|
INO_fn_wAddActiveKey(0xd0);
|
|
INO_fn_wAddActiveKey(0xd1);
|
|
INO_fn_wAddActiveKey(0xd2);
|
|
INO_fn_wAddActiveKey(0xd3);
|
|
INO_fn_wAddActiveKey(0xdb);
|
|
INO_fn_wAddActiveKey(0xdc);
|
|
INO_fn_wAddActiveKey(0xdd);
|
|
|
|
/* Fill the Dik to Virtual key code translation table */
|
|
/* for numeric pad (Vk when Verr Num is ON) */
|
|
INO_acDikToVirtual[C_ucKey_PAD_0] = VK_NUMPAD0;
|
|
INO_acDikToVirtual[C_ucKey_PAD_1] = VK_NUMPAD1;
|
|
INO_acDikToVirtual[C_ucKey_PAD_2] = VK_NUMPAD2;
|
|
INO_acDikToVirtual[C_ucKey_PAD_3] = VK_NUMPAD3;
|
|
INO_acDikToVirtual[C_ucKey_PAD_4] = VK_NUMPAD4;
|
|
INO_acDikToVirtual[C_ucKey_PAD_5] = VK_NUMPAD5;
|
|
INO_acDikToVirtual[C_ucKey_PAD_6] = VK_NUMPAD6;
|
|
INO_acDikToVirtual[C_ucKey_PAD_7] = VK_NUMPAD7;
|
|
INO_acDikToVirtual[C_ucKey_PAD_8] = VK_NUMPAD8;
|
|
INO_acDikToVirtual[C_ucKey_PAD_9] = VK_NUMPAD9;
|
|
INO_acDikToVirtual[C_ucKey_PAD_DIV] = VK_DIVIDE;
|
|
INO_acDikToVirtual[C_ucKey_PAD_MUL] = VK_MULTIPLY;
|
|
INO_acDikToVirtual[C_ucKey_PAD_SUB] = VK_SUBTRACT;
|
|
INO_acDikToVirtual[C_ucKey_PAD_ADD] = VK_ADD;
|
|
INO_acDikToVirtual[C_ucKey_PAD_POINT] = VK_DECIMAL;
|
|
|
|
/* Find keyboard type (Azerty / Qwerty) */
|
|
wASCIIForKeyA = INO_fn_wDikToAscii(C_ucKey_A,hDev) & 0xFF;
|
|
if ((wASCIIForKeyA == 'a') || (wASCIIForKeyA == 'A'))
|
|
((INO_tdstKeyboardCaps*)(hDev->m_p_stCaps))->m_wIsAzerty = 1;
|
|
else
|
|
((INO_tdstKeyboardCaps*)(hDev->m_p_stCaps))->m_wIsAzerty = 0;
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
/* This function must be called at regular interval, for example each VBL. */
|
|
/* It Update the informations about the keyboard. */
|
|
short INO_fn_wReadKeyboard(INO_tdhDevice hDev)
|
|
{
|
|
HRESULT DInputErr;
|
|
unsigned short i, j;
|
|
short DownKey[INO_C_wMaxKeyDown];
|
|
short DownKeyNumber;
|
|
short LastKeyHasChanged, StateHasChanged;
|
|
short wDev;
|
|
INO_tdstKeyboardState *p_stState = M_KState(hDev);
|
|
INO_tdstKeyboardRecord *p_stH = (INO_tdstKeyboardRecord*)hDev->m_pvHistoric;
|
|
unsigned char *p_ucCurrentTab, *p_ucPrevTab;
|
|
|
|
if (!INO_M_bIsConnected(hDev))
|
|
return (0);
|
|
|
|
for (wDev=0; wDev<INO_C_wNbMaxDevice; wDev++)
|
|
if (INO_g_a_stDIDevice[wDev].m_hDevice == hDev) break;
|
|
if (wDev == INO_C_wNbMaxDevice)
|
|
{
|
|
INO_fn_vUpdateLastError(E_uwINO_WarningInvalidDevice);
|
|
return (0);
|
|
}
|
|
|
|
/* Increase the internal engine loop counter */
|
|
hDev->m_ulLastTimeCount++;
|
|
|
|
/* Flip the keyboard state buffer */
|
|
p_stState->m_wCurrentTab = 1 - p_stState->m_wCurrentTab;
|
|
p_ucCurrentTab = p_stState->m_a_ucTabKey[p_stState->m_wCurrentTab];
|
|
p_ucPrevTab = p_stState->m_a_ucTabKey[1-p_stState->m_wCurrentTab];
|
|
|
|
/* Try to acquire the keyboard if not done */
|
|
if (!(p_stState->m_ucStatus & INO_C_ucAcquired) ||
|
|
(p_stState->m_ucStatus & INO_C_ucAccessError) )
|
|
{
|
|
DInputErr = M_DIAcquire(wDev);
|
|
switch (DInputErr)
|
|
{
|
|
case DI_OK:
|
|
case S_FALSE:
|
|
hDev->m_p_stState->m_ucStatus |= INO_C_ucAcquired;
|
|
hDev->m_p_stState->m_ucStatus &= ~INO_C_ucAccessError;
|
|
break;
|
|
|
|
case DIERR_INPUTLOST:
|
|
case DIERR_NOTACQUIRED:
|
|
case DIERR_OTHERAPPHASPRIO:
|
|
return (0);
|
|
|
|
default:
|
|
hDev->m_p_stState->m_ucStatus &= ~INO_C_ucAcquired;
|
|
hDev->m_p_stState->m_ucStatus |= INO_C_ucAccessError;
|
|
INO_fn_vUpdateLastError(E_uwINO_DirectInputError);
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
/* Read all key */
|
|
DInputErr = M_DIGetState(wDev, sizeof(BYTE)*256, p_ucCurrentTab);
|
|
switch (DInputErr)
|
|
{
|
|
case DI_OK:
|
|
case E_PENDING:
|
|
break;
|
|
|
|
case DIERR_INPUTLOST:
|
|
case DIERR_NOTACQUIRED:
|
|
hDev->m_p_stState->m_ucStatus &= ~INO_C_ucAcquired;
|
|
return (0);
|
|
|
|
default:
|
|
INO_fn_vUpdateLastError(E_uwINO_DirectInputError);
|
|
hDev->m_p_stState->m_ucStatus |= INO_C_ucAccessError;
|
|
hDev->m_p_stState->m_ucStatus &= ~INO_C_ucAcquired;
|
|
return (0);
|
|
}
|
|
|
|
/* Check if the keyboard state has changed by comparing the current buffer with */
|
|
/* the previous one. Store the key code of the down key in the local tab */
|
|
/* ChangedKey. */
|
|
StateHasChanged = 0;
|
|
LastKeyHasChanged = 0;
|
|
DownKeyNumber = 0;
|
|
for (i=0 ; i<INO_ActiveKeyNumber ; i++)
|
|
{
|
|
j = INO_ActiveKey[i];
|
|
if (p_ucCurrentTab[j] != p_ucPrevTab[j])
|
|
{
|
|
StateHasChanged = 1;
|
|
if (p_ucCurrentTab[j])
|
|
{
|
|
LastKeyHasChanged = 1;
|
|
p_stState->m_wLastKey = j;
|
|
}
|
|
}
|
|
if ((DownKeyNumber < INO_C_wMaxKeyDown) && p_ucCurrentTab[j])
|
|
DownKey[DownKeyNumber++] = j;
|
|
}
|
|
|
|
if (LastKeyHasChanged)
|
|
{
|
|
/* Update last ASCII code */
|
|
p_stState->m_wLastASCII = INO_fn_wDikToAscii(p_stState->m_wLastKey,hDev);
|
|
|
|
/* Update the current string */
|
|
if (p_stState->m_wLastASCII)
|
|
{
|
|
if (p_stState->m_wCurrentStringLength == INO_C_wStringMaxLength)
|
|
{
|
|
for (i=0; i<INO_C_wStringMaxLength-1; i++)
|
|
p_stState->m_szCurrentString[i] = p_stState->m_szCurrentString[i+1];
|
|
p_stState->m_szCurrentString[INO_C_wStringMaxLength-1] = (char)p_stState->m_wLastASCII;
|
|
}
|
|
else
|
|
{
|
|
p_stState->m_szCurrentString[p_stState->m_wCurrentStringLength] = (char)p_stState->m_wLastASCII;
|
|
p_stState->m_wCurrentStringLength++;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
p_stState->m_wLastASCII = 0;
|
|
|
|
/* Update historic. */
|
|
/* Test if it's the first call of the fn_wJKbReadKeyboard */
|
|
if (hDev->m_wRecordNumber == 0)
|
|
{
|
|
p_stH[0].m_ulDate = hDev->m_ulLastTimeCount;
|
|
p_stH[0].m_wNbKeyDown = 0;
|
|
hDev->m_wRecordNumber = 1;
|
|
StateHasChanged = 0;
|
|
}
|
|
/* If not, update the historic if keyboard state has changed */
|
|
else
|
|
{
|
|
if (StateHasChanged)
|
|
{
|
|
hDev->m_wHistoricHead++;
|
|
if (hDev->m_wHistoricHead == hDev->m_wHistoricSize) hDev->m_wHistoricHead = 0;
|
|
if (hDev->m_wRecordNumber != hDev->m_wHistoricSize) hDev->m_wRecordNumber++;
|
|
|
|
p_stH[hDev->m_wHistoricHead].m_ulDate = hDev->m_ulLastTimeCount;
|
|
p_stH[hDev->m_wHistoricHead].m_wNbKeyDown = 0;
|
|
for (i=0; i<DownKeyNumber; i++)
|
|
p_stH[hDev->m_wHistoricHead].m_wKeyDown[i] = DownKey[i];
|
|
p_stH[hDev->m_wHistoricHead].m_wNbKeyDown = DownKeyNumber;
|
|
}
|
|
}
|
|
p_stState->m_wStateHasChanged = StateHasChanged;
|
|
|
|
return (1);
|
|
}
|
|
|
|
/*
|
|
This function return C_wKbTrue if the selected key was down in the
|
|
specified previous state.
|
|
*/
|
|
short INO_fn_bKeyWasDown(INO_tdhDevice hDev, short wKeyCode, short wHistoricIndex)
|
|
{
|
|
long index, i;
|
|
INO_tdstKeyboardRecord *p_stState;
|
|
|
|
if (wHistoricIndex > hDev->m_wHistoricSize-1)
|
|
return (0);
|
|
else
|
|
{
|
|
index = (hDev->m_wHistoricHead - wHistoricIndex + hDev->m_wHistoricSize) % hDev->m_wHistoricSize;
|
|
p_stState = &((INO_tdstKeyboardRecord*)(hDev->m_pvHistoric))[index];
|
|
for (i=0 ; i<p_stState->m_wNbKeyDown; i++ )
|
|
if (p_stState->m_wKeyDown[i] == wKeyCode ) return (1);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
|
|
short INO_fn_wCheckCheatCode(INO_tdhDevice hDev,char *p_szTestString)
|
|
{
|
|
short l;
|
|
char *p_szCurrentS;
|
|
INO_tdstKeyboardState *p_stState = (INO_tdstKeyboardState*)(hDev->m_p_stState);
|
|
|
|
l = strlen(p_szTestString);
|
|
if (l > INO_C_wStringMaxLength) return (0);
|
|
if (l > p_stState->m_wCurrentStringLength) return (0);
|
|
|
|
p_szCurrentS = &p_stState->m_szCurrentString[p_stState->m_wCurrentStringLength-l];
|
|
|
|
return (strcmp(p_szCurrentS,p_szTestString) == 0);
|
|
}
|