From 17ae4f9f56d85c7aa7c4c1c10cc3e79c12676f47 Mon Sep 17 00:00:00 2001 From: DJRobX Date: Wed, 7 Nov 2007 09:24:46 +0000 Subject: [PATCH] Direct3d fixes, disabling lockable backbuffers. Official 1.8 beta seems to have an incomplete direct3d implementation. You cannot select full screen modes without using DirectDraw. This is fixed in this buld git-svn-id: https://svn.code.sf.net/p/vbam/code/trunk@27 a31d4220-a93d-0410-bf67-fe4944624d44 --- src/win32/Direct3D.cpp | 1276 ++++++++++++------------- src/win32/DirectInput.cpp | 1858 ++++++++++++++++++------------------- 2 files changed, 1573 insertions(+), 1561 deletions(-) diff --git a/src/win32/Direct3D.cpp b/src/win32/Direct3D.cpp index aba02150..81062b72 100644 --- a/src/win32/Direct3D.cpp +++ b/src/win32/Direct3D.cpp @@ -1,116 +1,117 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team -// Copyright (C) 2005-2006 VBA development team - -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2, or(at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "stdafx.h" - -#include "Display.h" - -#include "MainWnd.h" - -#include "../System.h" -#include "../GBA.h" -#include "../Globals.h" -#include "../Text.h" -#include "../Util.h" -#include "../gb/gbGlobals.h" - -// Direct3D -#define DIRECT3D_VERSION 0x0900 -#include // main include file -#include // required for font rednering -#include // contains debug functions - -extern int Init_2xSaI(u32); // initializes all pixel filters -extern int systemSpeed; - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -#ifdef MMX -extern "C" bool cpu_mmx; -extern bool detectMMX(); -#endif - - -class Direct3DDisplay : public IDisplay { -private: - LPDIRECT3D9 pD3D; - LPDIRECT3DDEVICE9 pDevice; - D3DDISPLAYMODE mode; - D3DPRESENT_PARAMETERS dpp; - D3DFORMAT screenFormat; - LPDIRECT3DSURFACE9 emulatedImage; - D3DTEXTUREFILTERTYPE filter; - int width; - int height; - RECT destRect; - bool failed; - ID3DXFont *pFont; - - void createFont(); - void destroyFont(); - void createSurface(); - void destroySurface(); - void calculateDestRect(); - bool resetDevice(); - void setPresentationType(); - -public: - Direct3DDisplay(); - virtual ~Direct3DDisplay(); - virtual DISPLAY_TYPE getType() { return DIRECT_3D; }; - - virtual bool initialize(); - virtual void cleanup(); - virtual void clear(); - virtual void render(); - - virtual void renderMenu(); - virtual bool changeRenderSize( int w, int h ); - virtual void resize( int w, int h ); - virtual void setOption( const char *option, int value ); - virtual int selectFullScreenMode( GUID ** ); -}; - - -Direct3DDisplay::Direct3DDisplay() -{ - pD3D = NULL; - pDevice = NULL; - screenFormat = D3DFMT_X8R8G8B8; - width = 0; - height = 0; - failed = false; - pFont = NULL; - emulatedImage = NULL; - filter = D3DTEXF_POINT; -} - - -Direct3DDisplay::~Direct3DDisplay() -{ - cleanup(); -} - +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team +// Copyright (C) 2005-2006 VBA development team + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or(at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "stdafx.h" + +#include "Display.h" + +#include "MainWnd.h" + +#include "../System.h" +#include "../GBA.h" +#include "../Globals.h" +#include "../Text.h" +#include "../Util.h" +#include "../gb/gbGlobals.h" + +// Direct3D +#define DIRECT3D_VERSION 0x0900 +#include // main include file +#include // required for font rednering +#include // contains debug functions + +extern int Init_2xSaI(u32); // initializes all pixel filters +extern int systemSpeed; + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +#ifdef MMX +extern "C" bool cpu_mmx; +extern bool detectMMX(); +#endif + +extern int winVideoModeSelect(CWnd *, GUID **); + +class Direct3DDisplay : public IDisplay { +private: + LPDIRECT3D9 pD3D; + LPDIRECT3DDEVICE9 pDevice; + D3DDISPLAYMODE mode; + D3DPRESENT_PARAMETERS dpp; + D3DFORMAT screenFormat; + LPDIRECT3DSURFACE9 emulatedImage; + D3DTEXTUREFILTERTYPE filter; + int width; + int height; + RECT destRect; + bool failed; + ID3DXFont *pFont; + + void createFont(); + void destroyFont(); + void createSurface(); + void destroySurface(); + void calculateDestRect(); + bool resetDevice(); + void setPresentationType(); + +public: + Direct3DDisplay(); + virtual ~Direct3DDisplay(); + virtual DISPLAY_TYPE getType() { return DIRECT_3D; }; + + virtual bool initialize(); + virtual void cleanup(); + virtual void clear(); + virtual void render(); + + virtual void renderMenu(); + virtual bool changeRenderSize( int w, int h ); + virtual void resize( int w, int h ); + virtual void setOption( const char *option, int value ); + virtual int selectFullScreenMode( GUID ** ); +}; + + +Direct3DDisplay::Direct3DDisplay() +{ + pD3D = NULL; + pDevice = NULL; + screenFormat = D3DFMT_X8R8G8B8; + width = 0; + height = 0; + failed = false; + pFont = NULL; + emulatedImage = NULL; + filter = D3DTEXF_POINT; +} + + +Direct3DDisplay::~Direct3DDisplay() +{ + cleanup(); +} + void Direct3DDisplay::setPresentationType() { // Change display mode @@ -134,523 +135,534 @@ void Direct3DDisplay::setPresentationType() else dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // No Sync } - - -void Direct3DDisplay::cleanup() -{ - destroyFont(); - destroySurface(); - - if( pDevice ) { - pDevice->Release(); - pDevice = NULL; - } - - if( pD3D ) { - pD3D->Release(); - pD3D = NULL; - } -} - - -bool Direct3DDisplay::initialize() -{ - switch(theApp.cartridgeType) - { - case IMAGE_GBA: - theApp.sizeX = 240; - theApp.sizeY = 160; - break; - case IMAGE_GB: - if (gbBorderOn) - { - theApp.sizeX = 256; - theApp.sizeY = 224; - } - else - { - theApp.sizeX = 160; - theApp.sizeY = 144; - } - break; - } - - - switch(theApp.videoOption) - { - case VIDEO_1X: - theApp.surfaceSizeX = theApp.sizeX; - theApp.surfaceSizeY = theApp.sizeY; - break; - case VIDEO_2X: - theApp.surfaceSizeX = theApp.sizeX * 2; - theApp.surfaceSizeY = theApp.sizeY * 2; - break; - case VIDEO_3X: - theApp.surfaceSizeX = theApp.sizeX * 3; - theApp.surfaceSizeY = theApp.sizeY * 3; - break; - case VIDEO_4X: - theApp.surfaceSizeX = theApp.sizeX * 4; - theApp.surfaceSizeY = theApp.sizeY * 4; - break; - case VIDEO_320x240: - case VIDEO_640x480: - case VIDEO_800x600: - case VIDEO_1024x768: - case VIDEO_1280x1024: - case VIDEO_OTHER: - float scaleX = ((float)theApp.fsWidth / theApp.sizeX); - float scaleY = ((float)theApp.fsHeight / theApp.sizeY); - float min = (scaleX < scaleY) ? scaleX : scaleY; - if(theApp.fullScreenStretch) { - theApp.surfaceSizeX = theApp.fsWidth; - theApp.surfaceSizeY = theApp.fsHeight; - } else { - theApp.surfaceSizeX = (int)(theApp.sizeX * min); - theApp.surfaceSizeY = (int)(theApp.sizeY * min); - } - break; - } - - theApp.rect.left = 0; - theApp.rect.top = 0; - theApp.rect.right = theApp.sizeX; - theApp.rect.bottom = theApp.sizeY; - - theApp.dest.left = 0; - theApp.dest.top = 0; - theApp.dest.right = theApp.surfaceSizeX; - theApp.dest.bottom = theApp.surfaceSizeY; - - - DWORD style = WS_POPUP | WS_VISIBLE; - DWORD styleEx = 0; - - if(theApp.videoOption <= VIDEO_4X) { - style |= WS_OVERLAPPEDWINDOW; - } else { - styleEx = 0; - } - - if(theApp.videoOption <= VIDEO_4X) { - AdjustWindowRectEx(&theApp.dest, style, TRUE, styleEx); - } else { - AdjustWindowRectEx(&theApp.dest, style, FALSE, styleEx); - } - - int winSizeX = theApp.dest.right-theApp.dest.left; - int winSizeY = theApp.dest.bottom-theApp.dest.top; - - if(theApp.videoOption > VIDEO_4X) { - winSizeX = theApp.fsWidth; - winSizeY = theApp.fsHeight; - } - - int x = 0, y = 0; - - if(theApp.videoOption <= VIDEO_4X) { - x = theApp.windowPositionX; - y = theApp.windowPositionY; - } - - - // Create a window - MainWnd *pWnd = new MainWnd; - theApp.m_pMainWnd = pWnd; - - pWnd->CreateEx(styleEx, - theApp.wndClass, - _T("VisualBoyAdvance"), - style, - x,y,winSizeX,winSizeY, - NULL, - 0); - - if (!(HWND)*pWnd) { - DXTRACE_ERR_MSGBOX( _T("Error creating window"), 0 ); - return FALSE; - } - pWnd->DragAcceptFiles(TRUE); - theApp.updateMenuBar(); - theApp.adjustDestRect(); - - - // load Direct3D v9 - pD3D = Direct3DCreate9( D3D_SDK_VERSION ); - - if(pD3D == NULL) { - DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D object"), 0 ); - return FALSE; - } - - theApp.mode320Available = FALSE; - theApp.mode640Available = FALSE; - theApp.mode800Available = FALSE; - theApp.mode1024Available = FALSE; - theApp.mode1280Available = FALSE; - - pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode); - screenFormat = mode.Format; - - switch(mode.Format) { - case D3DFMT_R8G8B8: - systemColorDepth = 24; - systemRedShift = 19; - systemGreenShift = 11; - systemBlueShift = 3; - break; - case D3DFMT_X8R8G8B8: - systemColorDepth = 32; - systemRedShift = 19; - systemGreenShift = 11; - systemBlueShift = 3; - Init_2xSaI(32); - break; - case D3DFMT_R5G6B5: - systemColorDepth = 16; - systemRedShift = 11; - systemGreenShift = 6; - systemBlueShift = 0; - Init_2xSaI(565); - break; - case D3DFMT_X1R5G5B5: - systemColorDepth = 16; - systemRedShift = 10; - systemGreenShift = 5; - systemBlueShift = 0; - Init_2xSaI(555); - break; - default: - DXTRACE_ERR_MSGBOX( _T("Unsupport D3D format"), 0 ); - return false; - } - theApp.fsColorDepth = systemColorDepth; - utilUpdateSystemColorMaps(); - - -#ifdef MMX - if(!theApp.disableMMX) { - cpu_mmx = theApp.detectMMX(); - } else { - cpu_mmx = 0; - } -#endif - - - theApp.updateFilter(); - theApp.updateIFB(); - - - // create device - setPresentationType(); - - HRESULT hret = pD3D->CreateDevice( - D3DADAPTER_DEFAULT, - D3DDEVTYPE_HAL, - pWnd->GetSafeHwnd(), - D3DCREATE_SOFTWARE_VERTEXPROCESSING, - &dpp, - &pDevice); - if( FAILED( hret ) ) { - DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D device"), hret ); - return false; - } - - createFont(); - createSurface(); - calculateDestRect(); - - setOption( _T("d3dFilter"), theApp.d3dFilter ); - - if(failed) return false; - - return TRUE; -} - - -void Direct3DDisplay::renderMenu() -{ - checkFullScreen(); - if(theApp.m_pMainWnd) { - theApp.m_pMainWnd->DrawMenuBar(); - } -} - - -void Direct3DDisplay::clear() -{ - if( pDevice ) { - pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00,0x00,0x00), 0.0f, 0 ); - } -} - - -void Direct3DDisplay::render() -{ - if( failed ) return; - if(!pDevice) return; - if( FAILED( pDevice->TestCooperativeLevel() ) ) return; - - clear(); - - pDevice->BeginScene(); - - // copy pix to emulatedImage and apply pixel filter if selected - HRESULT hr; - D3DLOCKED_RECT lr; - if( FAILED( hr = emulatedImage->LockRect( &lr, NULL, D3DLOCK_DISCARD ) ) ) { - DXTRACE_ERR_MSGBOX( _T("Can not lock back buffer"), hr ); - return; - } else { - if( !theApp.filterFunction ) { - copyImage( pix, lr.pBits, theApp.sizeX, theApp.sizeY, lr.Pitch, systemColorDepth ); - } else { - u32 pitch = theApp.filterWidth * (systemColorDepth>>3) + 4; - theApp.filterFunction( pix + pitch, - pitch, - (u8*)theApp.delta, - (u8*)lr.pBits, - lr.Pitch, - theApp.filterWidth, - theApp.filterHeight); - } - emulatedImage->UnlockRect(); - } - - // copy emulatedImage to pBackBuffer and scale with or without aspect ratio - LPDIRECT3DSURFACE9 pBackBuffer; - pDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ); - if( theApp.fullScreenStretch ) { - pDevice->StretchRect( emulatedImage, NULL, pBackBuffer, NULL, filter ); - } else { - pDevice->StretchRect( emulatedImage, NULL, pBackBuffer, &destRect, filter ); - } - pBackBuffer->Release(); - pBackBuffer = NULL; - - D3DCOLOR color; - RECT r; - r.left = 4; - r.right = dpp.BackBufferWidth - 4; - - if( theApp.screenMessage ) { - color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0xFF, 0x00, 0x00) : D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00); - if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !theApp.disableStatusMessage && pFont ) { - r.top = dpp.BackBufferHeight - 20; - r.bottom = dpp.BackBufferHeight - 4; - pFont->DrawText( NULL, theApp.screenMessageBuffer, -1, &r, 0, color ); - } else { - theApp.screenMessage = false; - } - } - - if( theApp.showSpeed && ( theApp.videoOption > VIDEO_4X ) ) { - color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0x00, 0x00, 0xFF) : D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0xFF); - char buffer[30]; - if( theApp.showSpeed == 1 ) { - sprintf( buffer, "%3d%%", systemSpeed ); - } else { - sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, theApp.showRenderedFrames ); - } - - r.top = 4; - r.bottom = 20; - pFont->DrawText( NULL, buffer, -1, &r, 0, color ); - } - - pDevice->EndScene(); - - pDevice->Present( NULL, NULL, NULL, NULL ); - - return; -} - - -bool Direct3DDisplay::changeRenderSize( int w, int h ) -{ - if( (w != width) || (h != height) ) { - width = w; height = h; - if( pDevice ) { - destroySurface(); - createSurface(); - calculateDestRect(); - } - } - return true; -} - - -void Direct3DDisplay::resize( int w, int h ) -{ - if( (w != dpp.BackBufferWidth) || (h != dpp.BackBufferHeight) ) { - dpp.BackBufferWidth = (UINT)w; - dpp.BackBufferHeight = (UINT)h; - resetDevice(); - calculateDestRect(); - } -} - - -int Direct3DDisplay::selectFullScreenMode( GUID ** ) -{ - HRESULT hr; - D3DDISPLAYMODE dm; - if( FAILED( hr = pDevice->GetDisplayMode( 0, &dm ) ) ) { - DXTRACE_ERR_MSGBOX( _T("pDevice->GetDisplayMode failed"), hr ); - return false; - } - - UINT bitsPerPixel; - switch( dm.Format ) - { - case D3DFMT_A2R10G10B10: - case D3DFMT_X8R8G8B8: - bitsPerPixel = 32; - break; - case D3DFMT_X1R5G5B5: - case D3DFMT_R5G6B5: - bitsPerPixel = 16; - break; - } - - return (bitsPerPixel << 24) | (dm.Width << 12) | dm.Height; -} - - -void Direct3DDisplay::createFont() -{ - if( !pFont ) { - HRESULT hr = D3DXCreateFont( - pDevice, - 14, - 0, - FW_BOLD, - 1, - FALSE, - DEFAULT_CHARSET, - OUT_DEFAULT_PRECIS, - DEFAULT_QUALITY, - DEFAULT_PITCH || FF_DONTCARE, - _T("Arial"), - &pFont ); - if( FAILED( hr ) ) { - DXTRACE_ERR_MSGBOX( _T("createFont failed"), hr ); - } - } -} - - -void Direct3DDisplay::destroyFont() -{ - if( pFont ) { - pFont->Release(); - pFont = NULL; - } -} - - -void Direct3DDisplay::createSurface() -{ - if( !emulatedImage ) { - HRESULT hr = pDevice->CreateOffscreenPlainSurface( - width, height, - dpp.BackBufferFormat, - D3DPOOL_DEFAULT, - &emulatedImage, - NULL ); - if( FAILED( hr ) ) { - DXTRACE_ERR_MSGBOX( _T("createSurface failed"), hr ); - } - } -} - - -void Direct3DDisplay::destroySurface() -{ - if( emulatedImage ) { - emulatedImage->Release(); - emulatedImage = NULL; - } -} - - -void Direct3DDisplay::calculateDestRect() -{ - float scaleX = (float)dpp.BackBufferWidth / (float)width; - float scaleY = (float)dpp.BackBufferHeight / (float)height; - float min = (scaleX < scaleY) ? scaleX : scaleY; - if( theApp.fsMaxScale && (min > theApp.fsMaxScale) ) { - min = (float)theApp.fsMaxScale; - } - destRect.left = 0; - destRect.top = 0; - destRect.right = (LONG)(width * min); - destRect.bottom = (LONG)(height * min); - if( destRect.right != dpp.BackBufferWidth ) { - LONG diff = (dpp.BackBufferWidth - destRect.right) / 2; - destRect.left += diff; - destRect.right += diff; - } - if( destRect.bottom != dpp.BackBufferHeight ) { - LONG diff = (dpp.BackBufferHeight - destRect.bottom) / 2; - destRect.top += diff; - destRect.bottom += diff; - } -} - - -void Direct3DDisplay::setOption( const char *option, int value ) -{ - if( !_tcscmp( option, _T("vsync") ) ) { - theApp.vsync = true; - resetDevice(); - } - - if( !_tcscmp( option, _T("tripleBuffering") ) ) { - theApp.tripleBuffering = true; - resetDevice(); - } - - if( !_tcscmp( option, _T("d3dFilter") ) ) { - switch( value ) - { - case 0: //point - filter = D3DTEXF_POINT; - break; - case 1: //linear - filter = D3DTEXF_LINEAR; - break; - } - } - - if( !_tcscmp( option, _T("maxScale") ) ) { - calculateDestRect(); - } -} - - -bool Direct3DDisplay::resetDevice() -{ - if( !pDevice ) return false; - - HRESULT hr; - destroyFont(); - destroySurface(); + + +void Direct3DDisplay::cleanup() +{ + destroyFont(); + destroySurface(); + + if( pDevice ) { + pDevice->Release(); + pDevice = NULL; + } + + if( pD3D ) { + pD3D->Release(); + pD3D = NULL; + } +} + + +bool Direct3DDisplay::initialize() +{ + switch(theApp.cartridgeType) + { + case IMAGE_GBA: + theApp.sizeX = 240; + theApp.sizeY = 160; + break; + case IMAGE_GB: + if (gbBorderOn) + { + theApp.sizeX = 256; + theApp.sizeY = 224; + } + else + { + theApp.sizeX = 160; + theApp.sizeY = 144; + } + break; + } + + + switch(theApp.videoOption) + { + case VIDEO_1X: + theApp.surfaceSizeX = theApp.sizeX; + theApp.surfaceSizeY = theApp.sizeY; + break; + case VIDEO_2X: + theApp.surfaceSizeX = theApp.sizeX * 2; + theApp.surfaceSizeY = theApp.sizeY * 2; + break; + case VIDEO_3X: + theApp.surfaceSizeX = theApp.sizeX * 3; + theApp.surfaceSizeY = theApp.sizeY * 3; + break; + case VIDEO_4X: + theApp.surfaceSizeX = theApp.sizeX * 4; + theApp.surfaceSizeY = theApp.sizeY * 4; + break; + case VIDEO_320x240: + case VIDEO_640x480: + case VIDEO_800x600: + case VIDEO_1024x768: + case VIDEO_1280x1024: + case VIDEO_OTHER: + float scaleX = ((float)theApp.fsWidth / theApp.sizeX); + float scaleY = ((float)theApp.fsHeight / theApp.sizeY); + float min = (scaleX < scaleY) ? scaleX : scaleY; + if(theApp.fullScreenStretch) { + theApp.surfaceSizeX = theApp.fsWidth; + theApp.surfaceSizeY = theApp.fsHeight; + } else { + theApp.surfaceSizeX = (int)(theApp.sizeX * min); + theApp.surfaceSizeY = (int)(theApp.sizeY * min); + } + break; + } + + theApp.rect.left = 0; + theApp.rect.top = 0; + theApp.rect.right = theApp.sizeX; + theApp.rect.bottom = theApp.sizeY; + + theApp.dest.left = 0; + theApp.dest.top = 0; + theApp.dest.right = theApp.surfaceSizeX; + theApp.dest.bottom = theApp.surfaceSizeY; + + + DWORD style = WS_POPUP | WS_VISIBLE; + DWORD styleEx = 0; + + if(theApp.videoOption <= VIDEO_4X) { + style |= WS_OVERLAPPEDWINDOW; + } else { + styleEx = 0; + } + + if(theApp.videoOption <= VIDEO_4X) { + AdjustWindowRectEx(&theApp.dest, style, TRUE, styleEx); + } else { + AdjustWindowRectEx(&theApp.dest, style, FALSE, styleEx); + } + + int winSizeX = theApp.dest.right-theApp.dest.left; + int winSizeY = theApp.dest.bottom-theApp.dest.top; + + if(theApp.videoOption > VIDEO_4X) { + winSizeX = theApp.fsWidth; + winSizeY = theApp.fsHeight; + } + + int x = 0, y = 0; + + if(theApp.videoOption <= VIDEO_4X) { + x = theApp.windowPositionX; + y = theApp.windowPositionY; + } + + + // Create a window + MainWnd *pWnd = new MainWnd; + theApp.m_pMainWnd = pWnd; + + pWnd->CreateEx(styleEx, + theApp.wndClass, + _T("VisualBoyAdvance"), + style, + x,y,winSizeX,winSizeY, + NULL, + 0); + + if (!(HWND)*pWnd) { + DXTRACE_ERR_MSGBOX( _T("Error creating window"), 0 ); + return FALSE; + } + pWnd->DragAcceptFiles(TRUE); + theApp.updateMenuBar(); + theApp.adjustDestRect(); + + + // load Direct3D v9 + pD3D = Direct3DCreate9( D3D_SDK_VERSION ); + + if(pD3D == NULL) { + DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D object"), 0 ); + return FALSE; + } + pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &mode); + + theApp.mode320Available = FALSE; + theApp.mode640Available = FALSE; + theApp.mode800Available = FALSE; + theApp.mode1024Available = FALSE; + theApp.mode1280Available = FALSE; + + unsigned int nModes, i; + D3DDISPLAYMODE dm; + + nModes = pD3D->GetAdapterModeCount(theApp.fsAdapter, mode.Format); + for (i = 0; iEnumAdapterModes(theApp.fsAdapter, mode.Format, i, &dm) ) + { + if ( (dm.Width == 320) && (dm.Height == 240) ) + theApp.mode320Available = true; + if ( (dm.Width == 640) && (dm.Height == 480) ) + theApp.mode640Available = true; + if ( (dm.Width == 800) && (dm.Height == 600) ) + theApp.mode800Available = true; + if ( (dm.Width == 1024) && (dm.Height == 768) ) + theApp.mode1024Available = true; + if ( (dm.Width == 1280) && (dm.Height == 1024) ) + theApp.mode1280Available = true; + } + } + + + screenFormat = mode.Format; + + switch(mode.Format) { + case D3DFMT_R8G8B8: + systemColorDepth = 24; + systemRedShift = 19; + systemGreenShift = 11; + systemBlueShift = 3; + break; + case D3DFMT_X8R8G8B8: + systemColorDepth = 32; + systemRedShift = 19; + systemGreenShift = 11; + systemBlueShift = 3; + Init_2xSaI(32); + break; + case D3DFMT_R5G6B5: + systemColorDepth = 16; + systemRedShift = 11; + systemGreenShift = 6; + systemBlueShift = 0; + Init_2xSaI(565); + break; + case D3DFMT_X1R5G5B5: + systemColorDepth = 16; + systemRedShift = 10; + systemGreenShift = 5; + systemBlueShift = 0; + Init_2xSaI(555); + break; + default: + DXTRACE_ERR_MSGBOX( _T("Unsupport D3D format"), 0 ); + return false; + } + theApp.fsColorDepth = systemColorDepth; + utilUpdateSystemColorMaps(); + + +#ifdef MMX + if(!theApp.disableMMX) { + cpu_mmx = theApp.detectMMX(); + } else { + cpu_mmx = 0; + } +#endif + + + theApp.updateFilter(); + theApp.updateIFB(); + + + // create device setPresentationType(); - if( FAILED( hr = pDevice->Reset( &dpp ) ) ) { - //DXTRACE_ERR_MSGBOX( _T("pDevice->Reset failed"), hr ); - failed = true; - return false; - } - createFont(); - createSurface(); - failed = false; - return true; -} - - -IDisplay *newDirect3DDisplay() -{ - return new Direct3DDisplay(); -} + + HRESULT hret = pD3D->CreateDevice( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + pWnd->GetSafeHwnd(), + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &dpp, + &pDevice); + if( FAILED( hret ) ) { + DXTRACE_ERR_MSGBOX( _T("Error creating Direct3D device"), hret ); + return false; + } + + createFont(); + createSurface(); + calculateDestRect(); + + setOption( _T("d3dFilter"), theApp.d3dFilter ); + + if(failed) return false; + + return TRUE; +} + + +void Direct3DDisplay::renderMenu() +{ + checkFullScreen(); + if(theApp.m_pMainWnd) { + theApp.m_pMainWnd->DrawMenuBar(); + } +} + + +void Direct3DDisplay::clear() +{ + if( pDevice ) { + pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0x00,0x00,0x00), 0.0f, 0 ); + } +} + + +void Direct3DDisplay::render() +{ + if( failed ) return; + if(!pDevice) return; + if( FAILED( pDevice->TestCooperativeLevel() ) ) return; + + clear(); + + pDevice->BeginScene(); + + // copy pix to emulatedImage and apply pixel filter if selected + HRESULT hr; + D3DLOCKED_RECT lr; + if( FAILED( hr = emulatedImage->LockRect( &lr, NULL, D3DLOCK_DISCARD ) ) ) { + DXTRACE_ERR_MSGBOX( _T("Can not lock back buffer"), hr ); + return; + } else { + if( !theApp.filterFunction ) { + copyImage( pix, lr.pBits, theApp.sizeX, theApp.sizeY, lr.Pitch, systemColorDepth ); + } else { + u32 pitch = theApp.filterWidth * (systemColorDepth>>3) + 4; + theApp.filterFunction( pix + pitch, + pitch, + (u8*)theApp.delta, + (u8*)lr.pBits, + lr.Pitch, + theApp.filterWidth, + theApp.filterHeight); + } + emulatedImage->UnlockRect(); + } + + // copy emulatedImage to pBackBuffer and scale with or without aspect ratio + LPDIRECT3DSURFACE9 pBackBuffer; + pDevice->GetBackBuffer( 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer ); + if( theApp.fullScreenStretch ) { + pDevice->StretchRect( emulatedImage, NULL, pBackBuffer, NULL, filter ); + } else { + pDevice->StretchRect( emulatedImage, NULL, pBackBuffer, &destRect, filter ); + } + pBackBuffer->Release(); + pBackBuffer = NULL; + + D3DCOLOR color; + RECT r; + r.left = 4; + r.right = dpp.BackBufferWidth - 4; + + if( theApp.screenMessage ) { + color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0xFF, 0x00, 0x00) : D3DCOLOR_ARGB(0xFF, 0xFF, 0x00, 0x00); + if( ( ( GetTickCount() - theApp.screenMessageTime ) < 3000 ) && !theApp.disableStatusMessage && pFont ) { + r.top = dpp.BackBufferHeight - 20; + r.bottom = dpp.BackBufferHeight - 4; + pFont->DrawText( NULL, theApp.screenMessageBuffer, -1, &r, 0, color ); + } else { + theApp.screenMessage = false; + } + } + + if( theApp.showSpeed && ( theApp.videoOption > VIDEO_4X ) ) { + color = theApp.showSpeedTransparent ? D3DCOLOR_ARGB(0x7F, 0x00, 0x00, 0xFF) : D3DCOLOR_ARGB(0xFF, 0x00, 0x00, 0xFF); + char buffer[30]; + if( theApp.showSpeed == 1 ) { + sprintf( buffer, "%3d%%", systemSpeed ); + } else { + sprintf( buffer, "%3d%%(%d, %d fps)", systemSpeed, systemFrameSkip, theApp.showRenderedFrames ); + } + + r.top = 4; + r.bottom = 20; + pFont->DrawText( NULL, buffer, -1, &r, 0, color ); + } + + pDevice->EndScene(); + + pDevice->Present( NULL, NULL, NULL, NULL ); + + return; +} + + +bool Direct3DDisplay::changeRenderSize( int w, int h ) +{ + if( (w != width) || (h != height) ) { + width = w; height = h; + if( pDevice ) { + destroySurface(); + createSurface(); + calculateDestRect(); + } + } + return true; +} + + +void Direct3DDisplay::resize( int w, int h ) +{ + if( (w != dpp.BackBufferWidth) || (h != dpp.BackBufferHeight) ) { + dpp.BackBufferWidth = (UINT)w; + dpp.BackBufferHeight = (UINT)h; + resetDevice(); + calculateDestRect(); + } + if(theApp.videoOption > VIDEO_4X) + resetDevice(); + +} + + +int Direct3DDisplay::selectFullScreenMode( GUID **pGUID ) +{ + return winVideoModeSelect(theApp.m_pMainWnd, pGUID); +} + + +void Direct3DDisplay::createFont() +{ + if( !pFont ) { + HRESULT hr = D3DXCreateFont( + pDevice, + 14, + 0, + FW_BOLD, + 1, + FALSE, + DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, + DEFAULT_QUALITY, + DEFAULT_PITCH || FF_DONTCARE, + _T("Arial"), + &pFont ); + if( FAILED( hr ) ) { + DXTRACE_ERR_MSGBOX( _T("createFont failed"), hr ); + } + } +} + + +void Direct3DDisplay::destroyFont() +{ + if( pFont ) { + pFont->Release(); + pFont = NULL; + } +} + + +void Direct3DDisplay::createSurface() +{ + if( !emulatedImage ) { + HRESULT hr = pDevice->CreateOffscreenPlainSurface( + width, height, + dpp.BackBufferFormat, + D3DPOOL_DEFAULT, + &emulatedImage, + NULL ); + if( FAILED( hr ) ) { + DXTRACE_ERR_MSGBOX( _T("createSurface failed"), hr ); + } + } +} + + +void Direct3DDisplay::destroySurface() +{ + if( emulatedImage ) { + emulatedImage->Release(); + emulatedImage = NULL; + } +} + + +void Direct3DDisplay::calculateDestRect() +{ + float scaleX = (float)dpp.BackBufferWidth / (float)width; + float scaleY = (float)dpp.BackBufferHeight / (float)height; + float min = (scaleX < scaleY) ? scaleX : scaleY; + if( theApp.fsMaxScale && (min > theApp.fsMaxScale) ) { + min = (float)theApp.fsMaxScale; + } + destRect.left = 0; + destRect.top = 0; + destRect.right = (LONG)(width * min); + destRect.bottom = (LONG)(height * min); + if( destRect.right != dpp.BackBufferWidth ) { + LONG diff = (dpp.BackBufferWidth - destRect.right) / 2; + destRect.left += diff; + destRect.right += diff; + } + if( destRect.bottom != dpp.BackBufferHeight ) { + LONG diff = (dpp.BackBufferHeight - destRect.bottom) / 2; + destRect.top += diff; + destRect.bottom += diff; + } +} + + +void Direct3DDisplay::setOption( const char *option, int value ) +{ + if( !_tcscmp( option, _T("vsync") ) ) { + theApp.vsync = true; + resetDevice(); + } + + if( !_tcscmp( option, _T("tripleBuffering") ) ) { + theApp.tripleBuffering = true; + resetDevice(); + } + + if( !_tcscmp( option, _T("d3dFilter") ) ) { + switch( value ) + { + case 0: //point + filter = D3DTEXF_POINT; + break; + case 1: //linear + filter = D3DTEXF_LINEAR; + break; + } + } + + if( !_tcscmp( option, _T("maxScale") ) ) { + calculateDestRect(); + } +} + + +bool Direct3DDisplay::resetDevice() +{ + if( !pDevice ) return false; + + HRESULT hr; + destroyFont(); + destroySurface(); + setPresentationType(); + if (!theApp.menuToggle) + pDevice->SetDialogBoxMode( FALSE ); + + if( FAILED( hr = pDevice->Reset( &dpp ) ) ) { + //DXTRACE_ERR_MSGBOX( _T("pDevice->Reset failed"), hr ); + failed = true; + return false; + } + if (theApp.menuToggle) + pDevice->SetDialogBoxMode( TRUE ); + + createFont(); + createSurface(); + failed = false; + return true; +} + + +IDisplay *newDirect3DDisplay() +{ + return new Direct3DDisplay(); +} diff --git a/src/win32/DirectInput.cpp b/src/win32/DirectInput.cpp index 074559c2..109918de 100644 --- a/src/win32/DirectInput.cpp +++ b/src/win32/DirectInput.cpp @@ -1,598 +1,598 @@ - -/* VisualBoyAdvance S - GB & GBA emulator - Copyright (C) 2006 Spacy - - Original VBA Credits: - Copyright (C) 1999-2003 Forgotten - Copyright (C) 2004-2006 VBA development team - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - -#include "stdafx.h" -#include "VBA.h" -#include "Input.h" -#include "Reg.h" -#include "WinResUtil.h" - -#define DIRECTINPUT_VERSION 0x0800 -#include -#pragma comment(lib, "Dinput8") - - -#ifdef _DEBUG -#define new DEBUG_NEW -#undef THIS_FILE -static char THIS_FILE[] = __FILE__; -#endif - -extern void directXMessage(const char *); -extern void winlog(const char *msg,...); - -#define POV_UP 1 -#define POV_DOWN 2 -#define POV_RIGHT 4 -#define POV_LEFT 8 - -class DirectInput : public Input { -public: - virtual void checkDevices(); - DirectInput(); - virtual ~DirectInput(); - - virtual bool initialize(); - virtual bool readDevices(); - virtual u32 readDevice(int which); - virtual CString getKeyName(LONG_PTR key); - virtual void checkKeys(); - virtual void checkMotionKeys(); - virtual void activate(); - virtual void loadSettings(); - virtual void saveSettings(); -}; - -struct deviceInfo { - LPDIRECTINPUTDEVICE8 device; - BOOL isPolled; - int nButtons; - int nAxes; - int nPovs; - BOOL first; - struct { - DWORD offset; - LONG center; - LONG negative; - LONG positive; - } axis[8]; - int needed; - union { - UCHAR data[256]; - DIJOYSTATE state; - }; -}; - -static deviceInfo *currentDevice = NULL; -static int numDevices = 1; -static deviceInfo *pDevices = NULL; -static LPDIRECTINPUT8 pDirectInput = NULL; -static int axisNumber = 0; - - - - -LONG_PTR defvalues[JOYPADS * KEYS_PER_PAD + MOTION_KEYS] = - { - DIK_LEFT, DIK_RIGHT, - DIK_UP, DIK_DOWN, - DIK_Z, DIK_X, - DIK_RETURN,DIK_BACK, - DIK_A, DIK_S, - DIK_SPACE, DIK_F12, - DIK_C, - 0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0, - DIK_NUMPAD4, DIK_NUMPAD6, DIK_NUMPAD8, DIK_NUMPAD2 -}; - - -void winReadKey(const char *name, KeyList& Keys) -{ - CString TxtKeyList = regQueryStringValue(name, ""); - int curPos= 0; - - CString resToken=TxtKeyList.Tokenize(",",curPos); - while (resToken != "") - { - Keys.AddTail(atoi(resToken)); - resToken= TxtKeyList.Tokenize(",",curPos); - }; -} - -void winReadKey(const char *name, int num, KeyList& Keys) -{ - char buffer[80]; - - sprintf(buffer, "Joy%d_%s", num, name); - winReadKey(buffer, Keys); -} - - -void winReadKeys() -{ - - for(int i = 0; i < JOYPADS; i++) { - winReadKey("Left", i, theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]); - winReadKey("Right", i, theApp.input->joypaddata[JOYPAD(i, KEY_RIGHT)]); - winReadKey("Up", i, theApp.input->joypaddata[JOYPAD(i,KEY_UP)]); - winReadKey("Down", i, theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]); - winReadKey("A", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]); - winReadKey("B", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]); - winReadKey("L", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]); - winReadKey("R", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]); - winReadKey("Start", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]); - winReadKey("Select", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]); - winReadKey("Speed", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]); - winReadKey("Capture", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]); - winReadKey("GS", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]); - } - winReadKey("Motion_Left", theApp.input->joypaddata[MOTION(KEY_LEFT)]); - winReadKey("Motion_Right", theApp.input->joypaddata[MOTION(KEY_RIGHT)]); - winReadKey("Motion_Up", theApp.input->joypaddata[MOTION(KEY_UP)]); - winReadKey("Motion_Down", theApp.input->joypaddata[MOTION(KEY_DOWN)]); -} - -void winSaveKey(char *name, KeyList& value) -{ - CString txtKeys; - - POSITION p = value.GetHeadPosition(); - while(p!=NULL) - { - CString tmp; - tmp.Format("%d", value.GetNext(p)); - txtKeys+=tmp; - if (p!=NULL) - txtKeys+=","; - } - regSetStringValue(name, txtKeys); -} - -static void winSaveKey(char *name, int num, KeyList& value) -{ - char buffer[80]; - - sprintf(buffer, "Joy%d_%s", num, name); - winSaveKey(buffer, value); -} - -void winSaveKeys() -{ - for(int i = 0; i < JOYPADS; i++) { - winSaveKey("Left", i, theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]); - winSaveKey("Right", i, theApp.input->joypaddata[JOYPAD(i,KEY_RIGHT)]); - winSaveKey("Up", i, theApp.input->joypaddata[JOYPAD(i,KEY_UP)]); - winSaveKey("Speed", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]); - winSaveKey("Capture", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]); - winSaveKey("GS", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]); - winSaveKey("Down", i, theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]); - winSaveKey("A", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]); - winSaveKey("B", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]); - winSaveKey("L", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]); - winSaveKey("R", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]); - winSaveKey("Start", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]); - winSaveKey("Select", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]); - } - regSetDwordValue("joyVersion", 1); - - winSaveKey("Motion_Left", - theApp.input->joypaddata[MOTION(KEY_LEFT)]); - winSaveKey("Motion_Right", - theApp.input->joypaddata[MOTION(KEY_RIGHT)]); - winSaveKey("Motion_Up", - theApp.input->joypaddata[MOTION(KEY_UP)]); - winSaveKey("Motion_Down", - theApp.input->joypaddata[MOTION(KEY_DOWN)]); -} - -static BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) -{ - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYOFFSET; - diprg.diph.dwObj = pdidoi->dwOfs; // Specify the enumerated axis - - diprg.lMin = -32768; - diprg.lMax = 32767; - // try to set the range - if (FAILED(currentDevice->device->SetProperty(DIPROP_RANGE, &diprg.diph))) { - // Get the range for the axis - if ( FAILED(currentDevice->device-> - GetProperty( DIPROP_RANGE, &diprg.diph ) ) ) { - return DIENUM_STOP; - } - } - - DIPROPDWORD didz; - - didz.diph.dwSize = sizeof(didz); - didz.diph.dwHeaderSize = sizeof(DIPROPHEADER); - didz.diph.dwHow = DIPH_BYOFFSET; - didz.diph.dwObj = pdidoi->dwOfs; - - didz.dwData = 5000; - - currentDevice->device->SetProperty(DIPROP_DEADZONE, &didz.diph); - - LONG center = (diprg.lMin + diprg.lMax)/2; - LONG threshold = (diprg.lMax - center)/2; - - // only 8 axis supported - if (axisNumber < 8) { - currentDevice->axis[axisNumber].center = center; - currentDevice->axis[axisNumber].negative = center - threshold; - currentDevice->axis[axisNumber].positive = center + threshold; - currentDevice->axis[axisNumber].offset = pdidoi->dwOfs; - } - axisNumber++; - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK EnumPovsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) -{ - return DIENUM_CONTINUE; -} - -static BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE pInst, - LPVOID lpvContext) -{ - ZeroMemory(&pDevices[numDevices],sizeof(deviceInfo)); - - HRESULT hRet = pDirectInput->CreateDevice(pInst->guidInstance, - &pDevices[numDevices].device, - NULL); - - if (hRet != DI_OK) - return DIENUM_STOP; - - DIDEVCAPS caps; - caps.dwSize=sizeof(DIDEVCAPS); - - hRet = pDevices[numDevices].device->GetCapabilities(&caps); - - if (hRet == DI_OK) { - if (caps.dwFlags & DIDC_POLLEDDATAFORMAT || - caps.dwFlags & DIDC_POLLEDDEVICE) - pDevices[numDevices].isPolled = TRUE; - - pDevices[numDevices].nButtons = caps.dwButtons; - pDevices[numDevices].nAxes = caps.dwAxes; - pDevices[numDevices].nPovs = caps.dwPOVs; - - for (int i = 0; i < 6; i++) { - pDevices[numDevices].axis[i].center = 0x8000; - pDevices[numDevices].axis[i].negative = 0x4000; - pDevices[numDevices].axis[i].positive = 0xc000; - } - } - - - numDevices++; - - - return DIENUM_CONTINUE; -} - -BOOL CALLBACK DIEnumDevicesCallback2(LPCDIDEVICEINSTANCE pInst, - LPVOID lpvContext) -{ - numDevices++; - - return DIENUM_CONTINUE; -} - -static int getPovState(DWORD value) -{ - int state = 0; - if (LOWORD(value) != 0xFFFF) { - if (value < 9000 || value > 27000) - state |= POV_UP; - if (value > 0 && value < 18000) - state |= POV_RIGHT; - if (value > 9000 && value < 27000) - state |= POV_DOWN; - if (value > 18000) - state |= POV_LEFT; - } - return state; -} - -static void checkKeys() -{ - LONG_PTR dev = 0; - int i; - - for(i = 0; i < (sizeof(theApp.input->joypaddata) / sizeof(theApp.input->joypaddata[0])); i++) - { - if (theApp.input->joypaddata[i].IsEmpty() && defvalues[i]) - theApp.input->joypaddata[i].AddTail(defvalues[i]); - POSITION p = theApp.input->joypaddata[i].GetHeadPosition(); - while(p!=NULL) - { - LONG_PTR k = theApp.input->joypaddata[i].GetNext(p); - if (k > 0 && DEVICEOF(k) < numDevices) - pDevices[DEVICEOF(k)].needed = true; - } - } -} - -#define KEYDOWN(buffer,key) (buffer[key] & 0x80) - -static bool readKeyboard() -{ - if (pDevices[0].needed) { - HRESULT hret = pDevices[0].device-> - GetDeviceState(256, - (LPVOID)pDevices[0].data); - - if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) { - hret = pDevices[0].device->Acquire(); - if (hret != DI_OK) - return false; - hret = pDevices[0].device->GetDeviceState(256,(LPVOID)pDevices[0].data); - } - - return hret == DI_OK; - } - return true; -} - -static bool readJoystick(int joy) -{ - if (pDevices[joy].needed) { - if (pDevices[joy].isPolled) - ((LPDIRECTINPUTDEVICE2)pDevices[joy].device)->Poll(); - - HRESULT hret = pDevices[joy].device-> - GetDeviceState(sizeof(DIJOYSTATE), - (LPVOID)&pDevices[joy].state); - - if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) { - hret = pDevices[joy].device->Acquire(); - - if (hret == DI_OK) { - - if (pDevices[joy].isPolled) - ((LPDIRECTINPUTDEVICE2)pDevices[joy].device)->Poll(); - - hret = pDevices[joy].device-> - GetDeviceState(sizeof(DIJOYSTATE), - (LPVOID)&pDevices[joy].state); - } - } - - return hret == DI_OK; - } - - return true; -} - -static void checkKeyboard() -{ - // mham fix. Patch #1378104 - UCHAR keystate[256]; - HRESULT hret = pDevices[0].device->Acquire(); - - if (pDevices[0].first) { - pDevices[0].device->GetDeviceState(256, (LPVOID)pDevices[0].data); - pDevices[0].first = FALSE; - return; - } - - hret = pDevices[0].device-> - GetDeviceState(256, (LPVOID)keystate); - - if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) { - return; - } - - if (hret == DI_OK) { - for (int i = 0; i < 256; i++) { - if (keystate[i] == pDevices[0].data[i]) continue; - if (KEYDOWN(keystate, i)) { - SendMessage(GetFocus(), JOYCONFIG_MESSAGE,0,i); - break; - } - } - } - memcpy(pDevices[0].data, keystate, sizeof(UCHAR) * 256); -} - -static void checkJoypads() -{ - DIDEVICEOBJECTINSTANCE di; - - ZeroMemory(&di,sizeof(DIDEVICEOBJECTINSTANCE)); - - di.dwSize = sizeof(DIDEVICEOBJECTINSTANCE); - - int i =0; - - DIJOYSTATE joystick; - - for (i = 1; i < numDevices; i++) { - HRESULT hret = pDevices[i].device->Acquire(); - - - if (pDevices[i].isPolled) - ((LPDIRECTINPUTDEVICE2)pDevices[i].device)->Poll(); - - hret = pDevices[i].device->GetDeviceState(sizeof(joystick), &joystick); - - int j; - - if (pDevices[i].first) { - memcpy(&pDevices[i].state, &joystick, sizeof(joystick)); - pDevices[i].first = FALSE; - continue; - } - - for (j = 0; j < pDevices[i].nButtons; j++) { - if (((pDevices[i].state.rgbButtons[j] ^ joystick.rgbButtons[j]) - & joystick.rgbButtons[j]) & 0x80) { - HWND focus = GetFocus(); - - SendMessage(focus, JOYCONFIG_MESSAGE, i,j+128); - } - } - - for (j = 0; j < pDevices[i].nAxes && j < 8; j++) { - LONG value = pDevices[i].axis[j].center; - LONG old = 0; - switch (pDevices[i].axis[j].offset) { - case DIJOFS_X: - value = joystick.lX; - old = pDevices[i].state.lX; - break; - case DIJOFS_Y: - value = joystick.lY; - old = pDevices[i].state.lY; - break; - case DIJOFS_Z: - value = joystick.lZ; - old = pDevices[i].state.lZ; - break; - case DIJOFS_RX: - value = joystick.lRx; - old = pDevices[i].state.lRx; - break; - case DIJOFS_RY: - value = joystick.lRy; - old = pDevices[i].state.lRy; - break; - case DIJOFS_RZ: - value = joystick.lRz; - old = pDevices[i].state.lRz; - break; - case DIJOFS_SLIDER(0): - value = joystick.rglSlider[0]; - old = pDevices[i].state.rglSlider[0]; - break; - case DIJOFS_SLIDER(1): - value = joystick.rglSlider[1]; - old = pDevices[i].state.rglSlider[1]; - break; - } - if (value != old) { - if (value < pDevices[i].axis[j].negative) - SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<1)); - else if (value > pDevices[i].axis[j].positive) - SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<1)+1); - } - } - - for (j = 0;j < 4 && j < pDevices[i].nPovs; j++) { - if (LOWORD(pDevices[i].state.rgdwPOV[j]) != LOWORD(joystick.rgdwPOV[j])) { - int state = getPovState(joystick.rgdwPOV[j]); - - if (state & POV_UP) - SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x20); - else if (state & POV_DOWN) - SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x21); - else if (state & POV_RIGHT) - SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x22); - else if (state & POV_LEFT) - SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x23); - } - } - - memcpy(&pDevices[i].state, &joystick, sizeof(joystick)); - } -} - -BOOL checkKey(LONG_PTR key) -{ - LONG_PTR dev = (key >> 8); - - LONG_PTR k = (key & 255); - - if (dev == 0) { - return KEYDOWN(pDevices[0].data,k); - } else { - if (k < 16) { - LONG_PTR axis = k >> 1; - LONG value = pDevices[dev].axis[axis].center; - switch (pDevices[dev].axis[axis].offset) { - case DIJOFS_X: - value = pDevices[dev].state.lX; - break; - case DIJOFS_Y: - value = pDevices[dev].state.lY; - break; - case DIJOFS_Z: - value = pDevices[dev].state.lZ; - break; - case DIJOFS_RX: - value = pDevices[dev].state.lRx; - break; - case DIJOFS_RY: - value = pDevices[dev].state.lRy; - break; - case DIJOFS_RZ: - value = pDevices[dev].state.lRz; - break; - case DIJOFS_SLIDER(0): - value = pDevices[dev].state.rglSlider[0]; - break; - case DIJOFS_SLIDER(1): - value = pDevices[dev].state.rglSlider[1]; - break; - } - - if (k & 1) - return value > pDevices[dev].axis[axis].positive; - return value < pDevices[dev].axis[axis].negative; - } else if (k < 48) { - LONG_PTR hat = (k >> 2) & 3; - int state = getPovState(pDevices[dev].state.rgdwPOV[hat]); - BOOL res = FALSE; - switch (k & 3) { - case 0: - res = state & POV_UP; - break; - case 1: - res = state & POV_DOWN; - break; - case 2: - res = state & POV_RIGHT; - break; - case 3: - res = state & POV_LEFT; - break; - } - return res; - } else if (k >= 128) { - return pDevices[dev].state.rgbButtons[k-128] & 0x80; - } - } - - return FALSE; -} + +/* VisualBoyAdvance S - GB & GBA emulator + Copyright (C) 2006 Spacy + + Original VBA Credits: + Copyright (C) 1999-2003 Forgotten + Copyright (C) 2004-2006 VBA development team + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "stdafx.h" +#include "VBA.h" +#include "Input.h" +#include "Reg.h" +#include "WinResUtil.h" + +#define DIRECTINPUT_VERSION 0x0800 +#include +#pragma comment(lib, "Dinput8") + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +extern void directXMessage(const char *); +extern void winlog(const char *msg,...); + +#define POV_UP 1 +#define POV_DOWN 2 +#define POV_RIGHT 4 +#define POV_LEFT 8 + +class DirectInput : public Input { +public: + virtual void checkDevices(); + DirectInput(); + virtual ~DirectInput(); + + virtual bool initialize(); + virtual bool readDevices(); + virtual u32 readDevice(int which); + virtual CString getKeyName(LONG_PTR key); + virtual void checkKeys(); + virtual void checkMotionKeys(); + virtual void activate(); + virtual void loadSettings(); + virtual void saveSettings(); +}; + +struct deviceInfo { + LPDIRECTINPUTDEVICE8 device; + BOOL isPolled; + int nButtons; + int nAxes; + int nPovs; + BOOL first; + struct { + DWORD offset; + LONG center; + LONG negative; + LONG positive; + } axis[8]; + int needed; + union { + UCHAR data[256]; + DIJOYSTATE state; + }; +}; + +static deviceInfo *currentDevice = NULL; +static int numDevices = 1; +static deviceInfo *pDevices = NULL; +static LPDIRECTINPUT8 pDirectInput = NULL; +static int axisNumber = 0; + + + + +LONG_PTR defvalues[JOYPADS * KEYS_PER_PAD + MOTION_KEYS] = + { + DIK_LEFT, DIK_RIGHT, + DIK_UP, DIK_DOWN, + DIK_Z, DIK_X, + DIK_RETURN,DIK_BACK, + DIK_A, DIK_S, + DIK_SPACE, DIK_F12, + DIK_C, + 0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0, + DIK_NUMPAD4, DIK_NUMPAD6, DIK_NUMPAD8, DIK_NUMPAD2 +}; + + +void winReadKey(const char *name, KeyList& Keys) +{ + CString TxtKeyList = regQueryStringValue(name, ""); + int curPos= 0; + + CString resToken=TxtKeyList.Tokenize(",",curPos); + while (resToken != "") + { + Keys.AddTail(atoi(resToken)); + resToken= TxtKeyList.Tokenize(",",curPos); + }; +} + +void winReadKey(const char *name, int num, KeyList& Keys) +{ + char buffer[80]; + + sprintf(buffer, "Joy%d_%s", num, name); + winReadKey(buffer, Keys); +} + + +void winReadKeys() +{ + + for(int i = 0; i < JOYPADS; i++) { + winReadKey("Left", i, theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]); + winReadKey("Right", i, theApp.input->joypaddata[JOYPAD(i, KEY_RIGHT)]); + winReadKey("Up", i, theApp.input->joypaddata[JOYPAD(i,KEY_UP)]); + winReadKey("Down", i, theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]); + winReadKey("A", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]); + winReadKey("B", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]); + winReadKey("L", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]); + winReadKey("R", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]); + winReadKey("Start", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]); + winReadKey("Select", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]); + winReadKey("Speed", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]); + winReadKey("Capture", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]); + winReadKey("GS", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]); + } + winReadKey("Motion_Left", theApp.input->joypaddata[MOTION(KEY_LEFT)]); + winReadKey("Motion_Right", theApp.input->joypaddata[MOTION(KEY_RIGHT)]); + winReadKey("Motion_Up", theApp.input->joypaddata[MOTION(KEY_UP)]); + winReadKey("Motion_Down", theApp.input->joypaddata[MOTION(KEY_DOWN)]); +} + +void winSaveKey(char *name, KeyList& value) +{ + CString txtKeys; + + POSITION p = value.GetHeadPosition(); + while(p!=NULL) + { + CString tmp; + tmp.Format("%d", value.GetNext(p)); + txtKeys+=tmp; + if (p!=NULL) + txtKeys+=","; + } + regSetStringValue(name, txtKeys); +} + +static void winSaveKey(char *name, int num, KeyList& value) +{ + char buffer[80]; + + sprintf(buffer, "Joy%d_%s", num, name); + winSaveKey(buffer, value); +} + +void winSaveKeys() +{ + for(int i = 0; i < JOYPADS; i++) { + winSaveKey("Left", i, theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)]); + winSaveKey("Right", i, theApp.input->joypaddata[JOYPAD(i,KEY_RIGHT)]); + winSaveKey("Up", i, theApp.input->joypaddata[JOYPAD(i,KEY_UP)]); + winSaveKey("Speed", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]); + winSaveKey("Capture", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)]); + winSaveKey("GS", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)]); + winSaveKey("Down", i, theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)]); + winSaveKey("A", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)]); + winSaveKey("B", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)]); + winSaveKey("L", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)]); + winSaveKey("R", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)]); + winSaveKey("Start", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)]); + winSaveKey("Select", i, theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)]); + } + regSetDwordValue("joyVersion", 1); + + winSaveKey("Motion_Left", + theApp.input->joypaddata[MOTION(KEY_LEFT)]); + winSaveKey("Motion_Right", + theApp.input->joypaddata[MOTION(KEY_RIGHT)]); + winSaveKey("Motion_Up", + theApp.input->joypaddata[MOTION(KEY_UP)]); + winSaveKey("Motion_Down", + theApp.input->joypaddata[MOTION(KEY_DOWN)]); +} + +static BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, + VOID* pContext ) +{ + DIPROPRANGE diprg; + diprg.diph.dwSize = sizeof(DIPROPRANGE); + diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); + diprg.diph.dwHow = DIPH_BYOFFSET; + diprg.diph.dwObj = pdidoi->dwOfs; // Specify the enumerated axis + + diprg.lMin = -32768; + diprg.lMax = 32767; + // try to set the range + if (FAILED(currentDevice->device->SetProperty(DIPROP_RANGE, &diprg.diph))) { + // Get the range for the axis + if ( FAILED(currentDevice->device-> + GetProperty( DIPROP_RANGE, &diprg.diph ) ) ) { + return DIENUM_STOP; + } + } + + DIPROPDWORD didz; + + didz.diph.dwSize = sizeof(didz); + didz.diph.dwHeaderSize = sizeof(DIPROPHEADER); + didz.diph.dwHow = DIPH_BYOFFSET; + didz.diph.dwObj = pdidoi->dwOfs; + + didz.dwData = 5000; + + currentDevice->device->SetProperty(DIPROP_DEADZONE, &didz.diph); + + LONG center = (diprg.lMin + diprg.lMax)/2; + LONG threshold = (diprg.lMax - center)/2; + + // only 8 axis supported + if (axisNumber < 8) { + currentDevice->axis[axisNumber].center = center; + currentDevice->axis[axisNumber].negative = center - threshold; + currentDevice->axis[axisNumber].positive = center + threshold; + currentDevice->axis[axisNumber].offset = pdidoi->dwOfs; + } + axisNumber++; + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK EnumPovsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, + VOID* pContext ) +{ + return DIENUM_CONTINUE; +} + +static BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE pInst, + LPVOID lpvContext) +{ + ZeroMemory(&pDevices[numDevices],sizeof(deviceInfo)); + + HRESULT hRet = pDirectInput->CreateDevice(pInst->guidInstance, + &pDevices[numDevices].device, + NULL); + + if (hRet != DI_OK) + return DIENUM_STOP; + + DIDEVCAPS caps; + caps.dwSize=sizeof(DIDEVCAPS); + + hRet = pDevices[numDevices].device->GetCapabilities(&caps); + + if (hRet == DI_OK) { + if (caps.dwFlags & DIDC_POLLEDDATAFORMAT || + caps.dwFlags & DIDC_POLLEDDEVICE) + pDevices[numDevices].isPolled = TRUE; + + pDevices[numDevices].nButtons = caps.dwButtons; + pDevices[numDevices].nAxes = caps.dwAxes; + pDevices[numDevices].nPovs = caps.dwPOVs; + + for (int i = 0; i < 6; i++) { + pDevices[numDevices].axis[i].center = 0x8000; + pDevices[numDevices].axis[i].negative = 0x4000; + pDevices[numDevices].axis[i].positive = 0xc000; + } + } + + + numDevices++; + + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK DIEnumDevicesCallback2(LPCDIDEVICEINSTANCE pInst, + LPVOID lpvContext) +{ + numDevices++; + + return DIENUM_CONTINUE; +} + +static int getPovState(DWORD value) +{ + int state = 0; + if (LOWORD(value) != 0xFFFF) { + if (value < 9000 || value > 27000) + state |= POV_UP; + if (value > 0 && value < 18000) + state |= POV_RIGHT; + if (value > 9000 && value < 27000) + state |= POV_DOWN; + if (value > 18000) + state |= POV_LEFT; + } + return state; +} + +static void checkKeys() +{ + LONG_PTR dev = 0; + int i; + + for(i = 0; i < (sizeof(theApp.input->joypaddata) / sizeof(theApp.input->joypaddata[0])); i++) + { + if (theApp.input->joypaddata[i].IsEmpty() && defvalues[i]) + theApp.input->joypaddata[i].AddTail(defvalues[i]); + POSITION p = theApp.input->joypaddata[i].GetHeadPosition(); + while(p!=NULL) + { + LONG_PTR k = theApp.input->joypaddata[i].GetNext(p); + if (k > 0 && DEVICEOF(k) < numDevices) + pDevices[DEVICEOF(k)].needed = true; + } + } +} + +#define KEYDOWN(buffer,key) (buffer[key] & 0x80) + +static bool readKeyboard() +{ + if (pDevices[0].needed) { + HRESULT hret = pDevices[0].device-> + GetDeviceState(256, + (LPVOID)pDevices[0].data); + + if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) { + hret = pDevices[0].device->Acquire(); + if (hret != DI_OK) + return false; + hret = pDevices[0].device->GetDeviceState(256,(LPVOID)pDevices[0].data); + } + + return hret == DI_OK; + } + return true; +} + +static bool readJoystick(int joy) +{ + if (pDevices[joy].needed) { + if (pDevices[joy].isPolled) + ((LPDIRECTINPUTDEVICE2)pDevices[joy].device)->Poll(); + + HRESULT hret = pDevices[joy].device-> + GetDeviceState(sizeof(DIJOYSTATE), + (LPVOID)&pDevices[joy].state); + + if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) { + hret = pDevices[joy].device->Acquire(); + + if (hret == DI_OK) { + + if (pDevices[joy].isPolled) + ((LPDIRECTINPUTDEVICE2)pDevices[joy].device)->Poll(); + + hret = pDevices[joy].device-> + GetDeviceState(sizeof(DIJOYSTATE), + (LPVOID)&pDevices[joy].state); + } + } + + return hret == DI_OK; + } + + return true; +} + +static void checkKeyboard() +{ + // mham fix. Patch #1378104 + UCHAR keystate[256]; + HRESULT hret = pDevices[0].device->Acquire(); + + if (pDevices[0].first) { + pDevices[0].device->GetDeviceState(256, (LPVOID)pDevices[0].data); + pDevices[0].first = FALSE; + return; + } + + hret = pDevices[0].device-> + GetDeviceState(256, (LPVOID)keystate); + + if (hret == DIERR_INPUTLOST || hret == DIERR_NOTACQUIRED) { + return; + } + + if (hret == DI_OK) { + for (int i = 0; i < 256; i++) { + if (keystate[i] == pDevices[0].data[i]) continue; + if (KEYDOWN(keystate, i)) { + SendMessage(GetFocus(), JOYCONFIG_MESSAGE,0,i); + break; + } + } + } + memcpy(pDevices[0].data, keystate, sizeof(UCHAR) * 256); +} + +static void checkJoypads() +{ + DIDEVICEOBJECTINSTANCE di; + + ZeroMemory(&di,sizeof(DIDEVICEOBJECTINSTANCE)); + + di.dwSize = sizeof(DIDEVICEOBJECTINSTANCE); + + int i =0; + + DIJOYSTATE joystick; + + for (i = 1; i < numDevices; i++) { + HRESULT hret = pDevices[i].device->Acquire(); + + + if (pDevices[i].isPolled) + ((LPDIRECTINPUTDEVICE2)pDevices[i].device)->Poll(); + + hret = pDevices[i].device->GetDeviceState(sizeof(joystick), &joystick); + + int j; + + if (pDevices[i].first) { + memcpy(&pDevices[i].state, &joystick, sizeof(joystick)); + pDevices[i].first = FALSE; + continue; + } + + for (j = 0; j < pDevices[i].nButtons; j++) { + if (((pDevices[i].state.rgbButtons[j] ^ joystick.rgbButtons[j]) + & joystick.rgbButtons[j]) & 0x80) { + HWND focus = GetFocus(); + + SendMessage(focus, JOYCONFIG_MESSAGE, i,j+128); + } + } + + for (j = 0; j < pDevices[i].nAxes && j < 8; j++) { + LONG value = pDevices[i].axis[j].center; + LONG old = 0; + switch (pDevices[i].axis[j].offset) { + case DIJOFS_X: + value = joystick.lX; + old = pDevices[i].state.lX; + break; + case DIJOFS_Y: + value = joystick.lY; + old = pDevices[i].state.lY; + break; + case DIJOFS_Z: + value = joystick.lZ; + old = pDevices[i].state.lZ; + break; + case DIJOFS_RX: + value = joystick.lRx; + old = pDevices[i].state.lRx; + break; + case DIJOFS_RY: + value = joystick.lRy; + old = pDevices[i].state.lRy; + break; + case DIJOFS_RZ: + value = joystick.lRz; + old = pDevices[i].state.lRz; + break; + case DIJOFS_SLIDER(0): + value = joystick.rglSlider[0]; + old = pDevices[i].state.rglSlider[0]; + break; + case DIJOFS_SLIDER(1): + value = joystick.rglSlider[1]; + old = pDevices[i].state.rglSlider[1]; + break; + } + if (value != old) { + if (value < pDevices[i].axis[j].negative) + SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<1)); + else if (value > pDevices[i].axis[j].positive) + SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<1)+1); + } + } + + for (j = 0;j < 4 && j < pDevices[i].nPovs; j++) { + if (LOWORD(pDevices[i].state.rgdwPOV[j]) != LOWORD(joystick.rgdwPOV[j])) { + int state = getPovState(joystick.rgdwPOV[j]); + + if (state & POV_UP) + SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x20); + else if (state & POV_DOWN) + SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x21); + else if (state & POV_RIGHT) + SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x22); + else if (state & POV_LEFT) + SendMessage(GetFocus(), JOYCONFIG_MESSAGE, i, (j<<2)+0x23); + } + } + + memcpy(&pDevices[i].state, &joystick, sizeof(joystick)); + } +} + +BOOL checkKey(LONG_PTR key) +{ + LONG_PTR dev = (key >> 8); + + LONG_PTR k = (key & 255); + + if (dev == 0) { + return KEYDOWN(pDevices[0].data,k); + } else { + if (k < 16) { + LONG_PTR axis = k >> 1; + LONG value = pDevices[dev].axis[axis].center; + switch (pDevices[dev].axis[axis].offset) { + case DIJOFS_X: + value = pDevices[dev].state.lX; + break; + case DIJOFS_Y: + value = pDevices[dev].state.lY; + break; + case DIJOFS_Z: + value = pDevices[dev].state.lZ; + break; + case DIJOFS_RX: + value = pDevices[dev].state.lRx; + break; + case DIJOFS_RY: + value = pDevices[dev].state.lRy; + break; + case DIJOFS_RZ: + value = pDevices[dev].state.lRz; + break; + case DIJOFS_SLIDER(0): + value = pDevices[dev].state.rglSlider[0]; + break; + case DIJOFS_SLIDER(1): + value = pDevices[dev].state.rglSlider[1]; + break; + } + + if (k & 1) + return value > pDevices[dev].axis[axis].positive; + return value < pDevices[dev].axis[axis].negative; + } else if (k < 48) { + LONG_PTR hat = (k >> 2) & 3; + int state = getPovState(pDevices[dev].state.rgdwPOV[hat]); + BOOL res = FALSE; + switch (k & 3) { + case 0: + res = state & POV_UP; + break; + case 1: + res = state & POV_DOWN; + break; + case 2: + res = state & POV_RIGHT; + break; + case 3: + res = state & POV_LEFT; + break; + } + return res; + } else if (k >= 128) { + return pDevices[dev].state.rgbButtons[k-128] & 0x80; + } + } + + return FALSE; +} BOOL checkKey(KeyList &k) { @@ -603,337 +603,337 @@ BOOL checkKey(KeyList &k) return TRUE; } return FALSE; -} - -DirectInput::DirectInput() -{} - -DirectInput::~DirectInput() -{ - saveSettings(); - if (pDirectInput != NULL) { - if (pDevices) { - for (int i = 0; i < numDevices ; i++) { - if (pDevices[i].device) { - pDevices[i].device->Unacquire(); - pDevices[i].device->Release(); - pDevices[i].device = NULL; - } - } - free(pDevices); - pDevices = NULL; - } - - pDirectInput->Release(); - pDirectInput = NULL; - } -} - - -bool DirectInput::initialize() -{ - - HRESULT hr; - - hr = DirectInput8Create( - AfxGetInstanceHandle(), - DIRECTINPUT_VERSION, - IID_IDirectInput8, - (LPVOID*)&pDirectInput, - NULL ); - - if ( hr != DI_OK ) { - return false; - } - - - - - hr = pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, - DIEnumDevicesCallback2, - NULL, - DIEDFL_ATTACHEDONLY); - - - - pDevices = (deviceInfo *)calloc(numDevices, sizeof(deviceInfo)); - - hr = pDirectInput->CreateDevice(GUID_SysKeyboard,&pDevices[0].device,NULL); - pDevices[0].isPolled = false; - pDevices[0].needed = true; - pDevices[0].first = true; - - if (hr != DI_OK) { - return false; - } - - - numDevices = 1; - - hr = pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, - DIEnumDevicesCallback, - NULL, - DIEDFL_ATTACHEDONLY); - - - if (hr != DI_OK) { - return false; - } - - hr = pDevices[0].device->SetDataFormat(&c_dfDIKeyboard); - - if (hr != DI_OK) { - return false; - } - - int i; - for (i = 1; i < numDevices; i++) { - pDevices[i].device->SetDataFormat(&c_dfDIJoystick); - pDevices[i].needed = false; - pDevices[i].first = true; - currentDevice = &pDevices[i]; - axisNumber = 0; - currentDevice->device->EnumObjects(EnumAxesCallback, NULL, DIDFT_AXIS); - currentDevice->device->EnumObjects(EnumPovsCallback, NULL, DIDFT_POV); - - - currentDevice = NULL; - } - - for (i = 0; i < numDevices; i++) - pDevices[i].device->Acquire(); - - return true; -} - -bool DirectInput::readDevices() -{ - bool ok = true; - for (int i = 0; i < numDevices; i++) { - if (pDevices[i].needed) { - if (i) { - ok = readJoystick(i); - } else - ok = readKeyboard(); - } - } - return ok; -} - -u32 DirectInput::readDevice(int which) -{ - u32 res = 0; - int i = theApp.joypadDefault; - if(which >= 0 && which <= 3) - i = which; - - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)])) - res |= 1; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)])) - res |= 2; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)])) - res |= 4; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)])) - res |= 8; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_RIGHT)])) - res |= 16; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)])) - res |= 32; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_UP)])) - res |= 64; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)])) - res |= 128; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)])) - res |= 256; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)])) - res |= 512; - - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)])) - res |= 4096; - - if(theApp.autoFire) { - res &= (~theApp.autoFire); - if(theApp.autoFireToggle) - res |= theApp.autoFire; - theApp.autoFireToggle = !theApp.autoFireToggle; - } - - // disallow L+R or U+D of being pressed at the same time - if((res & 48) == 48) - res &= ~16; - if((res & 192) == 192) - res &= ~128; - - if(theApp.movieRecording) { - if(i == theApp.joypadDefault) { - if(res != theApp.movieLastJoypad) { - fwrite(&theApp.movieFrame, 1, sizeof(theApp.movieFrame), theApp.movieFile); - fwrite(&res, 1, sizeof(res), theApp.movieFile); - theApp.movieLastJoypad = res; - } - } - } - if(theApp.moviePlaying) { - if(theApp.movieFrame == theApp.moviePlayFrame) { - theApp.movieLastJoypad = theApp.movieNextJoypad; - theApp.movieReadNext(); - } - res = theApp.movieLastJoypad; - } - // we don't record speed up or screen capture buttons - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]) || theApp.speedupToggle) - res |= 1024; - if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)])) - res |= 2048; - - return res; -} - -CString DirectInput::getKeyName(LONG_PTR key) -{ - LONG_PTR d = (key >> 8); - LONG_PTR k = key & 255; - - DIDEVICEOBJECTINSTANCE di; - - ZeroMemory(&di,sizeof(DIDEVICEOBJECTINSTANCE)); - - di.dwSize = sizeof(DIDEVICEOBJECTINSTANCE); - - CString winBuffer = winResLoadString(IDS_ERROR); - - if (d == 0) { - pDevices[0].device->GetObjectInfo( &di, (DWORD)key, DIPH_BYOFFSET ); - winBuffer = di.tszName; - } else { - if (k < 16) { - if (k < 4) { - switch (k) { - case 0: - winBuffer.Format(winResLoadString(IDS_JOY_LEFT), d); - break; - case 1: - winBuffer.Format(winResLoadString(IDS_JOY_RIGHT), d); - break; - case 2: - winBuffer.Format(winResLoadString(IDS_JOY_UP), d); - break; - case 3: - winBuffer.Format(winResLoadString(IDS_JOY_DOWN), d); - break; - } - } else { - pDevices[d].device->GetObjectInfo(&di, - pDevices[d].axis[k>>1].offset, - DIPH_BYOFFSET); - if (k & 1) - winBuffer.Format("Joy %d %s +", d, di.tszName); - else - winBuffer.Format("Joy %d %s -", d, di.tszName); - } - } else if (k < 48) { - LONG_PTR hat = (k >> 2) & 3; - pDevices[d].device->GetObjectInfo(&di, - (DWORD)DIJOFS_POV(hat), - DIPH_BYOFFSET); - char *dir = "up"; - LONG_PTR dd = k & 3; - if (dd == 1) - dir = "down"; - else if (dd == 2) - dir = "right"; - else if (dd == 3) - dir = "left"; - winBuffer.Format("Joy %d %s %s", d, di.tszName, dir); - } else { - pDevices[d].device->GetObjectInfo(&di, - (DWORD)DIJOFS_BUTTON(k-128), - DIPH_BYOFFSET); - winBuffer.Format(winResLoadString(IDS_JOY_BUTTON),d,di.tszName); - } - } - - return winBuffer; -} - -void DirectInput::checkKeys() -{ - ::checkKeys(); -} - -void DirectInput::checkMotionKeys() -{ - if(checkKey(theApp.input->joypaddata[MOTION(KEY_LEFT)])) { - theApp.sensorX += 3; - if(theApp.sensorX > 2197) - theApp.sensorX = 2197; - if(theApp.sensorX < 2047) - theApp.sensorX = 2057; - } else if(checkKey(theApp.input->joypaddata[MOTION(KEY_RIGHT)])) { - theApp.sensorX -= 3; - if(theApp.sensorX < 1897) - theApp.sensorX = 1897; - if(theApp.sensorX > 2047) - theApp.sensorX = 2037; - } else if(theApp.sensorX > 2047) { - theApp.sensorX -= 2; - if(theApp.sensorX < 2047) - theApp.sensorX = 2047; - } else { - theApp.sensorX += 2; - if(theApp.sensorX > 2047) - theApp.sensorX = 2047; - } - - if(checkKey(theApp.input->joypaddata[MOTION(KEY_UP)])) { - theApp.sensorY += 3; - if(theApp.sensorY > 2197) - theApp.sensorY = 2197; - if(theApp.sensorY < 2047) - theApp.sensorY = 2057; - } else if(checkKey(theApp.input->joypaddata[MOTION(KEY_DOWN)])) { - theApp.sensorY -= 3; - if(theApp.sensorY < 1897) - theApp.sensorY = 1897; - if(theApp.sensorY > 2047) - theApp.sensorY = 2037; - } else if(theApp.sensorY > 2047) { - theApp.sensorY -= 2; - if(theApp.sensorY < 2047) - theApp.sensorY = 2047; - } else { - theApp.sensorY += 2; - if(theApp.sensorY > 2047) - theApp.sensorY = 2047; - } -} - -Input *newDirectInput() -{ - return new DirectInput; -} - - -void DirectInput::checkDevices() -{ - checkJoypads(); - checkKeyboard(); -} - -void DirectInput::activate() -{ - for (int i = 0; i < numDevices; i++) { - if (pDevices != NULL && pDevices[i].device != NULL) - pDevices[i].device->Acquire(); - } -} - -void DirectInput::loadSettings() -{ - winReadKeys(); -} - -void DirectInput::saveSettings() -{ - winSaveKeys(); -} +} + +DirectInput::DirectInput() +{} + +DirectInput::~DirectInput() +{ + saveSettings(); + if (pDirectInput != NULL) { + if (pDevices) { + for (int i = 0; i < numDevices ; i++) { + if (pDevices[i].device) { + pDevices[i].device->Unacquire(); + pDevices[i].device->Release(); + pDevices[i].device = NULL; + } + } + free(pDevices); + pDevices = NULL; + } + + pDirectInput->Release(); + pDirectInput = NULL; + } +} + + +bool DirectInput::initialize() +{ + + HRESULT hr; + + hr = DirectInput8Create( + AfxGetInstanceHandle(), + DIRECTINPUT_VERSION, + IID_IDirectInput8, + (LPVOID*)&pDirectInput, + NULL ); + + if ( hr != DI_OK ) { + return false; + } + + + + + hr = pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, + DIEnumDevicesCallback2, + NULL, + DIEDFL_ATTACHEDONLY); + + + + pDevices = (deviceInfo *)calloc(numDevices, sizeof(deviceInfo)); + + hr = pDirectInput->CreateDevice(GUID_SysKeyboard,&pDevices[0].device,NULL); + pDevices[0].isPolled = false; + pDevices[0].needed = true; + pDevices[0].first = true; + + if (hr != DI_OK) { + return false; + } + + + numDevices = 1; + + hr = pDirectInput->EnumDevices(DI8DEVCLASS_GAMECTRL, + DIEnumDevicesCallback, + NULL, + DIEDFL_ATTACHEDONLY); + + + if (hr != DI_OK) { + return false; + } + + hr = pDevices[0].device->SetDataFormat(&c_dfDIKeyboard); + + if (hr != DI_OK) { + return false; + } + + int i; + for (i = 1; i < numDevices; i++) { + pDevices[i].device->SetDataFormat(&c_dfDIJoystick); + pDevices[i].needed = false; + pDevices[i].first = true; + currentDevice = &pDevices[i]; + axisNumber = 0; + currentDevice->device->EnumObjects(EnumAxesCallback, NULL, DIDFT_AXIS); + currentDevice->device->EnumObjects(EnumPovsCallback, NULL, DIDFT_POV); + + + currentDevice = NULL; + } + + for (i = 0; i < numDevices; i++) + pDevices[i].device->Acquire(); + + return true; +} + +bool DirectInput::readDevices() +{ + bool ok = true; + for (int i = 0; i < numDevices; i++) { + if (pDevices[i].needed) { + if (i) { + ok = readJoystick(i); + } else + ok = readKeyboard(); + } + } + return ok; +} + +u32 DirectInput::readDevice(int which) +{ + u32 res = 0; + int i = theApp.joypadDefault; + if(which >= 0 && which <= 3) + i = which; + + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_A)])) + res |= 1; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_B)])) + res |= 2; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SELECT)])) + res |= 4; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_START)])) + res |= 8; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_RIGHT)])) + res |= 16; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_LEFT)])) + res |= 32; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_UP)])) + res |= 64; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_DOWN)])) + res |= 128; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_R)])) + res |= 256; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_L)])) + res |= 512; + + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_GS)])) + res |= 4096; + + if(theApp.autoFire) { + res &= (~theApp.autoFire); + if(theApp.autoFireToggle) + res |= theApp.autoFire; + theApp.autoFireToggle = !theApp.autoFireToggle; + } + + // disallow L+R or U+D of being pressed at the same time + if((res & 48) == 48) + res &= ~16; + if((res & 192) == 192) + res &= ~128; + + if(theApp.movieRecording) { + if(i == theApp.joypadDefault) { + if(res != theApp.movieLastJoypad) { + fwrite(&theApp.movieFrame, 1, sizeof(theApp.movieFrame), theApp.movieFile); + fwrite(&res, 1, sizeof(res), theApp.movieFile); + theApp.movieLastJoypad = res; + } + } + } + if(theApp.moviePlaying) { + if(theApp.movieFrame == theApp.moviePlayFrame) { + theApp.movieLastJoypad = theApp.movieNextJoypad; + theApp.movieReadNext(); + } + res = theApp.movieLastJoypad; + } + // we don't record speed up or screen capture buttons + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_SPEED)]) || theApp.speedupToggle) + res |= 1024; + if(checkKey(theApp.input->joypaddata[JOYPAD(i,KEY_BUTTON_CAPTURE)])) + res |= 2048; + + return res; +} + +CString DirectInput::getKeyName(LONG_PTR key) +{ + LONG_PTR d = (key >> 8); + LONG_PTR k = key & 255; + + DIDEVICEOBJECTINSTANCE di; + + ZeroMemory(&di,sizeof(DIDEVICEOBJECTINSTANCE)); + + di.dwSize = sizeof(DIDEVICEOBJECTINSTANCE); + + CString winBuffer = winResLoadString(IDS_ERROR); + + if (d == 0) { + pDevices[0].device->GetObjectInfo( &di, (DWORD)key, DIPH_BYOFFSET ); + winBuffer = di.tszName; + } else { + if (k < 16) { + if (k < 4) { + switch (k) { + case 0: + winBuffer.Format(winResLoadString(IDS_JOY_LEFT), d); + break; + case 1: + winBuffer.Format(winResLoadString(IDS_JOY_RIGHT), d); + break; + case 2: + winBuffer.Format(winResLoadString(IDS_JOY_UP), d); + break; + case 3: + winBuffer.Format(winResLoadString(IDS_JOY_DOWN), d); + break; + } + } else { + pDevices[d].device->GetObjectInfo(&di, + pDevices[d].axis[k>>1].offset, + DIPH_BYOFFSET); + if (k & 1) + winBuffer.Format("Joy %d %s +", d, di.tszName); + else + winBuffer.Format("Joy %d %s -", d, di.tszName); + } + } else if (k < 48) { + LONG_PTR hat = (k >> 2) & 3; + pDevices[d].device->GetObjectInfo(&di, + (DWORD)DIJOFS_POV(hat), + DIPH_BYOFFSET); + char *dir = "up"; + LONG_PTR dd = k & 3; + if (dd == 1) + dir = "down"; + else if (dd == 2) + dir = "right"; + else if (dd == 3) + dir = "left"; + winBuffer.Format("Joy %d %s %s", d, di.tszName, dir); + } else { + pDevices[d].device->GetObjectInfo(&di, + (DWORD)DIJOFS_BUTTON(k-128), + DIPH_BYOFFSET); + winBuffer.Format(winResLoadString(IDS_JOY_BUTTON),d,di.tszName); + } + } + + return winBuffer; +} + +void DirectInput::checkKeys() +{ + ::checkKeys(); +} + +void DirectInput::checkMotionKeys() +{ + if(checkKey(theApp.input->joypaddata[MOTION(KEY_LEFT)])) { + theApp.sensorX += 3; + if(theApp.sensorX > 2197) + theApp.sensorX = 2197; + if(theApp.sensorX < 2047) + theApp.sensorX = 2057; + } else if(checkKey(theApp.input->joypaddata[MOTION(KEY_RIGHT)])) { + theApp.sensorX -= 3; + if(theApp.sensorX < 1897) + theApp.sensorX = 1897; + if(theApp.sensorX > 2047) + theApp.sensorX = 2037; + } else if(theApp.sensorX > 2047) { + theApp.sensorX -= 2; + if(theApp.sensorX < 2047) + theApp.sensorX = 2047; + } else { + theApp.sensorX += 2; + if(theApp.sensorX > 2047) + theApp.sensorX = 2047; + } + + if(checkKey(theApp.input->joypaddata[MOTION(KEY_UP)])) { + theApp.sensorY += 3; + if(theApp.sensorY > 2197) + theApp.sensorY = 2197; + if(theApp.sensorY < 2047) + theApp.sensorY = 2057; + } else if(checkKey(theApp.input->joypaddata[MOTION(KEY_DOWN)])) { + theApp.sensorY -= 3; + if(theApp.sensorY < 1897) + theApp.sensorY = 1897; + if(theApp.sensorY > 2047) + theApp.sensorY = 2037; + } else if(theApp.sensorY > 2047) { + theApp.sensorY -= 2; + if(theApp.sensorY < 2047) + theApp.sensorY = 2047; + } else { + theApp.sensorY += 2; + if(theApp.sensorY > 2047) + theApp.sensorY = 2047; + } +} + +Input *newDirectInput() +{ + return new DirectInput; +} + + +void DirectInput::checkDevices() +{ + checkJoypads(); + checkKeyboard(); +} + +void DirectInput::activate() +{ + for (int i = 0; i < numDevices; i++) { + if (pDevices != NULL && pDevices[i].device != NULL) + pDevices[i].device->Acquire(); + } +} + +void DirectInput::loadSettings() +{ + winReadKeys(); +} + +void DirectInput::saveSettings() +{ + winSaveKeys(); +}