1835 lines
51 KiB
C++
1835 lines
51 KiB
C++
/* FCE Ultra - NES/Famicom Emulator
|
|
*
|
|
* Copyright notice for this file:
|
|
* Copyright (C) 2002 Xodnizel
|
|
*
|
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
// For commctrl.h below
|
|
#define _WIN32_IE 0x0300
|
|
|
|
#include "common.h"
|
|
#include <dinput.h>
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
|
|
#include "input.h"
|
|
#include "keyboard.h"
|
|
#include "joystick.h"
|
|
#include "../../fceu.h" //mbg merge 7/17/06 added
|
|
|
|
#include "keyscan.h"
|
|
|
|
LPDIRECTINPUT7 lpDI=0;
|
|
|
|
/* UsrInputType[] is user-specified. InputType[] is current
|
|
(game loading can override user settings)
|
|
*/
|
|
|
|
int UsrInputType[3]={SI_GAMEPAD,SI_GAMEPAD,SIFC_NONE};
|
|
int InputType[3]={0,0,0};
|
|
int cspec=0;
|
|
|
|
int gametype=0;
|
|
|
|
int InitDInput(void)
|
|
{
|
|
HRESULT ddrval;
|
|
|
|
//mbg merge 7/17/06 changed:
|
|
//ddrval=DirectInputCreateEx(fceu_hInstance,DIRECTINPUT_VERSION,&IID_IDirectInput7,(LPVOID *)&lpDI,0);
|
|
ddrval=DirectInputCreateEx(fceu_hInstance,DIRECTINPUT_VERSION,IID_IDirectInput7,(LPVOID *)&lpDI,0);
|
|
if(ddrval!=DI_OK)
|
|
{
|
|
FCEUD_PrintError("DirectInput: Error creating DirectInput object.");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static uint32 MouseData[3];
|
|
static int screenmode=0;
|
|
void InputScreenChanged(int fs)
|
|
{
|
|
int x;
|
|
if(GI)
|
|
{
|
|
for(x=0;x<2;x++)
|
|
if(InputType[x]==SI_ZAPPER)
|
|
FCEUI_SetInput(x,SI_ZAPPER,MouseData,fs);
|
|
if(InputType[2]==SIFC_SHADOW)
|
|
FCEUI_SetInputFC(SIFC_SHADOW,MouseData,fs);
|
|
}
|
|
screenmode=fs;
|
|
}
|
|
|
|
/* Necessary for proper GUI functioning(configuring when a game isn't loaded). */
|
|
void InputUserActiveFix(void)
|
|
{
|
|
int x;
|
|
for(x=0;x<3;x++) InputType[x]=UsrInputType[x];
|
|
}
|
|
|
|
void ParseGIInput(FCEUGI *gi)
|
|
{
|
|
InputType[0]=UsrInputType[0];
|
|
InputType[1]=UsrInputType[1];
|
|
InputType[2]=UsrInputType[2];
|
|
|
|
if(gi)
|
|
{
|
|
if(gi->input[0]>=0)
|
|
InputType[0]=gi->input[0];
|
|
if(gi->input[1]>=0)
|
|
InputType[1]=gi->input[1];
|
|
if(gi->inputfc>=0)
|
|
InputType[2]=gi->inputfc;
|
|
cspec = gi->cspecial;
|
|
gametype=gi->type;
|
|
|
|
InitOtherInput();
|
|
}
|
|
else cspec=gametype=0;
|
|
}
|
|
|
|
|
|
static uint8 QuizKingData=0;
|
|
static uint8 HyperShotData=0;
|
|
static uint32 MahjongData=0;
|
|
static uint32 FTrainerData=0;
|
|
static uint8 TopRiderData=0;
|
|
|
|
static uint8 BWorldData[1+13+1];
|
|
|
|
static void UpdateFKB(void);
|
|
static void UpdateSuborKB(void);
|
|
void UpdateGamepad(void);
|
|
static void UpdateQuizKing(void);
|
|
static void UpdateHyperShot(void);
|
|
static void UpdateMahjong(void);
|
|
static void UpdateFTrainer(void);
|
|
static void UpdateTopRider(void);
|
|
|
|
static uint32 JSreturn=0;
|
|
int NoWaiting=0;
|
|
|
|
#include "keyscan.h"
|
|
static unsigned char *keys=0;
|
|
static unsigned char *keys_nr=0;
|
|
static int DIPS=0;
|
|
|
|
static uint8 keyonce[MKK_COUNT];
|
|
//#define KEY(__a) keys_nr[MKK(__a)]
|
|
|
|
static int _keyonly(int a)
|
|
{
|
|
if(keys_nr[a])
|
|
{
|
|
if(!keyonce[a])
|
|
{
|
|
keyonce[a]=1;
|
|
return(1);
|
|
}
|
|
}
|
|
else
|
|
keyonce[a]=0;
|
|
return(0);
|
|
}
|
|
|
|
int cidisabled=0;
|
|
|
|
#define MK(x) {{BUTTC_KEYBOARD},{0},{MKK(x)},1}
|
|
#define MC(x) {{BUTTC_KEYBOARD},{0},{x},1}
|
|
#define MK2(x1,x2) {{BUTTC_KEYBOARD},{0},{MKK(x1),MKK(x2)},2}
|
|
|
|
#define MKZ() {{0},{0},{0},0}
|
|
|
|
#define GPZ() {MKZ(), MKZ(), MKZ(), MKZ()}
|
|
|
|
ButtConfig GamePadConfig[4][10]={
|
|
/* Gamepad 1 */
|
|
{
|
|
MK(LEFTALT), MK(LEFTCONTROL), MK(TAB), MK(ENTER), MK(BL_CURSORUP),
|
|
MK(BL_CURSORDOWN),MK(BL_CURSORLEFT),MK(BL_CURSORRIGHT)
|
|
},
|
|
|
|
/* Gamepad 2 */
|
|
GPZ(),
|
|
|
|
/* Gamepad 3 */
|
|
GPZ(),
|
|
|
|
/* Gamepad 4 */
|
|
GPZ()
|
|
};
|
|
|
|
extern int rapidAlternator; // for auto-fire / autofire
|
|
int DesynchAutoFire=0; // A and B not at same time
|
|
uint32 JSAutoHeld=0, JSAutoHeldAffected=0; // for auto-hold
|
|
uint8 autoHoldOn=0, autoHoldReset=0, autoHoldRefire=0; // for auto-hold
|
|
|
|
void SetAutoFireDesynch(int DesynchOn)
|
|
{
|
|
if(DesynchOn)
|
|
{
|
|
DesynchAutoFire = 1;
|
|
}
|
|
else
|
|
{
|
|
DesynchAutoFire = 0;
|
|
}
|
|
}
|
|
|
|
int GetAutoFireDesynch()
|
|
{
|
|
return DesynchAutoFire;
|
|
}
|
|
|
|
int DTestButton(ButtConfig *bc)
|
|
{
|
|
uint32 x;//mbg merge 7/17/06 changed to uint
|
|
|
|
for(x=0;x<bc->NumC;x++)
|
|
{
|
|
if(bc->ButtType[x]==BUTTC_KEYBOARD)
|
|
{
|
|
if(keys_nr[bc->ButtonNum[x]])
|
|
{
|
|
return(1);
|
|
}
|
|
}
|
|
}
|
|
if(DTestButtonJoy(bc)) return(1);
|
|
return(0);
|
|
}
|
|
|
|
|
|
void UpdateGamepad()
|
|
{
|
|
if(FCEUI_IsMovieActive()<0)
|
|
return;
|
|
|
|
uint32 JS=0;
|
|
int x;
|
|
int wg;
|
|
if(FCEUI_IsMovieActive()>0)
|
|
AutoFire();
|
|
|
|
for(wg=0;wg<4;wg++)
|
|
{
|
|
for(x=0;x<8;x++)
|
|
if(DTestButton(&GamePadConfig[wg][x]))
|
|
JS|=(1<<x)<<(wg<<3);
|
|
|
|
// if(rapidAlternator)
|
|
for(x=0;x<2;x++)
|
|
if(DTestButton(&GamePadConfig[wg][8+x]))
|
|
JS|=((1<<x)<<(wg<<3))*(rapidAlternator^(x*DesynchAutoFire));
|
|
}
|
|
|
|
if(autoHoldOn)
|
|
{
|
|
if(autoHoldRefire)
|
|
{
|
|
autoHoldRefire--;
|
|
if(!autoHoldRefire)
|
|
JSAutoHeldAffected = 0;
|
|
}
|
|
|
|
for(wg=0;wg<4;wg++)
|
|
for(x=0;x<8;x++)
|
|
if(DTestButton(&GamePadConfig[wg][x]))
|
|
{
|
|
if(!autoHoldRefire || !(JSAutoHeldAffected&(1<<x)<<(wg<<3)))
|
|
{
|
|
JSAutoHeld^=(1<<x)<<(wg<<3);
|
|
JSAutoHeldAffected|=(1<<x)<<(wg<<3);
|
|
autoHoldRefire = 192;
|
|
}
|
|
}
|
|
|
|
char inputstr [32];
|
|
{
|
|
uint32 c = JSAutoHeld;
|
|
sprintf(inputstr, "%c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c",
|
|
(c&0x40)?'<':' ', (c&0x10)?'^':' ', (c&0x80)?'>':' ', (c&0x20)?'v':' ',
|
|
(c&0x01)?'A':' ', (c&0x02)?'B':' ', (c&0x08)?'S':' ', (c&0x04)?'s':' ',
|
|
(c&0x4000)?'<':' ', (c&0x1000)?'^':' ', (c&0x8000)?'>':' ', (c&0x2000)?'v':' ',
|
|
(c&0x0100)?'A':' ', (c&0x0200)?'B':' ', (c&0x0800)?'S':' ', (c&0x0400)?'s':' ');
|
|
if(!(c&0xff00))
|
|
inputstr[8] = '\0';
|
|
}
|
|
FCEU_DispMessage("Held: %s", inputstr);
|
|
}
|
|
else
|
|
{
|
|
JSAutoHeldAffected = 0;
|
|
autoHoldRefire = 0;
|
|
}
|
|
|
|
if(autoHoldReset)
|
|
{
|
|
FCEU_DispMessage("Held: ");
|
|
JSAutoHeld = 0;
|
|
JSAutoHeldAffected = 0;
|
|
autoHoldRefire = 0;
|
|
}
|
|
|
|
// apply auto-hold
|
|
if(JSAutoHeld)
|
|
JS ^= JSAutoHeld;
|
|
|
|
JSreturn=JS;
|
|
}
|
|
|
|
ButtConfig powerpadsc[2][12]={
|
|
{
|
|
MK(O),MK(P),MK(BRACKET_LEFT),
|
|
MK(BRACKET_RIGHT),
|
|
|
|
MK(K),MK(L),MK(SEMICOLON),
|
|
MK(APOSTROPHE),
|
|
MK(M),MK(COMMA),MK(PERIOD),MK(SLASH)
|
|
},
|
|
{
|
|
MK(O),MK(P),MK(BRACKET_LEFT),
|
|
MK(BRACKET_RIGHT),MK(K),MK(L),MK(SEMICOLON),
|
|
MK(APOSTROPHE),
|
|
MK(M),MK(COMMA),MK(PERIOD),MK(SLASH)
|
|
}
|
|
};
|
|
|
|
static uint32 powerpadbuf[2];
|
|
|
|
static uint32 UpdatePPadData(int w)
|
|
{
|
|
uint32 r=0;
|
|
ButtConfig *ppadtsc=powerpadsc[w];
|
|
int x;
|
|
|
|
for(x=0;x<12;x++)
|
|
if(DTestButton(&ppadtsc[x])) r|=1<<x;
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
static uint8 fkbkeys[0x48];
|
|
static uint8 suborkbkeys[0x60];
|
|
|
|
void KeyboardUpdateState(void); //mbg merge 7/17/06 yech had to add this
|
|
void GetMouseData(uint32 *md); //mbg merge 7/17/06 yech had to add this
|
|
|
|
void FCEUD_UpdateInput()
|
|
{
|
|
int x;
|
|
int t=0;
|
|
|
|
KeyboardUpdateState();
|
|
UpdateJoysticks();
|
|
|
|
//UpdatePhysicalInput();
|
|
//KeyboardCommands();
|
|
FCEUI_HandleEmuCommands(FCEUD_TestCommandState);
|
|
|
|
{
|
|
for(x=0;x<2;x++)
|
|
switch(InputType[x])
|
|
{
|
|
case SI_GAMEPAD:t|=1;break;
|
|
case SI_ARKANOID:t|=2;break;
|
|
case SI_ZAPPER:t|=2;break;
|
|
case SI_POWERPADA:
|
|
case SI_POWERPADB:powerpadbuf[x]=UpdatePPadData(x);break;
|
|
}
|
|
|
|
switch(InputType[2])
|
|
{
|
|
case SIFC_ARKANOID:t|=2;break;
|
|
case SIFC_SHADOW:t|=2;break;
|
|
case SIFC_FKB:if(cidisabled) UpdateFKB();break;
|
|
case SIFC_SUBORKB:if(cidisabled) UpdateSuborKB();break;
|
|
case SIFC_HYPERSHOT: UpdateHyperShot();break;
|
|
case SIFC_MAHJONG: UpdateMahjong();break;
|
|
case SIFC_QUIZKING: UpdateQuizKing();break;
|
|
case SIFC_FTRAINERB:
|
|
case SIFC_FTRAINERA: UpdateFTrainer();break;
|
|
case SIFC_TOPRIDER: UpdateTopRider();break;
|
|
case SIFC_OEKAKIDS:t|=2;break;
|
|
}
|
|
|
|
if(t&1)
|
|
UpdateGamepad();
|
|
|
|
if(t&2)
|
|
GetMouseData(MouseData);
|
|
}
|
|
}
|
|
|
|
void InitOtherInput(void)
|
|
{
|
|
void *InputDPtr;
|
|
|
|
int t;
|
|
int x;
|
|
int attrib;
|
|
|
|
for(t=0,x=0;x<2;x++)
|
|
{
|
|
attrib=0;
|
|
InputDPtr=0;
|
|
switch(InputType[x])
|
|
{
|
|
case SI_POWERPADA:
|
|
case SI_POWERPADB:InputDPtr=&powerpadbuf[x];break;
|
|
case SI_GAMEPAD:InputDPtr=&JSreturn;break;
|
|
case SI_ARKANOID:InputDPtr=MouseData;t|=1;break;
|
|
case SI_ZAPPER:InputDPtr=MouseData;
|
|
t|=1;
|
|
attrib=screenmode;
|
|
break;
|
|
}
|
|
FCEUI_SetInput(x,InputType[x],InputDPtr,attrib);
|
|
}
|
|
|
|
attrib=0;
|
|
InputDPtr=0;
|
|
switch(InputType[2])
|
|
{
|
|
case SIFC_SHADOW:InputDPtr=MouseData;t|=1;attrib=screenmode;break;
|
|
case SIFC_OEKAKIDS:InputDPtr=MouseData;t|=1;attrib=screenmode;break;
|
|
case SIFC_ARKANOID:InputDPtr=MouseData;t|=1;break;
|
|
case SIFC_FKB:InputDPtr=fkbkeys;break;
|
|
case SIFC_SUBORKB:InputDPtr=suborkbkeys;break;
|
|
case SIFC_HYPERSHOT:InputDPtr=&HyperShotData;break;
|
|
case SIFC_MAHJONG:InputDPtr=&MahjongData;break;
|
|
case SIFC_QUIZKING:InputDPtr=&QuizKingData;break;
|
|
case SIFC_TOPRIDER:InputDPtr=&TopRiderData;break;
|
|
case SIFC_BWORLD:InputDPtr=BWorldData;break;
|
|
case SIFC_FTRAINERA:
|
|
case SIFC_FTRAINERB:InputDPtr=&FTrainerData;break;
|
|
}
|
|
|
|
FCEUI_SetInputFC(InputType[2],InputDPtr,attrib);
|
|
FCEUI_DisableFourScore(eoptions&EO_NOFOURSCORE);
|
|
}
|
|
|
|
ButtConfig fkbmap[0x48]=
|
|
{
|
|
MK(F1),MK(F2),MK(F3),MK(F4),MK(F5),MK(F6),MK(F7),MK(F8),
|
|
MK(1),MK(2),MK(3),MK(4),MK(5),MK(6),MK(7),MK(8),MK(9),MK(0),
|
|
MK(MINUS),MK(EQUAL),MK(BACKSLASH),MK(BACKSPACE),
|
|
MK(ESCAPE),MK(Q),MK(W),MK(E),MK(R),MK(T),MK(Y),MK(U),MK(I),MK(O),
|
|
MK(P),MK(GRAVE),MK(BRACKET_LEFT),MK(ENTER),
|
|
MK(LEFTCONTROL),MK(A),MK(S),MK(D),MK(F),MK(G),MK(H),MK(J),MK(K),
|
|
MK(L),MK(SEMICOLON),MK(APOSTROPHE),MK(BRACKET_RIGHT),MK(INSERT),
|
|
MK(LEFTSHIFT),MK(Z),MK(X),MK(C),MK(V),MK(B),MK(N),MK(M),MK(COMMA),
|
|
MK(PERIOD),MK(SLASH),MK(RIGHTALT),MK(RIGHTSHIFT),MK(LEFTALT),MK(SPACE),
|
|
MK(BL_DELETE),
|
|
MK(BL_END),
|
|
MK(BL_PAGEDOWN),
|
|
MK(BL_CURSORUP),MK(BL_CURSORLEFT),MK(BL_CURSORRIGHT),MK(BL_CURSORDOWN)
|
|
};
|
|
|
|
ButtConfig suborkbmap[0x60]=
|
|
{
|
|
MC(0x01),MC(0x3b),MC(0x3c),MC(0x3d),MC(0x3e),MC(0x3f),MC(0x40),MC(0x41),MC(0x42),MC(0x43),
|
|
MC(0x44),MC(0x57),MC(0x58),MC(0x45),MC(0x29),MC(0x02),MC(0x03),MC(0x04),MC(0x05),MC(0x06),
|
|
MC(0x07),MC(0x08),MC(0x09),MC(0x0a),MC(0x0b),MC(0x0c),MC(0x0d),MC(0x0e),MC(0xd2),MC(0xc7),
|
|
MC(0xc9),MC(0xc5),MC(0xb5),MC(0x37),MC(0x4a),MC(0x0f),MC(0x10),MC(0x11),MC(0x12),MC(0x13),
|
|
MC(0x14),MC(0x15),MC(0x16),MC(0x17),MC(0x18),MC(0x19),MC(0x1a),MC(0x1b),MC(0x1c),MC(0xd3),
|
|
MC(0xca),MC(0xd1),MC(0x47),MC(0x48),MC(0x49),MC(0x4e),MC(0x3a),MC(0x1e),MC(0x1f),MC(0x20),
|
|
MC(0x21),MC(0x22),MC(0x23),MC(0x24),MC(0x25),MC(0x26),MC(0x27),MC(0x28),MC(0x4b),MC(0x4c),
|
|
MC(0x4d),MC(0x2a),MC(0x2c),MC(0x2d),MC(0x2e),MC(0x2f),MC(0x30),MC(0x31),MC(0x32),MC(0x33),
|
|
MC(0x34),MC(0x35),MC(0x2b),MC(0xc8),MC(0x4f),MC(0x50),MC(0x51),MC(0x1d),MC(0x38),MC(0x39),
|
|
MC(0xcb),MC(0xd0),MC(0xcd),MC(0x52),MC(0x53)
|
|
};
|
|
|
|
|
|
static void UpdateFKB(void)
|
|
{
|
|
int x;
|
|
|
|
for(x=0;x<0x48;x++)
|
|
{
|
|
fkbkeys[x]=0;
|
|
|
|
if(DTestButton(&fkbmap[x]))
|
|
fkbkeys[x]=1;
|
|
}
|
|
}
|
|
|
|
static void UpdateSuborKB(void)
|
|
{
|
|
int x;
|
|
|
|
for(x=0;x<0x60;x++)
|
|
{
|
|
suborkbkeys[x]=0;
|
|
|
|
if(DTestButton(&suborkbmap[x]))
|
|
suborkbkeys[x]=1;
|
|
}
|
|
}
|
|
|
|
static ButtConfig HyperShotButtons[4]=
|
|
{
|
|
MK(Q),MK(W),MK(E),MK(R)
|
|
};
|
|
|
|
static void UpdateHyperShot(void)
|
|
{
|
|
int x;
|
|
|
|
HyperShotData=0;
|
|
for(x=0;x<0x4;x++)
|
|
{
|
|
if(DTestButton(&HyperShotButtons[x]))
|
|
HyperShotData|=1<<x;
|
|
}
|
|
}
|
|
|
|
static ButtConfig MahjongButtons[21]=
|
|
{
|
|
MK(Q),MK(W),MK(E),MK(R),MK(T),
|
|
MK(A),MK(S),MK(D),MK(F),MK(G),MK(H),MK(J),MK(K),MK(L),
|
|
MK(Z),MK(X),MK(C),MK(V),MK(B),MK(N),MK(M)
|
|
};
|
|
|
|
static void UpdateMahjong(void)
|
|
{
|
|
int x;
|
|
|
|
MahjongData=0;
|
|
for(x=0;x<21;x++)
|
|
{
|
|
if(DTestButton(&MahjongButtons[x]))
|
|
MahjongData|=1<<x;
|
|
}
|
|
}
|
|
|
|
ButtConfig QuizKingButtons[6]=
|
|
{
|
|
MK(Q),MK(W),MK(E),MK(R),MK(T),MK(Y)
|
|
};
|
|
|
|
static void UpdateQuizKing(void)
|
|
{
|
|
int x;
|
|
|
|
QuizKingData=0;
|
|
|
|
for(x=0;x<6;x++)
|
|
{
|
|
if(DTestButton(&QuizKingButtons[x]))
|
|
QuizKingData|=1<<x;
|
|
}
|
|
|
|
}
|
|
|
|
ButtConfig TopRiderButtons[8]=
|
|
{
|
|
MK(Q),MK(W),MK(E),MK(R),MK(T),MK(Y),MK(U),MK(I)
|
|
};
|
|
|
|
static void UpdateTopRider(void)
|
|
{
|
|
int x;
|
|
TopRiderData=0;
|
|
for(x=0;x<8;x++)
|
|
if(DTestButton(&TopRiderButtons[x]))
|
|
TopRiderData|=1<<x;
|
|
}
|
|
|
|
ButtConfig FTrainerButtons[12]=
|
|
{
|
|
MK(O),MK(P),MK(BRACKET_LEFT),
|
|
MK(BRACKET_RIGHT),MK(K),MK(L),MK(SEMICOLON),
|
|
MK(APOSTROPHE),
|
|
MK(M),MK(COMMA),MK(PERIOD),MK(SLASH)
|
|
};
|
|
|
|
static void UpdateFTrainer(void)
|
|
{
|
|
int x;
|
|
|
|
FTrainerData=0;
|
|
|
|
for(x=0;x<12;x++)
|
|
{
|
|
if(DTestButton(&FTrainerButtons[x]))
|
|
FTrainerData|=1<<x;
|
|
}
|
|
}
|
|
|
|
int DWaitButton(HWND hParent, const uint8 *text, ButtConfig *bc);
|
|
int DWaitSimpleButton(HWND hParent, const uint8 *text);
|
|
|
|
CFGSTRUCT InputConfig[]={
|
|
ACA(UsrInputType),
|
|
AC(powerpadsc),
|
|
AC(QuizKingButtons),
|
|
AC(FTrainerButtons),
|
|
AC(HyperShotButtons),
|
|
AC(MahjongButtons),
|
|
AC(GamePadConfig),
|
|
AC(fkbmap),
|
|
AC(suborkbmap),
|
|
ENDCFGSTRUCT
|
|
};
|
|
|
|
void InitInputStuff(void)
|
|
{
|
|
int x,y;
|
|
|
|
KeyboardInitialize();
|
|
InitJoysticks(hAppWnd);
|
|
|
|
for(x=0; x<4; x++)
|
|
for(y=0; y<10; y++)
|
|
JoyClearBC(&GamePadConfig[x][y]);
|
|
|
|
for(x=0; x<2; x++)
|
|
for(y=0; y<12; y++)
|
|
JoyClearBC(&powerpadsc[x][y]);
|
|
|
|
for(x=0; x<0x48; x++)
|
|
JoyClearBC(&fkbmap[x]);
|
|
for(x=0; x<0x60; x++)
|
|
JoyClearBC(&suborkbmap[x]);
|
|
|
|
for(x=0; x<6; x++)
|
|
JoyClearBC(&QuizKingButtons[x]);
|
|
for(x=0; x<12; x++)
|
|
JoyClearBC(&FTrainerButtons[x]);
|
|
for(x=0; x<21; x++)
|
|
JoyClearBC(&MahjongButtons[x]);
|
|
for(x=0; x<4; x++)
|
|
JoyClearBC(&HyperShotButtons[x]);
|
|
}
|
|
|
|
|
|
|
|
static void FCExp(char *text)
|
|
{
|
|
static char *fccortab[12]={"none","arkanoid","shadow","4player","fkb","suborkb",
|
|
"hypershot","mahjong","quizking","ftrainera","ftrainerb","oekakids"};
|
|
|
|
static int fccortabi[12]={SIFC_NONE,SIFC_ARKANOID,SIFC_SHADOW,
|
|
SIFC_4PLAYER,SIFC_FKB,SIFC_SUBORKB,SIFC_HYPERSHOT,SIFC_MAHJONG,SIFC_QUIZKING,
|
|
SIFC_FTRAINERA,SIFC_FTRAINERB,SIFC_OEKAKIDS};
|
|
int y;
|
|
for(y=0;y<12;y++)
|
|
if(!strcmp(fccortab[y],text))
|
|
UsrInputType[2]=fccortabi[y];
|
|
}
|
|
|
|
static char *cortab[6]={"none","gamepad","zapper","powerpada","powerpadb","arkanoid"};
|
|
static int cortabi[6]={SI_NONE,SI_GAMEPAD,
|
|
SI_ZAPPER,SI_POWERPADA,SI_POWERPADB,SI_ARKANOID};
|
|
|
|
static void Input1(char *text)
|
|
{
|
|
int y;
|
|
|
|
for(y=0;y<6;y++)
|
|
if(!strcmp(cortab[y],text))
|
|
UsrInputType[0]=cortabi[y];
|
|
}
|
|
|
|
static void Input2(char *text)
|
|
{
|
|
int y;
|
|
|
|
for(y=0;y<6;y++)
|
|
if(!strcmp(cortab[y],text))
|
|
UsrInputType[1]=cortabi[y];
|
|
}
|
|
|
|
ARGPSTRUCT InputArgs[]={
|
|
{"-fcexp",0,(void *)FCExp,0x2000},
|
|
{"-input1",0,(void *)Input1,0x2000},
|
|
{"-input2",0,(void *)Input2,0x2000},
|
|
{0,0,0,0}
|
|
};
|
|
|
|
|
|
static char *MakeButtString(ButtConfig *bc)
|
|
{
|
|
uint32 x; //mbg merge 7/17/06 changed to uint
|
|
char tmpstr[512];
|
|
char *astr;
|
|
|
|
tmpstr[0] = 0;
|
|
|
|
for(x=0;x<bc->NumC;x++)
|
|
{
|
|
if(x) strcat(tmpstr, ", ");
|
|
|
|
if(bc->ButtType[x] == BUTTC_KEYBOARD)
|
|
{
|
|
strcat(tmpstr,"KB: ");
|
|
if(!GetKeyNameText(bc->ButtonNum[x]<<16,tmpstr+strlen(tmpstr),16))
|
|
{
|
|
switch(bc->ButtonNum[x])
|
|
{
|
|
case 200: strcpy(tmpstr+strlen(tmpstr),"Up Arrow"); break;
|
|
case 203: strcpy(tmpstr+strlen(tmpstr),"Left Arrow"); break;
|
|
case 205: strcpy(tmpstr+strlen(tmpstr),"Right Arrow"); break;
|
|
case 208: strcpy(tmpstr+strlen(tmpstr),"Down Arrow"); break;
|
|
default: sprintf(tmpstr+strlen(tmpstr),"%03d",bc->ButtonNum[x]); break;
|
|
}
|
|
}
|
|
}
|
|
else if(bc->ButtType[x] == BUTTC_JOYSTICK)
|
|
{
|
|
strcat(tmpstr,"JS ");
|
|
sprintf(tmpstr+strlen(tmpstr), "%d ", bc->DeviceNum[x]);
|
|
if(bc->ButtonNum[x] & 0x8000)
|
|
{
|
|
char *asel[3]={"x","y","z"};
|
|
sprintf(tmpstr+strlen(tmpstr), "axis %s%s", asel[bc->ButtonNum[x] & 3],(bc->ButtonNum[x]&0x4000)?"-":"+");
|
|
}
|
|
else if(bc->ButtonNum[x] & 0x2000)
|
|
{
|
|
sprintf(tmpstr+strlen(tmpstr), "hat %d:%d", (bc->ButtonNum[x] >> 4)&3,
|
|
bc->ButtonNum[x]&3);
|
|
}
|
|
else
|
|
{
|
|
sprintf(tmpstr+strlen(tmpstr), "button %d", bc->ButtonNum[x] & 127);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
astr=(char*)malloc(strlen(tmpstr) + 1); //mbg merge 7/17/06 added cast
|
|
strcpy(astr,tmpstr);
|
|
return(astr);
|
|
}
|
|
|
|
|
|
static int DWBStarted;
|
|
static ButtConfig *DWBButtons;
|
|
static const uint8 *DWBText;
|
|
|
|
static HWND die;
|
|
|
|
static BOOL CALLBACK DWBCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
|
|
switch(uMsg) {
|
|
case WM_DESTROY:
|
|
die = NULL;
|
|
return(0);
|
|
case WM_TIMER:
|
|
{
|
|
uint8 devicenum;
|
|
uint16 buttonnum;
|
|
GUID guid;
|
|
|
|
if(DoJoyWaitTest(&guid, &devicenum, &buttonnum))
|
|
{
|
|
ButtConfig *bc = DWBButtons;
|
|
char *nstr;
|
|
int wc;
|
|
if(DWBStarted)
|
|
{
|
|
ButtConfig *bc = DWBButtons;
|
|
bc->NumC = 0;
|
|
DWBStarted = 0;
|
|
}
|
|
wc = bc->NumC;
|
|
//FCEU_printf("%d: %d\n",devicenum,buttonnum);
|
|
bc->ButtType[wc]=BUTTC_JOYSTICK;
|
|
bc->DeviceNum[wc]=devicenum;
|
|
bc->ButtonNum[wc]=buttonnum;
|
|
bc->DeviceInstance[wc] = guid;
|
|
|
|
/* Stop config if the user pushes the same button twice in a row. */
|
|
if(wc && bc->ButtType[wc]==bc->ButtType[wc-1] && bc->DeviceNum[wc]==bc->DeviceNum[wc-1] &&
|
|
bc->ButtonNum[wc]==bc->ButtonNum[wc-1])
|
|
goto gornk;
|
|
|
|
bc->NumC++;
|
|
|
|
/* Stop config if we reached our maximum button limit. */
|
|
if(bc->NumC >= MAXBUTTCONFIG)
|
|
goto gornk;
|
|
nstr = MakeButtString(bc);
|
|
SetDlgItemText(hwndDlg, 100, nstr);
|
|
free(nstr);
|
|
}
|
|
}
|
|
break;
|
|
case WM_USER + 666:
|
|
//SetFocus(GetDlgItem(hwndDlg,100));
|
|
if(DWBStarted)
|
|
{
|
|
char *nstr;
|
|
ButtConfig *bc = DWBButtons;
|
|
bc->NumC = 0;
|
|
DWBStarted = 0;
|
|
nstr = MakeButtString(bc);
|
|
SetDlgItemText(hwndDlg, 100, nstr);
|
|
free(nstr);
|
|
}
|
|
|
|
{
|
|
ButtConfig *bc = DWBButtons;
|
|
int wc = bc->NumC;
|
|
char *nstr;
|
|
|
|
bc->ButtType[wc]=BUTTC_KEYBOARD;
|
|
bc->DeviceNum[wc]=0;
|
|
bc->ButtonNum[wc]=lParam&255;
|
|
|
|
/* Stop config if the user pushes the same button twice in a row. */
|
|
if(wc && bc->ButtType[wc]==bc->ButtType[wc-1] && bc->DeviceNum[wc]==bc->DeviceNum[wc-1] &&
|
|
bc->ButtonNum[wc]==bc->ButtonNum[wc-1])
|
|
goto gornk;
|
|
|
|
bc->NumC++;
|
|
/* Stop config if we reached our maximum button limit. */
|
|
if(bc->NumC >= MAXBUTTCONFIG)
|
|
goto gornk;
|
|
|
|
nstr = MakeButtString(bc);
|
|
SetDlgItemText(hwndDlg, 100, nstr);
|
|
free(nstr);
|
|
}
|
|
break;
|
|
case WM_INITDIALOG:
|
|
SetWindowText(hwndDlg, (char*)DWBText); //mbg merge 7/17/06 added cast
|
|
BeginJoyWait(hwndDlg);
|
|
SetTimer(hwndDlg,666,25,0); /* Every 25ms.*/
|
|
{
|
|
char *nstr = MakeButtString(DWBButtons);
|
|
SetDlgItemText(hwndDlg, 100, nstr);
|
|
free(nstr);
|
|
}
|
|
break;
|
|
case WM_CLOSE:
|
|
case WM_QUIT: goto gornk;
|
|
|
|
case WM_COMMAND:
|
|
switch(wParam&0xFFFF)
|
|
{
|
|
case 200:
|
|
{
|
|
ButtConfig *bc = DWBButtons;
|
|
char *nstr;
|
|
bc->NumC = 0;
|
|
nstr = MakeButtString(bc);
|
|
SetDlgItemText(hwndDlg, 100, nstr);
|
|
free(nstr);
|
|
}
|
|
break;
|
|
case 201:
|
|
gornk:
|
|
KillTimer(hwndDlg,666);
|
|
EndJoyWait(hAppWnd);
|
|
SetForegroundWindow(GetParent(hwndDlg));
|
|
DestroyWindow(hwndDlg);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int DWaitButton(HWND hParent, const uint8 *text, ButtConfig *bc)
|
|
{
|
|
DWBText=text;
|
|
DWBButtons = bc;
|
|
DWBStarted = 1;
|
|
|
|
die = CreateDialog(fceu_hInstance, "DWBDIALOG", hParent, DWBCallB);
|
|
|
|
EnableWindow(hParent, 0);
|
|
|
|
ShowWindow(die, 1);
|
|
|
|
while(die)
|
|
{
|
|
MSG msg;
|
|
while(PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if(GetMessage(&msg, 0, 0, 0) > 0)
|
|
{
|
|
if(msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
|
|
{
|
|
LPARAM tmpo;
|
|
|
|
tmpo=((msg.lParam>>16)&0x7F)|((msg.lParam>>17)&0x80);
|
|
PostMessage(die,WM_USER+666,0,tmpo);
|
|
continue;
|
|
}
|
|
if(msg.message == WM_SYSCOMMAND) continue;
|
|
if(!IsDialogMessage(die, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
Sleep(10);
|
|
}
|
|
|
|
EnableWindow(hParent, 1);
|
|
return 0; //mbg merge TODO 7/17/06 - had to add this return value--is it right?
|
|
}
|
|
|
|
int DWaitSimpleButton(HWND hParent, const uint8 *text)
|
|
{
|
|
DWBStarted = 1;
|
|
int ret = 0;
|
|
|
|
die = CreateDialog(fceu_hInstance, "DWBDIALOGSIMPLE", hParent, NULL);
|
|
SetWindowText(die, (char*)text); //mbg merge 7/17/06 added cast
|
|
EnableWindow(hParent, 0);
|
|
|
|
ShowWindow(die, 1);
|
|
|
|
while(die)
|
|
{
|
|
MSG msg;
|
|
while(PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if(GetMessage(&msg, 0, 0, 0) > 0)
|
|
{
|
|
if(msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
|
|
{
|
|
LPARAM tmpo;
|
|
|
|
tmpo=((msg.lParam>>16)&0x7F)|((msg.lParam>>17)&0x80);
|
|
ret = tmpo;
|
|
goto done;
|
|
}
|
|
if(msg.message == WM_SYSCOMMAND) continue;
|
|
if(!IsDialogMessage(die, &msg))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
Sleep(10);
|
|
}
|
|
done:
|
|
EndDialog(die,0);
|
|
EnableWindow(hParent, 1);
|
|
|
|
if(ret == 1) // convert Esc to nothing (why is it 1 and not VK_ESCAPE?)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
|
|
static ButtConfig *DoTBButtons=0;
|
|
static const char *DoTBTitle=0;
|
|
static int DoTBMax=0;
|
|
static int DoTBType=0,DoTBPort=0;
|
|
|
|
static BOOL CALLBACK DoTBCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg) {
|
|
case WM_INITDIALOG:
|
|
if(DoTBType == SI_GAMEPAD)
|
|
{
|
|
char buf[32];
|
|
sprintf(buf,"Virtual Gamepad %d",DoTBPort+1);
|
|
SetDlgItemText(hwndDlg, 100,buf);
|
|
|
|
sprintf(buf,"Virtual Gamepad %d",DoTBPort+3);
|
|
SetDlgItemText(hwndDlg, 101, buf);
|
|
|
|
CheckDlgButton(hwndDlg,400,(eoptions & EO_NOFOURSCORE)?BST_CHECKED:BST_UNCHECKED);
|
|
}
|
|
SetWindowText(hwndDlg, DoTBTitle);
|
|
break;
|
|
case WM_CLOSE:
|
|
case WM_QUIT: goto gornk;
|
|
|
|
case WM_COMMAND:
|
|
{
|
|
int b;
|
|
b=wParam&0xFFFF;
|
|
if(b>= 300 && b < (300 + DoTBMax))
|
|
{
|
|
char btext[128];
|
|
btext[0]=0;
|
|
GetDlgItemText(hwndDlg, b, btext, 128);
|
|
DWaitButton(hwndDlg, (uint8*)btext,&DoTBButtons[b - 300]); //mbg merge 7/17/06 added cast
|
|
}
|
|
else switch(wParam&0xFFFF)
|
|
{
|
|
case 1:
|
|
gornk:
|
|
|
|
if(DoTBType == SI_GAMEPAD)
|
|
{
|
|
eoptions &= ~EO_NOFOURSCORE;
|
|
if(IsDlgButtonChecked(hwndDlg,400)==BST_CHECKED)
|
|
eoptions|=EO_NOFOURSCORE;
|
|
}
|
|
EndDialog(hwndDlg,0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
static void DoTBConfig(HWND hParent, const char *text, char *_template, ButtConfig *buttons, int max)
|
|
{
|
|
DoTBTitle=text;
|
|
DoTBButtons = buttons;
|
|
DoTBMax = max;
|
|
DialogBox(fceu_hInstance,_template,hParent,DoTBCallB);
|
|
}
|
|
|
|
static BOOL CALLBACK InputConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static const char *strn[6]={"<none>","Gamepad","Zapper","Power Pad A","Power Pad B","Arkanoid Paddle"};
|
|
static const char *strf[14]=
|
|
{"<none>","Arkanoid Paddle","Hyper Shot gun","4-Player Adapter",
|
|
"Family Keyboard","Subor Keyboard","HyperShot Pads", "Mahjong", "Quiz King Buzzers",
|
|
"Family Trainer A","Family Trainer B", "Oeka Kids Tablet", "Barcode World",
|
|
"Top Rider"};
|
|
static const int haven[6]={0,1,0,1,1,0};
|
|
static const int havef[14]={0,0,0,0, 1,1,0,0, 1,1,1,0, 0,0};
|
|
int x;
|
|
|
|
switch(uMsg) {
|
|
case WM_INITDIALOG:
|
|
SetDlgItemText(hwndDlg,65488,"Select the device you want to be enabled on input ports 1 and 2, and the Famicom expansion port. You may configure the device listed above each drop-down list by pressing \"Configure\", if applicable. The device currently being emulated on the each port is listed above the drop down list; loading certain games will override your settings, but only temporarily. If you select a device to be on the emulated Famicom Expansion Port, you should probably have emulated gamepads on the emulated NES-style input ports.");
|
|
for(x=0;x<2;x++)
|
|
{
|
|
int y;
|
|
|
|
for(y=0;y<6;y++)
|
|
SendDlgItemMessage(hwndDlg,104+x,CB_ADDSTRING,0,(LPARAM)(LPSTR)strn[y]);
|
|
|
|
SendDlgItemMessage(hwndDlg,104+x,CB_SETCURSEL,UsrInputType[x],(LPARAM)(LPSTR)0);
|
|
EnableWindow(GetDlgItem(hwndDlg,106+x),haven[InputType[x]]);
|
|
SetDlgItemText(hwndDlg,200+x,(LPTSTR)strn[InputType[x]]);
|
|
}
|
|
|
|
|
|
{
|
|
int y;
|
|
for(y=0;y<13;y++)
|
|
SendDlgItemMessage(hwndDlg,110,CB_ADDSTRING,0,(LPARAM)(LPSTR)strf[y]);
|
|
SendDlgItemMessage(hwndDlg,110,CB_SETCURSEL,UsrInputType[2],(LPARAM)(LPSTR)0);
|
|
EnableWindow(GetDlgItem(hwndDlg,111),havef[InputType[2]]);
|
|
SetDlgItemText(hwndDlg,202,(LPTSTR)strf[InputType[2]]);
|
|
}
|
|
|
|
extern int autoHoldKey, autoHoldClearKey;
|
|
char btext[128];
|
|
if(autoHoldKey)
|
|
{
|
|
if(!GetKeyNameText(autoHoldKey<<16,btext,128))
|
|
sprintf(btext, "KB: %d", autoHoldKey);
|
|
}
|
|
else
|
|
sprintf(btext, "not assigned");
|
|
SetDlgItemText(hwndDlg, 115, btext);
|
|
|
|
if(autoHoldClearKey)
|
|
{
|
|
if(!GetKeyNameText(autoHoldClearKey<<16,btext,128))
|
|
sprintf(btext, "KB: %d", autoHoldClearKey);
|
|
}
|
|
else
|
|
sprintf(btext, "not assigned");
|
|
SetDlgItemText(hwndDlg, 116, btext);
|
|
|
|
break;
|
|
case WM_CLOSE:
|
|
case WM_QUIT: goto gornk;
|
|
case WM_COMMAND:
|
|
if(HIWORD(wParam)==CBN_SELENDOK)
|
|
{
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case 104:
|
|
case 105:UsrInputType[LOWORD(wParam)-104]=InputType[LOWORD(wParam)-104]=SendDlgItemMessage(hwndDlg,LOWORD(wParam),CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
|
|
EnableWindow( GetDlgItem(hwndDlg,LOWORD(wParam)+2),haven[InputType[LOWORD(wParam)-104]]);
|
|
SetDlgItemText(hwndDlg,200+LOWORD(wParam)-104,(LPTSTR)strn[InputType[LOWORD(wParam)-104]]);
|
|
break;
|
|
case 110:UsrInputType[2]=InputType[2]=SendDlgItemMessage(hwndDlg,110,CB_GETCURSEL,0,(LPARAM)(LPSTR)0);
|
|
EnableWindow(GetDlgItem(hwndDlg,111),havef[InputType[2]]);
|
|
SetDlgItemText(hwndDlg,202,(LPTSTR)strf[InputType[2]]);
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
if(!(wParam>>16))
|
|
switch(wParam&0xFFFF)
|
|
{
|
|
case 111:
|
|
{
|
|
const char *text = strf[InputType[2]];
|
|
DoTBType=DoTBPort=0;
|
|
|
|
switch(InputType[2])
|
|
{
|
|
case SIFC_FTRAINERA:
|
|
case SIFC_FTRAINERB:DoTBConfig(hwndDlg, text, "POWERPADDIALOG", FTrainerButtons, 12); break;
|
|
case SIFC_FKB:DoTBConfig(hwndDlg, text, "FKBDIALOG",fkbmap,0x48);break;
|
|
case SIFC_SUBORKB:DoTBConfig(hwndDlg, text, "SUBORKBDIALOG",suborkbmap,0x60);break;
|
|
case SIFC_QUIZKING:DoTBConfig(hwndDlg, text, "QUIZKINGDIALOG",QuizKingButtons,6);break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 107:
|
|
case 106:
|
|
{
|
|
int which=(wParam&0xFFFF)-106;
|
|
const char *text = strn[InputType[which]];
|
|
|
|
DoTBType=DoTBPort=0;
|
|
switch(InputType[which])
|
|
{
|
|
case SI_GAMEPAD:
|
|
{
|
|
ButtConfig tmp[10 + 10];
|
|
|
|
memcpy(tmp, GamePadConfig[which], 10 * sizeof(ButtConfig));
|
|
memcpy(&tmp[10], GamePadConfig[which+2], 10 * sizeof(ButtConfig));
|
|
|
|
DoTBType=SI_GAMEPAD;
|
|
DoTBPort=which;
|
|
DoTBConfig(hwndDlg, text, "GAMEPADDIALOG", tmp, 10 + 10);
|
|
|
|
memcpy(GamePadConfig[which], tmp, 10 * sizeof(ButtConfig));
|
|
memcpy(GamePadConfig[which+2], &tmp[10], 10 * sizeof(ButtConfig));
|
|
}
|
|
break;
|
|
|
|
case SI_POWERPADA:
|
|
case SI_POWERPADB:
|
|
DoTBConfig(hwndDlg, text, "POWERPADDIALOG",powerpadsc[which],12);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 112: // auto-hold button
|
|
{
|
|
char btext[128];
|
|
btext[0]=0;
|
|
GetDlgItemText(hwndDlg, 112, btext, 128);
|
|
int button = DWaitSimpleButton(hwndDlg, (uint8*)btext); //mbg merge 7/17/06
|
|
if(button)
|
|
{
|
|
if(!GetKeyNameText(button<<16,btext,128))
|
|
sprintf(btext, "KB: %d", button);
|
|
}
|
|
else
|
|
sprintf(btext, "not assigned");
|
|
extern int autoHoldKey;
|
|
autoHoldKey = button;
|
|
SetDlgItemText(hwndDlg, 115, btext);
|
|
}
|
|
break;
|
|
case 114: // auto-hold clear button
|
|
{
|
|
char btext[128];
|
|
btext[0]=0;
|
|
GetDlgItemText(hwndDlg, 114, btext, 128);
|
|
int button = DWaitSimpleButton(hwndDlg, (uint8*)btext); //mbg merge 7/17/06 added cast
|
|
if(button)
|
|
{
|
|
if(!GetKeyNameText(button<<16,btext,128))
|
|
sprintf(btext, "KB: %d", button);
|
|
}
|
|
else
|
|
sprintf(btext, "not assigned");
|
|
extern int autoHoldClearKey;
|
|
autoHoldClearKey = button;
|
|
SetDlgItemText(hwndDlg, 116, btext);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
gornk:
|
|
EndDialog(hwndDlg,0);
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void ConfigInput(HWND hParent)
|
|
{
|
|
DialogBox(fceu_hInstance,"INPUTCONFIG",hParent,InputConCallB);
|
|
if(GI)
|
|
InitOtherInput();
|
|
}
|
|
|
|
|
|
|
|
void DestroyInput(void)
|
|
{
|
|
if(lpDI)
|
|
{
|
|
KillJoysticks();
|
|
KeyboardClose();
|
|
IDirectInput7_Release(lpDI);
|
|
}
|
|
}
|
|
|
|
#define CMD_KEY_MASK 0xff
|
|
#define CMD_KEY_LSHIFT (1<<16)
|
|
#define CMD_KEY_RSHIFT (1<<17)
|
|
#define CMD_KEY_SHIFT (CMD_KEY_LSHIFT|CMD_KEY_RSHIFT)
|
|
#define CMD_KEY_LCTRL (1<<18)
|
|
#define CMD_KEY_RCTRL (1<<19)
|
|
#define CMD_KEY_CTRL (CMD_KEY_LCTRL|CMD_KEY_RCTRL)
|
|
#define CMD_KEY_LALT (1<<20)
|
|
#define CMD_KEY_RALT (1<<21)
|
|
#define CMD_KEY_ALT (CMD_KEY_LALT|CMD_KEY_RALT)
|
|
|
|
int FCEUD_CommandMapping[EMUCMD_MAX];
|
|
|
|
CFGSTRUCT HotkeyConfig[]={
|
|
AC(FCEUD_CommandMapping),
|
|
ENDCFGSTRUCT
|
|
};
|
|
|
|
static struct
|
|
{
|
|
int cmd;
|
|
int key;
|
|
} DefaultCommandMapping[]=
|
|
{
|
|
{ EMUCMD_RESET, SCAN_R | CMD_KEY_CTRL, },
|
|
{ EMUCMD_PAUSE, SCAN_PAUSE, },
|
|
{ EMUCMD_FRAME_ADVANCE, SCAN_BACKSLASH, },
|
|
{ EMUCMD_SCREENSHOT, SCAN_F12 },
|
|
{ EMUCMD_HIDE_MENU_TOGGLE, SCAN_ESCAPE },
|
|
{ EMUCMD_SPEED_SLOWER, SCAN_MINUS, },
|
|
{ EMUCMD_SPEED_FASTER, SCAN_EQUAL, },
|
|
{ EMUCMD_SPEED_TURBO, SCAN_TAB, },
|
|
{ EMUCMD_SAVE_SLOT_0, SCAN_0, },
|
|
{ EMUCMD_SAVE_SLOT_1, SCAN_1, },
|
|
{ EMUCMD_SAVE_SLOT_2, SCAN_2, },
|
|
{ EMUCMD_SAVE_SLOT_3, SCAN_3, },
|
|
{ EMUCMD_SAVE_SLOT_4, SCAN_4, },
|
|
{ EMUCMD_SAVE_SLOT_5, SCAN_5, },
|
|
{ EMUCMD_SAVE_SLOT_6, SCAN_6, },
|
|
{ EMUCMD_SAVE_SLOT_7, SCAN_7, },
|
|
{ EMUCMD_SAVE_SLOT_8, SCAN_8, },
|
|
{ EMUCMD_SAVE_SLOT_9, SCAN_9, },
|
|
{ EMUCMD_SAVE_STATE, SCAN_F5 | CMD_KEY_CTRL, },
|
|
{ EMUCMD_LOAD_STATE, SCAN_F7 | CMD_KEY_CTRL, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_0, SCAN_F10 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_1, SCAN_F1 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_2, SCAN_F2 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_3, SCAN_F3 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_4, SCAN_F4 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_5, SCAN_F5 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_6, SCAN_F6 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_7, SCAN_F7 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_8, SCAN_F8 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_SAVE_STATE_SLOT_9, SCAN_F9 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_0, SCAN_F10, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_1, SCAN_F1, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_2, SCAN_F2, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_3, SCAN_F3, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_4, SCAN_F4, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_5, SCAN_F5, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_6, SCAN_F6, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_7, SCAN_F7, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_8, SCAN_F8, },
|
|
{ EMUCMD_LOAD_STATE_SLOT_9, SCAN_F9, },
|
|
/* { EMUCMD_MOVIE_SLOT_0, SCAN_0 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_1, SCAN_1 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_2, SCAN_2 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_3, SCAN_3 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_4, SCAN_4 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_5, SCAN_5 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_6, SCAN_6 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_7, SCAN_7 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_8, SCAN_8 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_SLOT_9, SCAN_9 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_RECORD, SCAN_F5 | CMD_KEY_ALT, },
|
|
{ EMUCMD_MOVIE_REPLAY, SCAN_F7 | CMD_KEY_ALT, },*/
|
|
{ EMUCMD_MOVIE_FRAME_DISPLAY_TOGGLE, SCAN_PERIOD, },
|
|
{ EMUCMD_FDS_EJECT_INSERT, SCAN_F8 | CMD_KEY_CTRL, },
|
|
{ EMUCMD_FDS_SIDE_SELECT, SCAN_F6 | CMD_KEY_CTRL, },
|
|
{ EMUCMD_MOVIE_INPUT_DISPLAY_TOGGLE, SCAN_COMMA, },
|
|
{ EMUCMD_MOVIE_READONLY_TOGGLE, SCAN_8 | CMD_KEY_SHIFT, },
|
|
{ EMUCMD_MISC_REWIND, SCAN_R, },
|
|
};
|
|
|
|
#define NUM_DEFAULT_MAPPINGS (sizeof(DefaultCommandMapping)/sizeof(DefaultCommandMapping[0]))
|
|
|
|
void ApplyDefaultCommandMapping(void)
|
|
{
|
|
int i;
|
|
|
|
memset(FCEUD_CommandMapping, 0, sizeof(FCEUD_CommandMapping));
|
|
for(i=0; i<NUM_DEFAULT_MAPPINGS; ++i)
|
|
FCEUD_CommandMapping[DefaultCommandMapping[i].cmd] = DefaultCommandMapping[i].key;
|
|
}
|
|
|
|
int FCEUD_TestCommandState(int c)
|
|
{
|
|
int cmd=FCEUD_CommandMapping[c];
|
|
int cmdmask=cmd&CMD_KEY_MASK;
|
|
|
|
// allow certain commands be affected by key repeat
|
|
if(c == EMUCMD_FRAME_ADVANCE/*
|
|
|| c == EMUCMD_SOUND_VOLUME_UP
|
|
|| c == EMUCMD_SOUND_VOLUME_DOWN
|
|
|| c == EMUCMD_SPEED_SLOWER
|
|
|| c == EMUCMD_SPEED_FASTER*/)
|
|
{
|
|
keys=GetKeyboard();
|
|
/* if((cmdmask & CMD_KEY_LALT) == CMD_KEY_LALT
|
|
|| (cmdmask & CMD_KEY_RALT) == CMD_KEY_RALT
|
|
|| (cmdmask & CMD_KEY_LALT) == CMD_KEY_LALT
|
|
|| (cmdmask & CMD_KEY_LCTRL) == CMD_KEY_LCTRL
|
|
|| (cmdmask & CMD_KEY_RCTRL) == CMD_KEY_RCTRL
|
|
|| (cmdmask & CMD_KEY_LSHIFT) == CMD_KEY_LSHIFT
|
|
|| (cmdmask & CMD_KEY_RSHIFT) == CMD_KEY_RSHIFT)*/
|
|
keys_nr=GetKeyboard();
|
|
// else
|
|
// keys_nr=GetKeyboard_nr();
|
|
}
|
|
else if(c != EMUCMD_SPEED_TURBO) // TODO: this should be made more general by detecting if the command has an "off" function, but right now Turbo is the only command that has it
|
|
{
|
|
keys=GetKeyboard_jd();
|
|
keys_nr=GetKeyboard_nr();
|
|
}
|
|
else
|
|
{
|
|
keys=GetKeyboard_nr();
|
|
keys_nr=GetKeyboard_nr();
|
|
}
|
|
|
|
/* test CTRL, SHIFT, ALT */
|
|
if (cmd & CMD_KEY_ALT)
|
|
{
|
|
int ctlstate = (cmd & CMD_KEY_LALT) ? keys_nr[SCAN_LEFTALT] : 0;
|
|
ctlstate |= (cmd & CMD_KEY_RALT) ? keys_nr[SCAN_RIGHTALT] : 0;
|
|
if (!ctlstate)
|
|
return 0;
|
|
}
|
|
else if((cmdmask != SCAN_LEFTALT && keys_nr[SCAN_LEFTALT]) || (cmdmask != SCAN_RIGHTALT && keys_nr[SCAN_RIGHTALT]))
|
|
return 0;
|
|
|
|
if (cmd & CMD_KEY_CTRL)
|
|
{
|
|
int ctlstate = (cmd & CMD_KEY_LCTRL) ? keys_nr[SCAN_LEFTCONTROL] : 0;
|
|
ctlstate |= (cmd & CMD_KEY_RCTRL) ? keys_nr[SCAN_RIGHTCONTROL] : 0;
|
|
if (!ctlstate)
|
|
return 0;
|
|
}
|
|
else if((cmdmask != SCAN_LEFTCONTROL && keys_nr[SCAN_LEFTCONTROL]) || (cmdmask != SCAN_RIGHTCONTROL && keys_nr[SCAN_RIGHTCONTROL]))
|
|
return 0;
|
|
|
|
if (cmd & CMD_KEY_SHIFT)
|
|
{
|
|
int ctlstate = (cmd & CMD_KEY_LSHIFT) ? keys_nr[SCAN_LEFTSHIFT] : 0;
|
|
ctlstate |= (cmd & CMD_KEY_RSHIFT) ? keys_nr[SCAN_RIGHTSHIFT] : 0;
|
|
if (!ctlstate)
|
|
return 0;
|
|
}
|
|
else if((cmdmask != SCAN_LEFTSHIFT && keys_nr[SCAN_LEFTSHIFT]) || (cmdmask != SCAN_RIGHTSHIFT && keys_nr[SCAN_RIGHTSHIFT]))
|
|
return 0;
|
|
|
|
return keys[cmdmask] ? 1 : 0;
|
|
}
|
|
|
|
static const char* ScanNames[256]=
|
|
{
|
|
/* 0x00-0x0f */ 0, "Escape", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Minus", "Equals", "Backspace", "Tab",
|
|
/* 0x10-0x1f */ "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "Enter", "Left Ctrl", "A", "S",
|
|
/* 0x20-0x2f */ "D", "F", "G", "H", "J", "K", "L", "Semicolon", "Apostrophe", "Grave", "Left Shift", "Backslash", "Z", "X", "C", "V",
|
|
/* 0x30-0x3f */ "B", "N", "M", "Comma", "Period", "Slash", "Right Shift", "Numpad *", "Left Alt", "Space", "Caps Lock", "F1", "F2", "F3", "F4", "F5",
|
|
/* 0x40-0x4f */ "F6", "F7", "F8", "F9", "F10", "NumLock", "ScrollLock", "Numpad 7", "Numpad 8", "Numpad 9", "Numpad Minus", "Numpad 4", "Numpad 5", "Numpad 6", "Numpad Plus", "Numpad 1",
|
|
/* 0x50-0x5f */ "Numpad 2", "Numpad 3", "Numpad 0", "Numpad Period", 0, 0, "Backslash", "F11", "F12", 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x60-0x6f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x70-0x7f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x80-0x8f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0x90-0x9f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Numpad Enter", "Right Ctrl", 0, 0,
|
|
/* 0xa0-0xaf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0xb0-0xbf */ 0, 0, 0, 0, 0, "Numpad Divide", 0, "PrintScrn", "Right Alt", 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0xc0-0xcf */ 0, 0, 0, 0, 0, "Pause", 0, "Home", "Up Arrow", "PgUp", 0, "Left Arrow", 0, "Right Arrow", 0, "End",
|
|
/* 0xd0-0xdf */ "Down Arrow", "PgDn", "Ins", "Del", 0, 0, 0, 0, 0, 0, 0, "Left Win", "Right Win", "AppMenu", 0, 0,
|
|
/* 0xe0-0xef */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
/* 0xf0-0xff */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
};
|
|
|
|
static const char* GetKeyName(int code)
|
|
{
|
|
static char name[16];
|
|
|
|
code &= 0xff;
|
|
if(ScanNames[code])
|
|
return ScanNames[code];
|
|
|
|
sprintf(name, "Key 0x%.2x", code);
|
|
return name;
|
|
}
|
|
|
|
static char* GetKeyComboName(int c)
|
|
{
|
|
static char text[80];
|
|
|
|
text[0]='\0';
|
|
if(!c)
|
|
return text;
|
|
|
|
if ((c & CMD_KEY_CTRL) == CMD_KEY_CTRL) strcat(text, "Ctrl + ");
|
|
else if ((c & CMD_KEY_CTRL) == CMD_KEY_LCTRL) strcat(text, "Left Ctrl + ");
|
|
else if ((c & CMD_KEY_CTRL) == CMD_KEY_RCTRL) strcat(text, "Right Ctrl + ");
|
|
if ((c & CMD_KEY_ALT) == CMD_KEY_ALT) strcat(text, "Alt + ");
|
|
else if ((c & CMD_KEY_ALT) == CMD_KEY_LALT) strcat(text, "Left Alt + ");
|
|
else if ((c & CMD_KEY_ALT) == CMD_KEY_RALT) strcat(text, "Right Alt + ");
|
|
if ((c & CMD_KEY_SHIFT) == CMD_KEY_SHIFT) strcat(text, "Shift + ");
|
|
else if ((c & CMD_KEY_SHIFT) == CMD_KEY_LSHIFT) strcat(text, "Left Shift + ");
|
|
else if ((c & CMD_KEY_SHIFT) == CMD_KEY_RSHIFT) strcat(text, "Right Shift + ");
|
|
|
|
strcat(text, GetKeyName(c & CMD_KEY_MASK));
|
|
|
|
return text;
|
|
}
|
|
|
|
struct INPUTDLGTHREADARGS
|
|
{
|
|
HANDLE hThreadExit;
|
|
HWND hwndDlg;
|
|
};
|
|
|
|
static DWORD WINAPI NewInputDialogThread(LPVOID lpvArg)
|
|
{
|
|
struct INPUTDLGTHREADARGS* args = (struct INPUTDLGTHREADARGS*)lpvArg;
|
|
|
|
while (args->hThreadExit)
|
|
{
|
|
if (WaitForSingleObject(args->hThreadExit, 20) == WAIT_OBJECT_0)
|
|
break;
|
|
|
|
// Poke our owner dialog periodically.
|
|
PostMessage(args->hwndDlg, WM_USER, 0, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int GetKeyPressed()
|
|
{
|
|
int key=0;
|
|
int i;
|
|
|
|
keys_nr=GetKeyboard_nr();
|
|
|
|
for(i=0; i<256 && !key; ++i)
|
|
{
|
|
if(_keyonly(i))
|
|
key=i;
|
|
}
|
|
return key;
|
|
}
|
|
|
|
static int NothingPressed()
|
|
{
|
|
int i;
|
|
|
|
keys_nr=GetKeyboard_nr();
|
|
|
|
for(i=0; i<256; ++i)
|
|
{
|
|
if(keys_nr[i])
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int GetKeyMeta(int key)
|
|
{
|
|
int meta = key & (~CMD_KEY_MASK);
|
|
switch(key & CMD_KEY_MASK)
|
|
{
|
|
case SCAN_LEFTCONTROL:
|
|
case SCAN_RIGHTCONTROL: return CMD_KEY_CTRL | meta;
|
|
case SCAN_LEFTALT:
|
|
case SCAN_RIGHTALT: return CMD_KEY_ALT | meta;
|
|
case SCAN_LEFTSHIFT:
|
|
case SCAN_RIGHTSHIFT: return CMD_KEY_SHIFT | meta;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return meta;
|
|
}
|
|
|
|
static void ClearExtraMeta(int* key)
|
|
{
|
|
switch((*key)&0xff)
|
|
{
|
|
case SCAN_LEFTCONTROL:
|
|
case SCAN_RIGHTCONTROL: *key &= ~(CMD_KEY_CTRL); break;
|
|
case SCAN_LEFTALT:
|
|
case SCAN_RIGHTALT: *key &= ~(CMD_KEY_ALT); break;
|
|
case SCAN_LEFTSHIFT:
|
|
case SCAN_RIGHTSHIFT: *key &= ~(CMD_KEY_SHIFT); break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static BOOL CALLBACK ChangeInputDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static HANDLE hThread = NULL;
|
|
static DWORD dwThreadId = 0;
|
|
static struct INPUTDLGTHREADARGS threadargs;
|
|
static int key=0;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
// Start the message thread.
|
|
threadargs.hThreadExit = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
threadargs.hwndDlg = hwndDlg;
|
|
hThread = CreateThread(NULL, 0, NewInputDialogThread, (LPVOID)&threadargs, 0, &dwThreadId);
|
|
key=0;
|
|
memset(keyonce, 0, sizeof(keyonce));
|
|
KeyboardSetBackgroundAccess(1);
|
|
SetFocus(GetDlgItem(hwndDlg, 100));
|
|
}
|
|
return FALSE;
|
|
|
|
case WM_COMMAND:
|
|
if(LOWORD(wParam) == 202 && HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
key=0;
|
|
PostMessage(hwndDlg, WM_USER+1, 0, 0); // Send quit message.
|
|
}
|
|
else if(LOWORD(wParam) == 200 && HIWORD(wParam) == BN_CLICKED)
|
|
{
|
|
key=-1;
|
|
PostMessage(hwndDlg, WM_USER+1, 0, 0); // Send quit message.
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_USER:
|
|
{
|
|
// Our thread sent us a timer signal.
|
|
int newkey;
|
|
int meta=GetKeyMeta(key);
|
|
|
|
KeyboardUpdateState();
|
|
|
|
if((newkey=GetKeyPressed()) != 0)
|
|
{
|
|
key = newkey | meta;
|
|
ClearExtraMeta(&key);
|
|
SetDlgItemText(hwndDlg, 100, GetKeyComboName(key));
|
|
}
|
|
else if(NothingPressed() && key)
|
|
PostMessage(hwndDlg, WM_USER+1, 0, 0); // Send quit message.
|
|
}
|
|
break;
|
|
|
|
case WM_USER+1:
|
|
{
|
|
// Done with keyboard.
|
|
KeyboardSetBackgroundAccess(0);
|
|
|
|
// Kill the thread.
|
|
SetEvent(threadargs.hThreadExit);
|
|
WaitForSingleObject(hThread, INFINITE);
|
|
CloseHandle(hThread);
|
|
CloseHandle(threadargs.hThreadExit);
|
|
|
|
// End the dialog.
|
|
EndDialog(hwndDlg, key);
|
|
return TRUE;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int* ConflictTable=0;
|
|
|
|
static int ShouldDisplayMapping(int mapn, int filter)
|
|
{
|
|
//mbg merge 7/17/06 changed to if..elseif
|
|
if(filter==0) /* No filter */
|
|
return 1;
|
|
else if(filter <= EMUCMDTYPE_MAX) /* Filter by type */
|
|
return (FCEUI_CommandTable[mapn].type == filter-1);
|
|
else if(filter == EMUCMDTYPE_MAX+1) /* Assigned */
|
|
return FCEUD_CommandMapping[mapn];
|
|
else if(filter == EMUCMDTYPE_MAX+2) /* Unassigned */
|
|
return !(FCEUD_CommandMapping[mapn]);
|
|
else if(filter == EMUCMDTYPE_MAX+3) /* Conflicts */
|
|
return ConflictTable[mapn];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static void PopulateMappingDisplay(HWND hwndDlg)
|
|
{
|
|
LVITEM lvi;
|
|
int i;
|
|
int idx;
|
|
HWND hwndListView = GetDlgItem(hwndDlg, 1003);
|
|
int num=SendMessage(hwndListView, LVM_GETITEMCOUNT, 0, 0);
|
|
int filter = (int)SendDlgItemMessage(hwndDlg, 300, CB_GETCURSEL, 0, 0);
|
|
|
|
// Delete everything in the current display.
|
|
for(i=num; i>0; --i)
|
|
SendMessage(hwndListView, LVM_DELETEITEM, (WPARAM)i-1, 0);
|
|
|
|
// Get the filter type.
|
|
ConflictTable=0;
|
|
if (filter == EMUCMDTYPE_MAX+3)
|
|
{
|
|
// Set up the conflict table.
|
|
ConflictTable=(int*)malloc(sizeof(int)*EMUCMD_MAX);
|
|
memset(ConflictTable, 0, sizeof(int)*EMUCMD_MAX);
|
|
for(i=0; i<EMUCMD_MAX-1; ++i)
|
|
{
|
|
int j;
|
|
for(j=i+1; j<EMUCMD_MAX; ++j)
|
|
{
|
|
if(FCEUD_CommandMapping[i] &&
|
|
FCEUD_CommandMapping[i] == FCEUD_CommandMapping[j])
|
|
{
|
|
ConflictTable[i]=1;
|
|
ConflictTable[j]=1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Populate display.
|
|
for(i=0, idx=0; i<EMUCMD_MAX; ++i)
|
|
{
|
|
if(ShouldDisplayMapping(i, filter))
|
|
{
|
|
memset(&lvi, 0, sizeof(lvi));
|
|
lvi.mask = LVIF_TEXT | LVIF_PARAM;
|
|
lvi.iItem = idx;
|
|
lvi.iSubItem = 0;
|
|
lvi.pszText = (char*)FCEUI_CommandTypeNames[FCEUI_CommandTable[i].type];
|
|
lvi.lParam = (LPARAM)i;
|
|
|
|
SendMessage(hwndListView, LVM_INSERTITEM, (WPARAM)0, (LPARAM)&lvi);
|
|
|
|
memset(&lvi, 0, sizeof(lvi));
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.iItem = idx;
|
|
lvi.iSubItem = 1;
|
|
lvi.pszText = FCEUI_CommandTable[i].name;
|
|
|
|
SendMessage(hwndListView, LVM_SETITEM, (WPARAM)0, (LPARAM)&lvi);
|
|
|
|
memset(&lvi, 0, sizeof(lvi));
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.iItem = idx;
|
|
lvi.iSubItem = 2;
|
|
lvi.pszText = GetKeyComboName(FCEUD_CommandMapping[i]);
|
|
|
|
SendMessage(hwndListView, LVM_SETITEM, (WPARAM)0, (LPARAM)&lvi);
|
|
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
if(ConflictTable)
|
|
free(ConflictTable);
|
|
}
|
|
|
|
static BOOL CALLBACK MapInputDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HWND hwndListView = GetDlgItem(hwndDlg, 1003);
|
|
LVCOLUMN lv;
|
|
//LVITEM lvi; //mbg merge 7/17/06 removed
|
|
int i;
|
|
|
|
// Set full row select.
|
|
SendMessage(hwndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
|
|
|
|
// Init ListView columns.
|
|
memset(&lv, 0, sizeof(lv));
|
|
lv.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
|
lv.fmt = LVCFMT_LEFT;
|
|
lv.pszText = "Type";
|
|
lv.cx = 40;
|
|
|
|
SendMessage(hwndListView, LVM_INSERTCOLUMN, (WPARAM)0, (LPARAM)&lv);
|
|
|
|
memset(&lv, 0, sizeof(lv));
|
|
lv.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
|
|
lv.fmt = LVCFMT_LEFT;
|
|
lv.pszText = "Command";
|
|
lv.cx = 180;
|
|
|
|
SendMessage(hwndListView, LVM_INSERTCOLUMN, (WPARAM)1, (LPARAM)&lv);
|
|
|
|
memset(&lv, 0, sizeof(lv));
|
|
lv.mask = LVCF_FMT | LVCF_TEXT;
|
|
lv.fmt = LVCFMT_LEFT;
|
|
lv.pszText = "Input";
|
|
|
|
SendMessage(hwndListView, LVM_INSERTCOLUMN, (WPARAM)2, (LPARAM)&lv);
|
|
|
|
// Populate the filter combobox.
|
|
SendDlgItemMessage(hwndDlg, 300, CB_INSERTSTRING, 0, (LPARAM)"None");
|
|
for(i=0; i<EMUCMDTYPE_MAX; ++i)
|
|
SendDlgItemMessage(hwndDlg, 300, CB_INSERTSTRING, i+1, (LPARAM)FCEUI_CommandTypeNames[i]);
|
|
SendDlgItemMessage(hwndDlg, 300, CB_INSERTSTRING, ++i, (LPARAM)"Assigned");
|
|
SendDlgItemMessage(hwndDlg, 300, CB_INSERTSTRING, ++i, (LPARAM)"Unassigned");
|
|
SendDlgItemMessage(hwndDlg, 300, CB_INSERTSTRING, ++i, (LPARAM)"Conflicts");
|
|
|
|
SendDlgItemMessage(hwndDlg, 300, CB_SETCURSEL, 0, 0); // Default filter is "none".
|
|
|
|
// Now populate the mapping display.
|
|
PopulateMappingDisplay(hwndDlg);
|
|
|
|
// Autosize last column.
|
|
SendMessage(hwndListView, LVM_SETCOLUMNWIDTH, (WPARAM)2, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0));
|
|
|
|
}
|
|
return FALSE;
|
|
|
|
case WM_COMMAND:
|
|
if(HIWORD(wParam) == CBN_SELCHANGE)
|
|
{
|
|
PopulateMappingDisplay(hwndDlg);
|
|
break;
|
|
}
|
|
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
EndDialog(hwndDlg, 1);
|
|
return TRUE;
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hwndDlg, 0);
|
|
return TRUE;
|
|
|
|
case 200:
|
|
ApplyDefaultCommandMapping();
|
|
PopulateMappingDisplay(hwndDlg);
|
|
return TRUE;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
switch(LOWORD(wParam))
|
|
{
|
|
case 1003:
|
|
if (lParam)
|
|
{
|
|
HWND hwndListView = GetDlgItem(hwndDlg, 1003);
|
|
NMHDR* pnm = (NMHDR*)lParam;
|
|
if (pnm->code == LVN_ITEMACTIVATE)
|
|
{
|
|
int nSel = SendMessage(hwndListView, LVM_GETNEXTITEM, (WPARAM)-1, LVNI_SELECTED);
|
|
if (nSel != -1)
|
|
{
|
|
int nCmd;
|
|
int nRet;
|
|
LVITEM lvi;
|
|
|
|
// Get the corresponding input
|
|
memset(&lvi, 0, sizeof(lvi));
|
|
lvi.mask = LVIF_PARAM;
|
|
lvi.iItem = nSel;
|
|
lvi.iSubItem = 0;
|
|
SendMessage(hwndListView, LVM_GETITEM, 0, (LPARAM)&lvi);
|
|
nCmd = lvi.lParam;
|
|
|
|
nRet = DialogBox(fceu_hInstance,"NEWINPUT",hwndListView,ChangeInputDialogProc);
|
|
if (nRet)
|
|
{
|
|
// nRet will be -1 when the user selects "clear".
|
|
FCEUD_CommandMapping[nCmd] = (nRet<0) ? 0 : nRet;
|
|
|
|
memset(&lvi, 0, sizeof(lvi));
|
|
lvi.mask = LVIF_TEXT;
|
|
lvi.iItem = nSel;
|
|
lvi.iSubItem = 2;
|
|
lvi.pszText = GetKeyComboName(FCEUD_CommandMapping[nCmd]);
|
|
SendMessage(hwndListView, LVM_SETITEM, (WPARAM)0, (LPARAM)&lvi);
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void MapInput(void)
|
|
{
|
|
// Make a backup of the current mappings, in case the user changes their mind.
|
|
int* backupmapping = (int*)malloc(sizeof(FCEUD_CommandMapping));
|
|
memcpy(backupmapping, FCEUD_CommandMapping, sizeof(FCEUD_CommandMapping));
|
|
|
|
if(!DialogBox(fceu_hInstance,"MAPINPUT",hAppWnd,MapInputDialogProc))
|
|
memcpy(FCEUD_CommandMapping, backupmapping, sizeof(FCEUD_CommandMapping));
|
|
|
|
free(backupmapping);
|
|
}
|
|
|
|
void FCEUD_TurboOn(void)
|
|
{
|
|
NoWaiting|=1;
|
|
}
|
|
|
|
void FCEUD_TurboOff(void)
|
|
{
|
|
NoWaiting&=~1;
|
|
}
|
|
|