#pragma once #include "std.hpp" #include "gxinput.hpp" #include "gxruntime.hpp" static const int QUE_SIZE = 32; class Device : public gxDevice { public: bool acquired; gxInput *input; LPDIRECTINPUTDEVICE8 device; Device(gxInput *i, LPDIRECTINPUTDEVICE8 d) :input(i), acquired(false), device(d) { } virtual ~Device() { device->Release(); //device->Release(); } bool acquire() { return device->Acquire() >= 0; //return acquired=device->Acquire()>=0; } void unacquire() { device->Unacquire(); //device->Unacquire(); acquired = false; } }; class Keyboard : public Device { public: Keyboard(gxInput *i, LPDIRECTINPUTDEVICE8 d) :Device(i, d) { } void update() { if (!acquired) { input->runtime->idle(); return; } int k, cnt = 32; DIDEVICEOBJECTDATA data[32], *curr; if (device->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), data, (DWORD*)&cnt, 0) < 0) return; curr = data; for (k = 0; k < cnt; ++curr, ++k) { int n = curr->dwOfs; if (!n || n > 255) continue; if (curr->dwData & 0x80) downEvent(n); else upEvent(n); } } }; class Mouse : public Device { public: Mouse(gxInput *i, LPDIRECTINPUTDEVICE8 d) :Device(i, d) { } void update() { if (!acquired) { input->runtime->idle(); return; } DIMOUSESTATE state; if (device->GetDeviceState(sizeof(state), &state) < 0) return; if (gxGraphics *g = input->runtime->graphics) { int mx = axis_states[0] + state.lX; int my = axis_states[1] + state.lY; if (mx < 0) mx = 0; else if (mx >= g->getWidth()) mx = g->getWidth() - 1; if (my < 0) my = 0; else if (my >= g->getHeight()) my = g->getHeight() - 1; axis_states[0] = mx; axis_states[1] = my; axis_states[2] += state.lZ; } for (int k = 0; k < 3; ++k) { setDownState(k + 1, state.rgbButtons[k] & 0x80 ? true : false); } } }; class Joystick : public Device { public: int type, poll_time; int mins[12], maxs[12]; Joystick(gxInput *i, LPDIRECTINPUTDEVICE8 d, int t) :Device(i, d), type(t), poll_time(0) { for (int k = 0; k < 12; ++k) { //initialize joystick axis ranges (d'oh!) DIPROPRANGE range; range.diph.dwSize = sizeof(DIPROPRANGE); range.diph.dwHeaderSize = sizeof(DIPROPHEADER); range.diph.dwObj = k * 4 + 12; range.diph.dwHow = DIPH_BYOFFSET; if (d->GetProperty(DIPROP_RANGE, &range.diph) < 0) { mins[k] = 0; maxs[k] = 65535; continue; } mins[k] = range.lMin; maxs[k] = range.lMax - range.lMin; } } void update() { unsigned tm = timeGetTime(); if (tm - poll_time < 3) return; if (device->Poll() < 0) { acquired = false; input->runtime->idle(); acquire(); if (device->Poll() < 0) return; } poll_time = tm; DIJOYSTATE state; if (device->GetDeviceState(sizeof(state), &state) < 0) return; axis_states[0] = (state.lX - mins[0]) / (float)maxs[0] * 2 - 1; axis_states[1] = (state.lY - mins[1]) / (float)maxs[1] * 2 - 1; axis_states[2] = (state.lZ - mins[2]) / (float)maxs[2] * 2 - 1; axis_states[3] = (state.rglSlider[0] - mins[6]) / (float)maxs[6] * 2 - 1; axis_states[4] = (state.rglSlider[1] - mins[7]) / (float)maxs[7] * 2 - 1; axis_states[5] = (state.lRx - mins[3]) / (float)maxs[3] * 2 - 1; axis_states[6] = (state.lRy - mins[4]) / (float)maxs[4] * 2 - 1; axis_states[7] = (state.lRz - mins[5]) / (float)maxs[5] * 2 - 1; if ((state.rgdwPOV[0] & 0xffff) == 0xffff) axis_states[8] = -1; else axis_states[8] = floor(state.rgdwPOV[0] / 100.0f + .5f); for (int k = 0; k < 31; ++k) { setDownState(k + 1, state.rgbButtons[k] & 0x80 ? true : false); } } }; static Keyboard *keyboard; static Mouse *mouse; static vector joysticks; static Keyboard *createKeyboard(gxInput *input) { LPDIRECTINPUTDEVICE8 dev; if (input->dirInput->CreateDevice(GUID_SysKeyboard, &dev, NULL) >= 0) { if (dev->SetCooperativeLevel(input->runtime->hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE) >= 0) { if (dev->SetDataFormat(&c_dfDIKeyboard) >= 0) { DIPROPDWORD dword; memset(&dword, 0, sizeof(dword)); dword.diph.dwSize = sizeof(DIPROPDWORD); dword.diph.dwHeaderSize = sizeof(DIPROPHEADER); dword.diph.dwObj = 0; dword.diph.dwHow = DIPH_DEVICE; dword.dwData = 32; if (dev->SetProperty(DIPROP_BUFFERSIZE, &dword.diph) >= 0) { return new Keyboard(input, dev); } else { // input->runtime->debugInfo( "keyboard: SetProperty failed" ); } } else { // input->runtime->debugInfo( "keyboard: SetDataFormat failed" ); } return new Keyboard(input, dev); } else { input->runtime->debugInfo("keyboard: SetCooperativeLevel failed"); } dev->Release(); } else { input->runtime->debugInfo("keyboard: CreateDeviceEx failed"); } return 0; } static Mouse *createMouse(gxInput *input) { LPDIRECTINPUTDEVICE8 dev; if (input->dirInput->CreateDevice(GUID_SysMouse, &dev, 0) >= 0) { if (dev->SetCooperativeLevel(input->runtime->hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE) >= 0) { if (dev->SetDataFormat(&c_dfDIMouse) >= 0) { return new Mouse(input, dev); } else { // input->runtime->debugInfo( "mouse: SetDataFormat failed" ); } return new Mouse(input, dev); } else { input->runtime->debugInfo("mouse: SetCooperativeLevel failed"); } dev->Release(); } else { input->runtime->debugInfo("mouse: CreateDeviceEx failed"); } return 0; } static Joystick *createJoystick(gxInput *input, LPCDIDEVICEINSTANCE devinst) { LPDIRECTINPUTDEVICE8 dev; if (input->dirInput->CreateDevice(devinst->guidInstance, &dev, 0) >= 0) { if (dev->SetCooperativeLevel(input->runtime->hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE) >= 0) { if (dev->SetDataFormat(&c_dfDIJoystick) >= 0) { int t = ((devinst->dwDevType >> 8) & 0xff) == DI8DEVCLASS_GAMECTRL ? 1 : 2; return new Joystick(input, dev, t); } } dev->Release(); } return 0; } static BOOL CALLBACK enumJoystick(LPCDIDEVICEINSTANCE devinst, LPVOID pvRef) { if ((devinst->dwDevType & 0xff) != DI8DEVCLASS_GAMECTRL) return DIENUM_CONTINUE; if (Joystick *joy = createJoystick((gxInput*)pvRef, devinst)) { joysticks.push_back(joy); } return DIENUM_CONTINUE; } gxInput::gxInput(gxRuntime *rt, LPDIRECTINPUT8 di) : runtime(rt), dirInput(di) { keyboard = createKeyboard(this); mouse = createMouse(this); joysticks.clear(); dirInput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumJoystick, this, DIEDFL_ATTACHEDONLY); } gxInput::~gxInput() { for (int k = 0; k < joysticks.size(); ++k) delete joysticks[k]; joysticks.clear(); delete mouse; delete keyboard; dirInput->Release(); } void gxInput::wm_keydown(int key) { if (keyboard) keyboard->downEvent(key); } void gxInput::wm_keyup(int key) { if (keyboard) keyboard->upEvent(key); } void gxInput::wm_mousedown(int key) { if (mouse) mouse->downEvent(key); } void gxInput::wm_mouseup(int key) { if (mouse) mouse->upEvent(key); } void gxInput::wm_mousemove(int x, int y) { if (mouse) { mouse->axis_states[0] = x; mouse->axis_states[1] = y; } } void gxInput::wm_mousewheel(int dz) { if (mouse) mouse->axis_states[2] += dz; } void gxInput::reset() { if (mouse) mouse->reset(); if (keyboard) keyboard->reset(); for (int k = 0; k < joysticks.size(); ++k) joysticks[k]->reset(); } bool gxInput::acquire() { bool m_ok = true, k_ok = true; if (mouse) m_ok = mouse->acquire(); if (keyboard) k_ok = keyboard->acquire(); if (m_ok && k_ok) return true; if (k_ok) keyboard->unacquire(); if (m_ok) mouse->unacquire(); return false; } void gxInput::unacquire() { if (keyboard) keyboard->unacquire(); if (mouse) mouse->unacquire(); } void gxInput::moveMouse(int x, int y) { if (!mouse) return; mouse->axis_states[0] = x; mouse->axis_states[1] = y; runtime->moveMouse(x, y); } gxDevice *gxInput::getMouse()const { return mouse; } gxDevice *gxInput::getKeyboard()const { return keyboard; } gxDevice *gxInput::getJoystick(int n)const { return n >= 0 && n < joysticks.size() ? joysticks[n] : 0; } int gxInput::getJoystickType(int n)const { return n >= 0 && n < joysticks.size() ? joysticks[n]->type : 0; } int gxInput::numJoysticks()const { return joysticks.size(); } int gxInput::toAscii(int scan)const { switch (scan) { case DIK_INSERT:return ASC_INSERT; case DIK_DELETE:return ASC_DELETE; case DIK_HOME:return ASC_HOME; case DIK_END:return ASC_END; case DIK_PGUP:return ASC_PAGEUP; case DIK_PGDN:return ASC_PAGEDOWN; case DIK_UP:return ASC_UP; case DIK_DOWN:return ASC_DOWN; case DIK_LEFT:return ASC_LEFT; case DIK_RIGHT:return ASC_RIGHT; } scan &= 0x7f; int virt = MapVirtualKey(scan, 1); if (!virt) return 0; static unsigned char mat[256]; mat[VK_LSHIFT] = keyboard->keyDown(DIK_LSHIFT) ? 0x80 : 0; mat[VK_RSHIFT] = keyboard->keyDown(DIK_RSHIFT) ? 0x80 : 0; mat[VK_SHIFT] = mat[VK_LSHIFT] | mat[VK_RSHIFT]; mat[VK_LCONTROL] = keyboard->keyDown(DIK_LCONTROL) ? 0x80 : 0; mat[VK_RCONTROL] = keyboard->keyDown(DIK_RCONTROL) ? 0x80 : 0; mat[VK_CONTROL] = mat[VK_LCONTROL] | mat[VK_RCONTROL]; mat[VK_LMENU] = keyboard->keyDown(DIK_LMENU) ? 0x80 : 0; mat[VK_RMENU] = keyboard->keyDown(DIK_RMENU) ? 0x80 : 0; mat[VK_MENU] = mat[VK_LMENU] | mat[VK_RMENU]; WORD ch; if (ToAscii(virt, scan, mat, &ch, 0) != 1) return 0; return ch & 255; }