initial fce ultra 0.81 import
[fceu.git] / drivers / win / keyboard.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Ben Parnell
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "common.h"
22 #include <dinput.h>
23
24
25 #include "input.h"
26 #include "keyboard.h"
27
28 #include "keyscan.h"
29
30
31 HRESULT  ddrval;
32
33 static LPDIRECTINPUTDEVICE7 lpdid=0;
34 static int porttemp;
35
36
37 int keyBMap[4][8]={
38                    {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT},
39                    {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT},
40                    {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT},
41                    {SCAN_LEFTALT,SCAN_LEFTCONTROL,SCAN_TAB,SCAN_ENTER,SCAN_BL_CURSORUP,SCAN_BL_CURSORDOWN,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT}
42                   };
43 int keybEnable=1;
44
45 int powerpadside=0;
46 int powerpadsc[2][12]={
47                               {
48                                SCAN_O,SCAN_P,SCAN_BRACKET_LEFT,
49                                SCAN_BRACKET_RIGHT,SCAN_K,SCAN_L,SCAN_SEMICOLON,SCAN_APOSTROPHE,
50                                SCAN_M,SCAN_COMMA,SCAN_PERIOD,SCAN_SLASH
51                               },
52                               {
53                                SCAN_O,SCAN_P,SCAN_BRACKET_LEFT,
54                                SCAN_BRACKET_RIGHT,SCAN_K,SCAN_L,SCAN_SEMICOLON,SCAN_APOSTROPHE,
55                                SCAN_M,SCAN_COMMA,SCAN_PERIOD,SCAN_SLASH
56                               }
57                              };
58
59
60
61
62 void KeyboardClose(void)
63 {
64  if(lpdid) IDirectInputDevice7_Unacquire(lpdid);
65  lpdid=0;
66 }
67
68 static char keys[256];
69 static void KeyboardUpdateState(void)
70 {
71  ddrval=IDirectInputDevice7_GetDeviceState(lpdid,256,keys);
72  switch(ddrval)
73   {
74    case DIERR_INPUTLOST:
75    case DIERR_NOTACQUIRED:
76                          IDirectInputDevice7_Acquire(lpdid);
77                          break;
78   }
79 }
80
81 int KeyboardInitialize(void)
82 {
83
84  if(lpdid)
85   return(1);
86
87  ddrval=IDirectInput7_CreateDeviceEx(lpDI, &GUID_SysKeyboard,&IID_IDirectInputDevice7, (LPVOID *)&lpdid,0);
88  if(ddrval != DI_OK)
89  {
90   FCEUD_PrintError("DirectInput: Error creating keyboard device.");
91   return 0;
92  }
93
94  ddrval=IDirectInputDevice7_SetCooperativeLevel(lpdid, hAppWnd,DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
95  if(ddrval != DI_OK)
96  {
97   FCEUD_PrintError("DirectInput: Error setting keyboard cooperative level.");
98   return 0;
99  }
100
101  ddrval=IDirectInputDevice7_SetDataFormat(lpdid,&c_dfDIKeyboard);
102  if(ddrval != DI_OK)
103  {
104   FCEUD_PrintError("DirectInput: Error setting keyboard data format.");
105   return 0;
106  }
107
108  ddrval=IDirectInputDevice7_Acquire(lpdid);
109  if(ddrval != DI_OK)
110  {
111   FCEUD_PrintError("DirectInput: Error acquiring keyboard.");
112   return 0;
113  }
114  return 1;
115 }
116
117 static int DIPS=0;
118 static uint8 keyonce[256];
119 #define KEY(__a) keys[SCAN_##__a]
120 #define keyonly(__a,__z) {if(KEY(__a)){if(!keyonce[SCAN_##__a]) {keyonce[SCAN_##__a]=1;__z}} else{keyonce[SCAN_##__a]=0;}}
121 int cidisabled=0;
122
123 void KeyboardUpdate(void)
124
125  KeyboardUpdateState();
126
127  if(InputTypeFC==SIFC_FKB && cidisabled)
128   return;
129
130  NoWaiting&=~1;
131  if(KEY(GRAVE))
132   NoWaiting|=1;
133
134  if(GI)
135  {
136   if(GI->type==GIT_FDS)
137   {
138    keyonly(S,DriverInterface(DES_FDSSELECT,0);)
139    keyonly(I,DriverInterface(DES_FDSINSERT,0);)
140    keyonly(E,DriverInterface(DES_FDSEJECT,0);)
141   }
142
143   if(GI->type!=GIT_NSF)
144   {
145    keyonly(F5,FCEUI_SaveState();)
146    keyonly(F7,FCEUI_LoadState();)
147   }
148   keyonly(F9,FCEUI_SaveSnapshot();)
149
150   if(GI->type==GIT_VSUNI)
151   {
152    keyonly(C,DriverInterface(DES_VSUNICOIN,0);)
153    keyonly(V,DIPS^=1;DriverInterface(DES_VSUNITOGGLEDIPVIEW,0);)
154    if(!(DIPS&1)) goto DIPSless;
155    keyonly(1,DriverInterface(DES_VSUNIDIPSET,(void *)1);)
156    keyonly(2,DriverInterface(DES_VSUNIDIPSET,(void *)2);)
157    keyonly(3,DriverInterface(DES_VSUNIDIPSET,(void *)3);)
158    keyonly(4,DriverInterface(DES_VSUNIDIPSET,(void *)4);)
159    keyonly(5,DriverInterface(DES_VSUNIDIPSET,(void *)5);)
160    keyonly(6,DriverInterface(DES_VSUNIDIPSET,(void *)6);)
161    keyonly(7,DriverInterface(DES_VSUNIDIPSET,(void *)7);)
162    keyonly(8,DriverInterface(DES_VSUNIDIPSET,(void *)8);)
163   }
164   else
165   {
166    keyonly(H,DriverInterface(DES_NTSCSELHUE,0);)
167    keyonly(T,DriverInterface(DES_NTSCSELTINT,0);)
168    if(KEY(KP_MINUS) || KEY(MINUS)) DriverInterface(DES_NTSCDEC,0);
169    if(KEY(KP_PLUS) || KEY(EQUAL)) DriverInterface(DES_NTSCINC,0);
170
171    DIPSless:
172    keyonly(0,FCEUI_SelectState(0);)
173    keyonly(1,FCEUI_SelectState(1);)
174    keyonly(2,FCEUI_SelectState(2);)
175    keyonly(3,FCEUI_SelectState(3);)
176    keyonly(4,FCEUI_SelectState(4);)
177    keyonly(5,FCEUI_SelectState(5);)
178    keyonly(6,FCEUI_SelectState(6);)
179    keyonly(7,FCEUI_SelectState(7);)
180    keyonly(8,FCEUI_SelectState(8);)
181    keyonly(9,FCEUI_SelectState(9);)
182   }
183  }
184 }
185
186 uint32 KeyboardDodo(void)
187 {
188  uint32 JS=0;
189
190
191  if(GI)
192  if(GI->type!=GIT_NSF)
193  {
194   int x,y,u,b;
195
196   for(u=0;u<4;u++)
197   {
198    if(keybEnable&(1<<u))
199    {
200     int *tmpo=keyBMap[u];
201     x=y=0;
202
203     for(b=3;b>=0;b--)
204      if(keys[tmpo[b]]) JS|=(1<<b)<<(u<<3);
205
206     if(keys[tmpo[4]])    y|= JOY_UP;
207     if(keys[tmpo[5]])  y|= JOY_DOWN;
208     if(keys[tmpo[6]])  x|= JOY_LEFT;
209     if(keys[tmpo[7]]) x|= JOY_RIGHT;
210
211     if(y!=(JOY_DOWN|JOY_UP)) JS|=y<<(u<<3);
212     if(x!=(JOY_LEFT|JOY_RIGHT)) JS|=x<<(u<<3);
213    }
214   }
215  }
216  return JS;
217 }
218
219 uint32 UpdatePPadData(int w)
220 {
221  static const char shifttableA[12]={8,9,0,1,11,7,4,2,10,6,5,3};
222  static const char shifttableB[12]={1,0,9,8,2,4,7,11,3,5,6,10};
223  uint32 r=0;
224  int *ppadtsc=powerpadsc[w];
225  int x;
226
227  if(powerpadside&(1<<w))
228  {
229   for(x=0;x<12;x++)
230    if(keys[ppadtsc[x]]) r|=1<<shifttableA[x];
231  }
232  else
233  {
234   for(x=0;x<12;x++)
235    if(keys[ppadtsc[x]]) r|=1<<shifttableB[x];
236  }
237  return r;
238 }
239
240 int fkbmap[0x48]=
241 {
242  SCAN_F1,SCAN_F2,SCAN_F3,SCAN_F4,SCAN_F5,SCAN_F6,SCAN_F7,SCAN_F8,
243  SCAN_1,SCAN_2,SCAN_3,SCAN_4,SCAN_5,SCAN_6,SCAN_7,SCAN_8,SCAN_9,SCAN_0,
244         SCAN_MINUS,SCAN_EQUAL,SCAN_BACKSLASH,SCAN_BACKSPACE,
245  SCAN_ESCAPE,SCAN_Q,SCAN_W,SCAN_E,SCAN_R,SCAN_T,SCAN_Y,SCAN_U,SCAN_I,SCAN_O,
246         SCAN_P,SCAN_GRAVE,SCAN_BRACKET_LEFT,SCAN_ENTER,
247  SCAN_LEFTCONTROL,SCAN_A,SCAN_S,SCAN_D,SCAN_F,SCAN_G,SCAN_H,SCAN_J,SCAN_K,
248         SCAN_L,SCAN_SEMICOLON,SCAN_APOSTROPHE,SCAN_BRACKET_RIGHT,SCAN_BL_INSERT,
249  SCAN_LEFTSHIFT,SCAN_Z,SCAN_X,SCAN_C,SCAN_V,SCAN_B,SCAN_N,SCAN_M,SCAN_COMMA,
250         SCAN_PERIOD,SCAN_SLASH,SCAN_RIGHTALT,SCAN_RIGHTSHIFT,SCAN_LEFTALT,SCAN_SPACE,
251  SCAN_BL_DELETE,SCAN_BL_END,SCAN_BL_PAGEDOWN,
252  SCAN_BL_CURSORUP,SCAN_BL_CURSORLEFT,SCAN_BL_CURSORRIGHT,SCAN_BL_CURSORDOWN
253 };
254
255 uint8 fkbkeys[0x48];
256 void UpdateFKB(void)
257 {
258  int x;
259
260  for(x=0;x<0x48;x++)
261  {
262   fkbkeys[x]=0;
263   if(keys[fkbmap[x]])
264    fkbkeys[x]=1;
265  }
266 }
267
268
269
270 static int inkeyloop=0;
271
272 static BOOL CALLBACK KeyConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
273 {
274   int x,y;
275   char tempo[64];
276
277   switch(uMsg) {
278    case WM_USER+666:
279                    if(inkeyloop)
280                    {
281                     SetDlgItemInt(hwndDlg,inkeyloop,lParam,0);
282                     inkeyloop=0;
283                    }                   
284                    break;
285    case WM_INITDIALOG:
286                 sprintf(tempo,"Virtual Gamepad %d",porttemp+1);
287                 SetDlgItemText(hwndDlg,302,tempo);
288                 sprintf(tempo,"Virtual Gamepad %d",porttemp+3);
289                 SetDlgItemText(hwndDlg,311,tempo);
290
291                 for(x=0;x<2;x++)
292                 {
293                  for(y=0;y<8;y++)
294                   SetDlgItemInt(hwndDlg,600+y+x*10,keyBMap[porttemp+(x<<1)][y],0);
295                  if(keybEnable&(1<<((x<<1)+porttemp)))
296                   CheckDlgButton(hwndDlg,320+x,BST_CHECKED);
297                 }
298                 break;
299    case WM_CLOSE:
300    case WM_QUIT: goto gornk;
301    case WM_COMMAND:
302                   if(!(wParam>>16))
303                   {
304                    wParam&=0xFFFF;
305                    if((wParam>=600 && wParam<=607) || (wParam>=610 && wParam<=617))
306                     inkeyloop=wParam;
307                    else switch(wParam)
308                    {                    
309                     case 1:
310                            gornk:
311                            for(x=0;x<2;x++)
312                            {
313                             for(y=0;y<8;y++)
314                              keyBMap[porttemp+(x<<1)][y]=GetDlgItemInt(hwndDlg,600+y+x*10,0,0);
315
316                             if(IsDlgButtonChecked(hwndDlg,320+x)==BST_CHECKED)
317                              keybEnable|=(1<<((x<<1)+porttemp));
318                             else
319                              keybEnable&=~(1<<((x<<1)+porttemp));
320                            }
321
322                            EndDialog(hwndDlg,0);
323                            break;
324                    }  
325                   }
326               }
327   return 0;
328 }
329
330 static BOOL CALLBACK KeyPPConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
331 {
332   int x;
333   char tempo[64];
334
335   switch(uMsg) {
336    case WM_USER+666:
337                    if(inkeyloop)
338                    {
339                     SetDlgItemInt(hwndDlg,inkeyloop,lParam,0);
340                     inkeyloop=0;
341                    }                   
342                    break;
343    case WM_INITDIALOG:
344                 for(x=0;x<12;x++)
345                  SetDlgItemInt(hwndDlg,500+x,powerpadsc[porttemp][x],0);
346                 CheckDlgButton(hwndDlg,300+((powerpadside>>porttemp)&1),BST_CHECKED);
347                 sprintf(tempo,"Virtual Power Pad %d",porttemp+1);
348                 SetDlgItemText(hwndDlg,302,tempo);
349                 break;
350    case WM_CLOSE:
351    case WM_QUIT: goto gornk;
352    case WM_COMMAND:
353                   if(!(wParam>>16))
354                   {                   
355                    wParam&=0xFFFF;
356                    if(wParam>=500 && wParam<=511)
357                     inkeyloop=wParam;
358                    else switch(wParam)
359                    {                    
360                     case 1:
361                            gornk:
362                            for(x=0;x<12;x++)
363                             powerpadsc[porttemp][x]=GetDlgItemInt(hwndDlg,500+x,0,0);
364                            powerpadside&=~(1<<porttemp);
365                            if(IsDlgButtonChecked(hwndDlg,301)==BST_CHECKED)
366                             powerpadside|=1<<porttemp;
367                            EndDialog(hwndDlg,0);
368                            break;
369                    }  
370                   }
371               }
372   return 0;
373 }
374
375 static BOOL CALLBACK FKBConCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
376 {
377   int x;
378
379   switch(uMsg) {
380    case WM_USER+666:
381                    if(inkeyloop)
382                    {
383                     SetDlgItemInt(hwndDlg,inkeyloop,lParam,0);
384                     fkbmap[inkeyloop-300]=lParam;
385                     inkeyloop=0;
386                    }                   
387                    break;
388    case WM_INITDIALOG:
389                 for(x=0;x<72;x++)
390                  SetDlgItemInt(hwndDlg,300+x,fkbmap[x],0);
391                 break;
392    case WM_CLOSE:
393    case WM_QUIT: goto gornk;
394    case WM_COMMAND:
395                   if(!(wParam>>16))
396                   {                   
397                    wParam&=0xFFFF;
398                    if(wParam>=300 && wParam<=371)
399                     inkeyloop=wParam;
400                    else switch(wParam)
401                    {                    
402                     case 1:
403                            gornk:
404                            EndDialog(hwndDlg,0);
405                            break;
406                    }  
407                   }
408               }
409   return 0;
410 }
411
412 static HHOOK hHook;
413 static LRESULT CALLBACK FilterFunc(int nCode, WORD wParam, DWORD lParam)
414 {
415  MSG FAR *ptrMsg;
416  LPARAM tmpo;
417
418  if(nCode>=0)
419  {
420   if(nCode==MSGF_DIALOGBOX)
421   {
422    ptrMsg=(MSG FAR *)lParam;
423    if(ptrMsg->message==WM_KEYDOWN || ptrMsg->message==WM_SYSKEYDOWN)
424    {
425     tmpo=((ptrMsg->lParam>>16)&0x7F)|((ptrMsg->lParam>>17)&0x80);
426     PostMessage(GetParent(ptrMsg->hwnd),WM_USER+666,0,tmpo);
427     if(inkeyloop) return 1;
428    }
429   }
430  }
431  return CallNextHookEx(hHook,nCode,wParam,lParam);
432 }
433
434
435 void ConfigKeyboardie(HWND hParent, int port)
436 {
437  porttemp=port;
438
439  hHook=SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)FilterFunc,fceu_hInstance,GetCurrentThreadId());
440  DialogBox(fceu_hInstance,"KEYCONFIG",hParent,KeyConCallB);
441  UnhookWindowsHookEx(hHook);
442 }
443
444 void ConfigKeyboardiePowerpad(HWND hParent, int port)
445 {
446  porttemp=port;
447
448  hHook=SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)FilterFunc,fceu_hInstance,GetCurrentThreadId());
449  DialogBox(fceu_hInstance,"KEYPPCONFIG",hParent,KeyPPConCallB);
450  UnhookWindowsHookEx(hHook);
451 }
452
453 void ConfigFKB(HWND hParent)
454 {
455  hHook=SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)FilterFunc,fceu_hInstance,GetCurrentThreadId());
456  DialogBox(fceu_hInstance,"FKBCONFIG",hParent,FKBConCallB);
457  UnhookWindowsHookEx(hHook);
458 }