2010-01-26 21:00:30 -06:00
|
|
|
#include "global.h"
|
|
|
|
|
#include "InputHandler_DirectInputHelper.h"
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "RageLog.h"
|
|
|
|
|
#include "archutils/Win32/DirectXHelpers.h"
|
|
|
|
|
#include "archutils/Win32/ErrorStrings.h"
|
|
|
|
|
#include "archutils/Win32/GraphicsWindow.h"
|
|
|
|
|
|
|
|
|
|
#if defined(_MSC_VER)
|
|
|
|
|
#pragma comment(lib, "dinput.lib")
|
|
|
|
|
#if defined(_WINDOWS)
|
|
|
|
|
#pragma comment(lib, "dxguid.lib")
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
LPDIRECTINPUT g_dinput = NULL;
|
|
|
|
|
|
|
|
|
|
static int ConvertScancodeToKey( int scancode );
|
|
|
|
|
static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data);
|
2011-02-14 03:16:32 -06:00
|
|
|
static BOOL CALLBACK DIMouse_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data);
|
2010-01-26 21:00:30 -06:00
|
|
|
|
|
|
|
|
DIDevice::DIDevice()
|
|
|
|
|
{
|
|
|
|
|
buttons = axes = hats = 0;
|
|
|
|
|
dev = InputDevice_Invalid;
|
|
|
|
|
buffered = true;
|
|
|
|
|
memset(&JoystickInst, 0, sizeof(JoystickInst));
|
2011-02-14 14:23:56 -06:00
|
|
|
memset(&MouseInst, 0, sizeof(MouseInst));
|
2010-01-26 21:00:30 -06:00
|
|
|
Device = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DIDevice::Open()
|
|
|
|
|
{
|
|
|
|
|
m_sName = ConvertACPToUTF8( JoystickInst.tszProductName );
|
|
|
|
|
|
|
|
|
|
LOG->Trace( "Opening device '%s'", m_sName.c_str() );
|
|
|
|
|
buffered = true;
|
|
|
|
|
|
|
|
|
|
LPDIRECTINPUTDEVICE tmpdevice;
|
2011-02-14 01:43:41 -06:00
|
|
|
|
|
|
|
|
// load joystick
|
2010-01-26 21:00:30 -06:00
|
|
|
HRESULT hr = g_dinput->CreateDevice( JoystickInst.guidInstance, &tmpdevice, NULL );
|
|
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
hr = tmpdevice->QueryInterface( IID_IDirectInputDevice2, (LPVOID *) &Device );
|
|
|
|
|
tmpdevice->Release();
|
|
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice::QueryInterface", m_sName.c_str()) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 03:16:32 -06:00
|
|
|
// load mouse
|
|
|
|
|
/*
|
|
|
|
|
hr = g_dinput->CreateDevice( MouseInst.guidInstance, &tmpdevice, NULL );
|
|
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice: IDirectInput_CreateDevice") );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
// is this ok? -aj
|
|
|
|
|
//hr = tmpdevice->QueryInterface( IID_IDirectInputDevice2, (LPVOID *) &Device );
|
|
|
|
|
/*
|
|
|
|
|
tmpdevice->Release();
|
|
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice::QueryInterface", m_sName.c_str()) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*/
|
2011-02-14 01:43:41 -06:00
|
|
|
|
2011-02-14 03:16:32 -06:00
|
|
|
// should mouse be foreground? -aj
|
2010-01-26 21:00:30 -06:00
|
|
|
int coop = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
|
|
|
|
|
if( type == KEYBOARD )
|
|
|
|
|
coop = DISCL_NONEXCLUSIVE | DISCL_FOREGROUND;
|
|
|
|
|
|
|
|
|
|
hr = Device->SetCooperativeLevel( GraphicsWindow::GetHwnd(), coop );
|
|
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetCooperativeLevel", m_sName.c_str()) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 01:43:41 -06:00
|
|
|
switch(type)
|
|
|
|
|
{
|
|
|
|
|
case KEYBOARD:
|
|
|
|
|
hr = Device->SetDataFormat( &c_dfDIKeyboard );
|
|
|
|
|
break;
|
|
|
|
|
case JOYSTICK:
|
|
|
|
|
hr = Device->SetDataFormat( &c_dfDIJoystick );
|
|
|
|
|
break;
|
|
|
|
|
case MOUSE:
|
|
|
|
|
hr = Device->SetDataFormat( &c_dfDIMouse );
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-01-26 21:00:30 -06:00
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetDataFormat", m_sName.c_str()) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch( type )
|
|
|
|
|
{
|
2011-02-14 03:16:32 -06:00
|
|
|
case JOYSTICK:
|
|
|
|
|
Device->EnumObjects( DIJoystick_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
|
|
|
|
|
break;
|
|
|
|
|
case KEYBOARD:
|
|
|
|
|
// Always 256-button.
|
|
|
|
|
for( int b = 0; b < 256; ++b )
|
|
|
|
|
{
|
|
|
|
|
input_t in;
|
|
|
|
|
in.type = in.KEY;
|
|
|
|
|
|
|
|
|
|
in.num = ConvertScancodeToKey(b);
|
|
|
|
|
in.ofs = b;
|
|
|
|
|
buttons++;
|
|
|
|
|
Inputs.push_back(in);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MOUSE:
|
|
|
|
|
Device->EnumObjects( DIMouse_EnumDevObjectsProc, this, DIDFT_BUTTON | DIDFT_PSHBUTTON );
|
|
|
|
|
break;
|
2010-01-26 21:00:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
DIPROPDWORD dipdw;
|
|
|
|
|
memset(&dipdw, 0, sizeof(dipdw));
|
|
|
|
|
dipdw.diph.dwSize = sizeof(dipdw);
|
|
|
|
|
dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
|
|
|
|
|
dipdw.diph.dwObj = 0;
|
|
|
|
|
dipdw.diph.dwHow = DIPH_DEVICE;
|
|
|
|
|
dipdw.dwData = INPUT_QSIZE;
|
|
|
|
|
hr = Device->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph );
|
|
|
|
|
if ( hr == DI_POLLEDDEVICE )
|
|
|
|
|
{
|
|
|
|
|
/* This device doesn't support buffering, so we're forced
|
|
|
|
|
* to use less reliable polling. */
|
|
|
|
|
buffered = false;
|
|
|
|
|
}
|
|
|
|
|
else if ( hr != DI_OK )
|
|
|
|
|
{
|
|
|
|
|
LOG->Info( hr_ssprintf(hr, "OpenDevice(%s): IDirectInputDevice2::SetProperty", m_sName.c_str()) );
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DIDevice::Close()
|
|
|
|
|
{
|
2010-02-24 02:40:36 -06:00
|
|
|
// Don't try to close a device that isn't open.
|
2010-01-26 21:00:30 -06:00
|
|
|
ASSERT( Device != NULL );
|
|
|
|
|
|
|
|
|
|
Device->Unacquire();
|
|
|
|
|
Device->Release();
|
|
|
|
|
|
|
|
|
|
Device = NULL;
|
|
|
|
|
buttons = axes = hats = NULL;
|
|
|
|
|
Inputs.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BOOL CALLBACK DIJoystick_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data)
|
|
|
|
|
{
|
|
|
|
|
DIDevice *device = (DIDevice *) data;
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
|
|
input_t in;
|
|
|
|
|
const int SupportedMask = DIDFT_BUTTON | DIDFT_POV | DIDFT_AXIS;
|
|
|
|
|
if(!(dev->dwType & SupportedMask))
|
2011-02-14 01:43:41 -06:00
|
|
|
return DIENUM_CONTINUE; // unsupported
|
2010-01-26 21:00:30 -06:00
|
|
|
|
|
|
|
|
in.ofs = dev->dwOfs;
|
|
|
|
|
|
|
|
|
|
if(dev->dwType & DIDFT_BUTTON) {
|
|
|
|
|
if( device->buttons == 24 )
|
2010-02-24 02:40:36 -06:00
|
|
|
return DIENUM_CONTINUE; // too many buttons
|
2010-01-26 21:00:30 -06:00
|
|
|
|
|
|
|
|
in.type = in.BUTTON;
|
|
|
|
|
in.num = device->buttons;
|
|
|
|
|
device->buttons++;
|
|
|
|
|
} else if(dev->dwType & DIDFT_POV) {
|
|
|
|
|
in.type = in.HAT;
|
|
|
|
|
in.num = device->hats;
|
|
|
|
|
device->hats++;
|
2010-02-24 02:40:36 -06:00
|
|
|
} else { // dev->dwType & DIDFT_AXIS
|
2010-01-26 21:00:30 -06:00
|
|
|
DIPROPRANGE diprg;
|
|
|
|
|
DIPROPDWORD dilong;
|
2010-02-24 02:40:36 -06:00
|
|
|
|
2010-01-26 21:00:30 -06:00
|
|
|
in.type = in.AXIS;
|
|
|
|
|
in.num = device->axes;
|
2010-02-24 02:40:36 -06:00
|
|
|
|
2010-01-26 21:00:30 -06:00
|
|
|
diprg.diph.dwSize = sizeof(diprg);
|
|
|
|
|
diprg.diph.dwHeaderSize = sizeof(diprg.diph);
|
|
|
|
|
diprg.diph.dwObj = dev->dwOfs;
|
|
|
|
|
diprg.diph.dwHow = DIPH_BYOFFSET;
|
|
|
|
|
diprg.lMin = -100;
|
|
|
|
|
diprg.lMax = 100;
|
|
|
|
|
|
|
|
|
|
hr = device->Device->SetProperty( DIPROP_RANGE, &diprg.diph );
|
|
|
|
|
if ( hr != DI_OK )
|
2010-02-24 02:40:36 -06:00
|
|
|
return DIENUM_CONTINUE; // don't use this axis
|
|
|
|
|
|
|
|
|
|
// Set dead zone to 0.
|
2010-01-26 21:00:30 -06:00
|
|
|
dilong.diph.dwSize = sizeof(dilong);
|
|
|
|
|
dilong.diph.dwHeaderSize = sizeof(dilong.diph);
|
|
|
|
|
dilong.diph.dwObj = dev->dwOfs;
|
|
|
|
|
dilong.diph.dwHow = DIPH_BYOFFSET;
|
|
|
|
|
dilong.dwData = 0;
|
|
|
|
|
hr = device->Device->SetProperty( DIPROP_DEADZONE, &dilong.diph );
|
|
|
|
|
if ( hr != DI_OK )
|
|
|
|
|
return DIENUM_CONTINUE; /* don't use this axis */
|
|
|
|
|
|
|
|
|
|
device->axes++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
device->Inputs.push_back(in);
|
|
|
|
|
|
|
|
|
|
return DIENUM_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ConvertScancodeToKey( int scancode )
|
|
|
|
|
{
|
|
|
|
|
switch(scancode)
|
|
|
|
|
{
|
|
|
|
|
case DIK_ESCAPE: return KEY_ESC;
|
|
|
|
|
case DIK_1: return KEY_C1;
|
|
|
|
|
case DIK_2: return KEY_C2;
|
|
|
|
|
case DIK_3: return KEY_C3;
|
|
|
|
|
case DIK_4: return KEY_C4;
|
|
|
|
|
case DIK_5: return KEY_C5;
|
|
|
|
|
case DIK_6: return KEY_C6;
|
|
|
|
|
case DIK_7: return KEY_C7;
|
|
|
|
|
case DIK_8: return KEY_C8;
|
|
|
|
|
case DIK_9: return KEY_C9;
|
|
|
|
|
case DIK_0: return KEY_C0;
|
|
|
|
|
case DIK_MINUS: return KEY_HYPHEN;
|
|
|
|
|
case DIK_EQUALS: return KEY_EQUAL;
|
|
|
|
|
case DIK_BACK: return KEY_BACK;
|
|
|
|
|
case DIK_TAB: return KEY_TAB;
|
|
|
|
|
case DIK_Q: return KEY_Cq;
|
|
|
|
|
case DIK_W: return KEY_Cw;
|
|
|
|
|
case DIK_E: return KEY_Ce;
|
|
|
|
|
case DIK_R: return KEY_Cr;
|
|
|
|
|
case DIK_T: return KEY_Ct;
|
|
|
|
|
case DIK_Y: return KEY_Cy;
|
|
|
|
|
case DIK_U: return KEY_Cu;
|
|
|
|
|
case DIK_I: return KEY_Ci;
|
|
|
|
|
case DIK_O: return KEY_Co;
|
|
|
|
|
case DIK_P: return KEY_Cp;
|
|
|
|
|
case DIK_LBRACKET: return KEY_LBRACKET;
|
|
|
|
|
case DIK_RBRACKET: return KEY_RBRACKET;
|
|
|
|
|
case DIK_RETURN: return KEY_ENTER;
|
|
|
|
|
case DIK_LCONTROL: return KEY_LCTRL;
|
|
|
|
|
case DIK_A: return KEY_Ca;
|
|
|
|
|
case DIK_S: return KEY_Cs;
|
|
|
|
|
case DIK_D: return KEY_Cd;
|
|
|
|
|
case DIK_F: return KEY_Cf;
|
|
|
|
|
case DIK_G: return KEY_Cg;
|
|
|
|
|
case DIK_H: return KEY_Ch;
|
|
|
|
|
case DIK_J: return KEY_Cj;
|
|
|
|
|
case DIK_K: return KEY_Ck;
|
|
|
|
|
case DIK_L: return KEY_Cl;
|
|
|
|
|
case DIK_SEMICOLON: return KEY_SEMICOLON;
|
|
|
|
|
case DIK_APOSTROPHE: return KEY_SQUOTE;
|
|
|
|
|
case DIK_GRAVE: return KEY_ACCENT;
|
|
|
|
|
case DIK_LSHIFT: return KEY_LSHIFT;
|
|
|
|
|
case DIK_BACKSLASH: return KEY_BACKSLASH;
|
|
|
|
|
case DIK_OEM_102: return KEY_BACKSLASH;
|
|
|
|
|
case DIK_Z: return KEY_Cz;
|
|
|
|
|
case DIK_X: return KEY_Cx;
|
|
|
|
|
case DIK_C: return KEY_Cc;
|
|
|
|
|
case DIK_V: return KEY_Cv;
|
|
|
|
|
case DIK_B: return KEY_Cb;
|
|
|
|
|
case DIK_N: return KEY_Cn;
|
|
|
|
|
case DIK_M: return KEY_Cm;
|
|
|
|
|
case DIK_COMMA: return KEY_COMMA;
|
|
|
|
|
case DIK_PERIOD: return KEY_PERIOD;
|
|
|
|
|
case DIK_SLASH: return KEY_SLASH;
|
|
|
|
|
case DIK_RSHIFT: return KEY_RSHIFT;
|
|
|
|
|
case DIK_MULTIPLY: return KEY_KP_ASTERISK;
|
|
|
|
|
case DIK_LMENU: return KEY_LALT;
|
|
|
|
|
case DIK_SPACE: return KEY_SPACE;
|
|
|
|
|
case DIK_CAPITAL: return KEY_CAPSLOCK;
|
|
|
|
|
case DIK_F1: return KEY_F1;
|
|
|
|
|
case DIK_F2: return KEY_F2;
|
|
|
|
|
case DIK_F3: return KEY_F3;
|
|
|
|
|
case DIK_F4: return KEY_F4;
|
|
|
|
|
case DIK_F5: return KEY_F5;
|
|
|
|
|
case DIK_F6: return KEY_F6;
|
|
|
|
|
case DIK_F7: return KEY_F7;
|
|
|
|
|
case DIK_F8: return KEY_F8;
|
|
|
|
|
case DIK_F9: return KEY_F9;
|
|
|
|
|
case DIK_F10: return KEY_F10;
|
|
|
|
|
case DIK_NUMLOCK: return KEY_NUMLOCK;
|
|
|
|
|
case DIK_SCROLL: return KEY_SCRLLOCK;
|
|
|
|
|
case DIK_NUMPAD7: return KEY_KP_C7;
|
|
|
|
|
case DIK_NUMPAD8: return KEY_KP_C8;
|
|
|
|
|
case DIK_NUMPAD9: return KEY_KP_C9;
|
|
|
|
|
case DIK_SUBTRACT: return KEY_KP_HYPHEN;
|
|
|
|
|
case DIK_NUMPAD4: return KEY_KP_C4;
|
|
|
|
|
case DIK_NUMPAD5: return KEY_KP_C5;
|
|
|
|
|
case DIK_NUMPAD6: return KEY_KP_C6;
|
|
|
|
|
case DIK_ADD: return KEY_KP_PLUS;
|
|
|
|
|
case DIK_NUMPAD1: return KEY_KP_C1;
|
|
|
|
|
case DIK_NUMPAD2: return KEY_KP_C2;
|
|
|
|
|
case DIK_NUMPAD3: return KEY_KP_C3;
|
|
|
|
|
case DIK_NUMPAD0: return KEY_KP_C0;
|
|
|
|
|
case DIK_DECIMAL: return KEY_KP_PERIOD;
|
|
|
|
|
case DIK_F11: return KEY_F11;
|
|
|
|
|
case DIK_F12: return KEY_F12;
|
|
|
|
|
|
|
|
|
|
case DIK_F13: return KEY_F13;
|
|
|
|
|
case DIK_F14: return KEY_F14;
|
|
|
|
|
case DIK_F15: return KEY_F15;
|
|
|
|
|
|
|
|
|
|
case DIK_NUMPADEQUALS: return KEY_KP_EQUAL;
|
|
|
|
|
case DIK_NUMPADENTER: return KEY_KP_ENTER;
|
|
|
|
|
case DIK_RCONTROL: return KEY_RCTRL;
|
|
|
|
|
case DIK_DIVIDE: return KEY_KP_SLASH;
|
|
|
|
|
case DIK_SYSRQ: return KEY_PRTSC;
|
|
|
|
|
case DIK_RMENU: return KEY_RALT;
|
|
|
|
|
case DIK_PAUSE: return KEY_PAUSE;
|
|
|
|
|
case DIK_HOME: return KEY_HOME;
|
|
|
|
|
case DIK_UP: return KEY_UP;
|
|
|
|
|
case DIK_PRIOR: return KEY_PGUP;
|
|
|
|
|
case DIK_LEFT: return KEY_LEFT;
|
|
|
|
|
case DIK_RIGHT: return KEY_RIGHT;
|
|
|
|
|
case DIK_END: return KEY_END;
|
|
|
|
|
case DIK_DOWN: return KEY_DOWN;
|
|
|
|
|
case DIK_NEXT: return KEY_PGDN;
|
|
|
|
|
case DIK_INSERT: return KEY_INSERT;
|
|
|
|
|
case DIK_DELETE: return KEY_DEL;
|
|
|
|
|
case DIK_LWIN: return KEY_LMETA;
|
|
|
|
|
case DIK_RWIN: return KEY_RMETA;
|
|
|
|
|
case DIK_APPS: return KEY_MENU;
|
|
|
|
|
default: return '?';
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-14 01:43:41 -06:00
|
|
|
static BOOL CALLBACK DIMouse_EnumDevObjectsProc(LPCDIDEVICEOBJECTINSTANCE dev, LPVOID data)
|
|
|
|
|
{
|
2011-02-14 03:16:32 -06:00
|
|
|
/*
|
2011-02-14 01:43:41 -06:00
|
|
|
DIDevice *device = (DIDevice *) data;
|
|
|
|
|
|
|
|
|
|
input_t in;
|
|
|
|
|
// todo: check mask for accuracy -aj
|
2011-02-14 14:16:24 -06:00
|
|
|
const int SupportedMask = DIDFT_BUTTON;
|
2011-02-14 01:43:41 -06:00
|
|
|
if(!(dev->dwType & SupportedMask))
|
|
|
|
|
return DIENUM_CONTINUE; // unsupported
|
|
|
|
|
|
|
|
|
|
// xxx: does this check for scrollwheels? -aj
|
2011-02-14 14:16:24 -06:00
|
|
|
if(dev->dwType & DIDFT_BUTTON ) {
|
2011-02-14 01:43:41 -06:00
|
|
|
in.type = in.BUTTON;
|
|
|
|
|
in.num = device->buttons;
|
|
|
|
|
device->buttons++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
device->Inputs.push_back(in);
|
2011-02-14 03:16:32 -06:00
|
|
|
*/
|
2011-02-14 01:43:41 -06:00
|
|
|
|
|
|
|
|
return DIENUM_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* (c) 2003-2011 Glenn Maynard, AJ Kelly
|
2010-01-26 21:00:30 -06:00
|
|
|
* All rights reserved.
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, and/or sell copies of the Software, and to permit persons to
|
|
|
|
|
* whom the Software is furnished to do so, provided that the above
|
|
|
|
|
* copyright notice(s) and this permission notice appear in all copies of
|
|
|
|
|
* the Software and that both the above copyright notice(s) and this
|
|
|
|
|
* permission notice appear in supporting documentation.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
|
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
|
|
|
|
|
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
|
|
|
|
|
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
|
|
|
|
|
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
|
|
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
|
*/
|