DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/gui/sdl_mapper.cpp
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 
00020 #include <vector>
00021 #include <list>
00022 #include <string.h>
00023 #include <ctype.h>
00024 #include <stdarg.h>
00025 #include <stdio.h>
00026 #include <assert.h>
00027 
00028 
00029 #include "SDL.h"
00030 
00031 #include "dosbox.h"
00032 #include "video.h"
00033 #include "keyboard.h"
00034 #include "pic.h"
00035 #include "control.h"
00036 #include "joystick.h"
00037 #include "keymap.h"
00038 #include "support.h"
00039 #include "mapper.h"
00040 #include "setup.h"
00041 #include "menu.h"
00042 
00043 #include <map>
00044 
00045 std::map<std::string,std::string> pending_string_binds;
00046 
00047 void MAPPER_CheckKeyboardLayout();
00048 
00049 Bitu next_handler_xpos=0;
00050 Bitu next_handler_ypos=0;
00051 
00052 bool mapper_addhandler_create_buttons = false;
00053 
00054 bool isJPkeyboard = false;
00055 
00056 enum {
00057     CLR_BLACK=0,
00058     CLR_WHITE=1,
00059     CLR_RED=2,
00060     CLR_BLUE=3,
00061     CLR_GREEN=4
00062 };
00063 
00064 enum BB_Types {
00065     BB_Next,BB_Add,BB_Del,
00066     BB_Save,BB_Exit,BB_Capture
00067 };
00068 
00069 enum BC_Types {
00070     BC_Mod1,BC_Mod2,BC_Mod3,BC_Host,
00071     BC_Hold
00072 };
00073 
00074 #define BMOD_Mod1 0x0001
00075 #define BMOD_Mod2 0x0002
00076 #define BMOD_Mod3 0x0004
00077 #define BMOD_Host 0x0008
00078 
00079 #define BFLG_Hold 0x0001
00080 #define BFLG_Repeat 0x0004
00081 
00082 
00083 #define MAXSTICKS 8
00084 #define MAXACTIVE 16
00085 #define MAXBUTTON 32
00086 #define MAXBUTTON_CAP 16
00087 #define MAXAXIS 8
00088 #define MAXHAT 2
00089 
00090 class CEvent;
00091 class CHandlerEvent;
00092 class CButton;
00093 class CBind;
00094 class CBindGroup;
00095 
00096 static void SetActiveEvent(CEvent * event);
00097 static void SetActiveBind(CBind * _bind);
00098 extern Bit8u int10_font_14[256 * 14];
00099 
00100 static std::vector<CEvent *> events;
00101 static std::vector<CButton *> buttons;
00102 static std::vector<CBindGroup *> bindgroups;
00103 static std::vector<CHandlerEvent *> handlergroup;
00104 typedef std::list<CBind *> CBindList;
00105 typedef std::list<CEvent *>::iterator CEventList_it;
00106 typedef std::list<CBind *>::iterator CBindList_it;
00107 typedef std::vector<CButton *>::iterator CButton_it;
00108 typedef std::vector<CEvent *>::iterator CEventVector_it;
00109 typedef std::vector<CHandlerEvent *>::iterator CHandlerEventVector_it;
00110 typedef std::vector<CBindGroup *>::iterator CBindGroup_it;
00111 
00112 #include <map>
00113 
00114 static std::map<std::string, size_t> name_to_events;
00115 
00116 class CEvent;
00117 
00118 CEvent *get_mapper_event_by_name(const std::string &x);
00119 
00121 class CEvent {
00122 public:
00127     enum event_type {
00128         event_t=0,
00129         handler_event_t
00130     };
00131 public:
00138     CEvent(char const * const _entry,const enum event_type _type = event_t) {
00139         safe_strncpy(entry,_entry,sizeof(entry));
00140 
00141         {
00142             if (name_to_events.find(entry) != name_to_events.end())
00143                 E_Exit("Mapper: Event \"%s\" already defined",entry);
00144         }
00145 
00146         name_to_events[entry] = events.size();
00147 
00148         events.push_back(this);
00149         bindlist.clear();
00150         active=false;
00151         activity=0;
00152         current_value=0;
00153         type = _type;
00154 
00155         assert(get_mapper_event_by_name(entry) == this);
00156     }
00157 
00163     virtual std::string GetBindMenuText(void);
00164 
00166     void update_menu_shortcut(void) {
00167         if (!eventname.empty()) {
00168             DOSBoxMenu::item& item = mainMenu.get_item(std::string("mapper_") + std::string(eventname));
00169             std::string str = GetBindMenuText();
00170             item.set_shortcut_text(str);
00171             item.refresh_item(mainMenu);
00172 //            LOG_MSG("%s",str.c_str());
00173         }
00174     }
00175 
00177     void AddBind(CBind * bind);
00178 
00179     virtual ~CEvent();
00180 
00182     virtual void Active(bool yesno) {
00183         active = yesno;
00184     }
00185 
00187     virtual void ActivateEvent(bool ev_trigger,bool skip_action)=0;
00188 
00190     virtual void DeActivateEvent(bool ev_trigger)=0;
00191 
00193     void DeActivateAll(void);
00194 
00196     void SetValue(Bits value){
00197         current_value=value;
00198     }
00199 
00201     Bits GetValue(void) {
00202         return current_value;
00203     }
00204 
00206     char * GetName(void) { return entry; }
00207 
00209     virtual bool IsTrigger(void)=0;
00210 
00212     std::string eventname;
00213 
00215     enum event_type type;
00216 
00218     CBindList bindlist;
00219 
00221     bool active;
00222 protected:
00224     Bitu activity;
00225 
00227     char entry[16];
00228 
00230     Bits current_value;
00231 };
00232 
00233 CEvent *get_mapper_event_by_name(const std::string &x) {
00234     auto i = name_to_events.find(x);
00235 
00236     if (i != name_to_events.end()) {
00237         if (i->second >= events.size())
00238             E_Exit("Mapper: name to events contains out of range index for \"%s\"",x.c_str());
00239 
00240         return events[i->second];
00241     }
00242 
00243     return NULL;
00244 }
00245 
00247 class CTriggeredEvent : public CEvent {
00248 public:
00250     CTriggeredEvent(char const * const _entry) : CEvent(_entry) {}
00251 
00252     // methods below this line have sufficient documentation inherited from the base class
00253 
00254     virtual ~CTriggeredEvent() {}
00255 
00256     virtual bool IsTrigger(void) {
00257         return true;
00258     }
00259 
00260     void ActivateEvent(bool ev_trigger,bool skip_action) {
00261         if (current_value>25000) {
00262             /* value exceeds boundary, trigger event if not active */
00263             if (!activity && !skip_action) Active(true);
00264             if (activity<32767) activity++;
00265         } else {
00266             if (activity>0) {
00267                 /* untrigger event if it is fully inactive */
00268                 DeActivateEvent(ev_trigger);
00269                 activity=0;
00270             }
00271         }
00272     }
00273 
00274     void DeActivateEvent(bool /*ev_trigger*/) {
00275         activity--;
00276         if (!activity) Active(false);
00277     }
00278 };
00279 
00281 class CContinuousEvent : public CEvent {
00282 public:
00284     CContinuousEvent(char const * const _entry) : CEvent(_entry) {}
00285 
00286     // methods below this line have sufficient documentation inherited from the base class
00287 
00288     virtual ~CContinuousEvent() {}
00289 
00290     virtual bool IsTrigger(void) {
00291         return false;
00292     }
00293 
00294     void ActivateEvent(bool ev_trigger,bool skip_action) {
00295         if (ev_trigger) {
00296             activity++;
00297             if (!skip_action) Active(true);
00298         } else {
00299             /* test if no trigger-activity is present, this cares especially
00300                about activity of the opposite-direction joystick axis for example */
00301             if (!GetActivityCount()) Active(true);
00302         }
00303     }
00304 
00305     void DeActivateEvent(bool ev_trigger) {
00306         if (ev_trigger) {
00307             if (activity>0) activity--;
00308             if (activity==0) {
00309                 /* test if still some trigger-activity is present,
00310                    adjust the state in this case accordingly */
00311                 if (GetActivityCount()) RepostActivity();
00312                 else Active(false);
00313             }
00314         } else {
00315             if (!GetActivityCount()) Active(false);
00316         }
00317     }
00318 
00320     virtual Bitu GetActivityCount(void) {
00321         return activity;
00322     }
00323 
00325     virtual void RepostActivity(void) {}
00326 };
00327 
00329 class CBind {
00330 public:
00332     enum CBindType {
00333         bind_t=0,
00334         keybind_t
00335     };
00336 public:
00337     virtual ~CBind () {
00338         list->remove(this);
00339     }
00340 
00342     CBind(CBindList * _list,enum CBindType _type = bind_t) {
00343         list=_list;
00344         _list->push_back(this);
00345         mods=flags=0;
00346         event=0;
00347         active=holding=false;
00348         type = _type;
00349     }
00350 
00352     virtual std::string GetModifierText(void);
00353 
00355     virtual std::string GetBindMenuText(void) {
00356         return GetModifierText();
00357     }
00358 
00360     void AddFlags(char * buf) {
00361         if (mods & BMOD_Mod1) strcat(buf," mod1");
00362         if (mods & BMOD_Mod2) strcat(buf," mod2");
00363         if (mods & BMOD_Mod3) strcat(buf," mod3");
00364         if (mods & BMOD_Host) strcat(buf," host");
00365         if (flags & BFLG_Hold) strcat(buf," hold");
00366     }
00367 
00369     void SetFlags(char * buf) {
00370         char * word;
00371         while (*(word=StripWord(buf))) {
00372             if (!strcasecmp(word,"mod1")) mods|=BMOD_Mod1;
00373             if (!strcasecmp(word,"mod2")) mods|=BMOD_Mod2;
00374             if (!strcasecmp(word,"mod3")) mods|=BMOD_Mod3;
00375             if (!strcasecmp(word,"host")) mods|=BMOD_Host;
00376             if (!strcasecmp(word,"hold")) flags|=BFLG_Hold;
00377         }
00378     }
00379 
00381     void ActivateBind(Bits _value,bool ev_trigger,bool skip_action=false) {
00382         if (event->IsTrigger()) {
00383             /* use value-boundary for on/off events */
00384             if (_value>25000) {
00385                 event->SetValue(_value);
00386                 if (active) return;
00387                 if (!holding) event->ActivateEvent(ev_trigger,skip_action);
00388                 active=true;
00389             } else {
00390                 if (active) {
00391                     event->DeActivateEvent(ev_trigger);
00392                     active=false;
00393                 }
00394             }
00395         } else {
00396             /* store value for possible later use in the activated event */
00397             event->SetValue(_value);
00398             event->ActivateEvent(ev_trigger,false);
00399         }
00400     }
00401 
00403     void DeActivateBind(bool ev_trigger) {
00404         if (event->IsTrigger()) {
00405             if (!active) return;
00406             active=false;
00407             if (flags & BFLG_Hold) {
00408                 if (!holding) {
00409                     holding=true;
00410                     return;
00411                 } else {
00412                     holding=false;
00413                 }
00414             }
00415             event->DeActivateEvent(ev_trigger);
00416         } else {
00417             /* store value for possible later use in the activated event */
00418             event->SetValue(0);
00419             event->DeActivateEvent(ev_trigger);
00420         }
00421     }
00422 
00424     virtual void ConfigName(char * buf)=0;
00425 
00427     virtual void BindName(char * buf)=0;
00428 
00430     Bitu mods;
00431 
00433     Bitu flags;
00434 
00436     Bit16s value;
00437 
00439     CEvent * event;
00440 
00442     CBindList * list;
00443 
00445     bool active;
00446 
00448     bool holding;
00449 
00451     enum CBindType type;
00452 };
00453 
00454 CEvent::~CEvent() {
00455     CBindList_it it;
00456 
00457     while ((it=bindlist.begin()) != bindlist.end()) {
00458         delete (*it);
00459         bindlist.erase(it);
00460     }
00461 }
00462 
00463 void CEvent::AddBind(CBind * bind) {
00464     bindlist.push_front(bind);
00465     bind->event=this;
00466 }
00467 void CEvent::DeActivateAll(void) {
00468     for (CBindList_it bit=bindlist.begin();bit!=bindlist.end();bit++) {
00469         (*bit)->DeActivateBind(true);
00470     }
00471 }
00472 
00473 
00474 
00475 class CBindGroup {
00476 public:
00477     CBindGroup() {
00478         bindgroups.push_back(this);
00479     }
00480     virtual ~CBindGroup (void) { }
00481     void ActivateBindList(CBindList * list,Bits value,bool ev_trigger);
00482     void DeactivateBindList(CBindList * list,bool ev_trigger);
00483     virtual CBind * CreateConfigBind(char *&buf)=0;
00484     virtual CBind * CreateEventBind(SDL_Event * event)=0;
00485 
00486     virtual bool CheckEvent(SDL_Event * event)=0;
00487     virtual const char * ConfigStart(void)=0;
00488     virtual const char * BindStart(void)=0;
00489 
00490 protected:
00491 
00492 };
00493 
00494 #if defined(C_SDL2) /* SDL 2.x */
00495 
00496 /* HACK */
00497 typedef SDL_Scancode SDLKey;
00498 
00499 #else /* !defined(C_SDL2) SDL 1.x */
00500 
00501 #define MAX_SDLKEYS 323
00502 
00503 static bool usescancodes;
00504 static Bit8u scancode_map[MAX_SDLKEYS];
00505 
00506 #define Z SDLK_UNKNOWN
00507 
00508 #if defined (MACOSX)
00509 static SDLKey sdlkey_map[]={
00510     /* Main block printables */
00511     /*00-05*/ Z, SDLK_s, SDLK_d, SDLK_f, SDLK_h, SDLK_g,
00512     /*06-0B*/ SDLK_z, SDLK_x, SDLK_c, SDLK_v, SDLK_WORLD_0, SDLK_b,
00513     /*0C-11*/ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_y, SDLK_t, 
00514     /*12-17*/ SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_6, SDLK_5, 
00515     /*18-1D*/ SDLK_EQUALS, SDLK_9, SDLK_7, SDLK_MINUS, SDLK_8, SDLK_0, 
00516     /*1E-21*/ SDLK_RIGHTBRACKET, SDLK_o, SDLK_u, SDLK_LEFTBRACKET, 
00517     /*22-23*/ SDLK_i, SDLK_p,
00518     /*24-29*/ SDLK_RETURN, SDLK_l, SDLK_j, SDLK_QUOTE, SDLK_k, SDLK_SEMICOLON, 
00519     /*2A-29*/ SDLK_BACKSLASH, SDLK_COMMA, SDLK_SLASH, SDLK_n, SDLK_m, 
00520     /*2F-2F*/ SDLK_PERIOD,
00521 
00522     /* Spaces, controls, modifiers (dosbox uses LMETA only for
00523      * hotkeys, it's not really mapped to an emulated key) */
00524     /*30-33*/ SDLK_TAB, SDLK_SPACE, SDLK_BACKQUOTE, SDLK_BACKSPACE,
00525     /*34-37*/ Z, SDLK_ESCAPE, Z, SDLK_LMETA,
00526     /*38-3B*/ SDLK_LSHIFT, SDLK_CAPSLOCK, SDLK_LALT, SDLK_LCTRL,
00527 
00528     /*3C-40*/ Z, Z, Z, Z, Z,
00529 
00530     /* Keypad (KP_EQUALS not supported, NUMLOCK used on what is CLEAR
00531      * in Mac OS X) */
00532     /*41-46*/ SDLK_KP_PERIOD, Z, SDLK_KP_MULTIPLY, Z, SDLK_KP_PLUS, Z,
00533     /*47-4A*/ SDLK_NUMLOCK /*==SDLK_CLEAR*/, Z, Z, Z,
00534     /*4B-4D*/ SDLK_KP_DIVIDE, SDLK_KP_ENTER, Z,
00535     /*4E-51*/ SDLK_KP_MINUS, Z, Z, SDLK_KP_EQUALS,
00536     /*52-57*/ SDLK_KP0, SDLK_KP1, SDLK_KP2, SDLK_KP3, SDLK_KP4, SDLK_KP5, 
00537     /*58-5C*/ SDLK_KP6, SDLK_KP7, Z, SDLK_KP8, SDLK_KP9, 
00538 
00539     /*5D-5F*/ Z, Z, SDLK_a,
00540     
00541     /* Function keys and cursor blocks (F13 not supported, F14 =>
00542      * PRINT[SCREEN], F15 => SCROLLOCK, F16 => PAUSE, HELP => INSERT) */
00543     /*60-64*/ SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F3, SDLK_F8,
00544     /*65-6A*/ SDLK_F9, Z, SDLK_F11, Z, SDLK_F13, SDLK_PAUSE /*==SDLK_F16*/,
00545     /*6B-70*/ SDLK_PRINT /*==SDLK_F14*/, Z, SDLK_F10, Z, SDLK_F12, Z,
00546     /*71-72*/ SDLK_SCROLLOCK /*==SDLK_F15*/, SDLK_INSERT /*==SDLK_HELP*/, 
00547     /*73-77*/ SDLK_HOME, SDLK_PAGEUP, SDLK_DELETE, SDLK_F4, SDLK_END,
00548     /*78-7C*/ SDLK_F2, SDLK_PAGEDOWN, SDLK_F1, SDLK_LEFT, SDLK_RIGHT,
00549     /*7D-7E*/ SDLK_DOWN, SDLK_UP,
00550 
00551     /*7F-7F*/ Z,
00552 
00553     /* 4 extra keys that don't really exist, but are needed for
00554      * round-trip mapping (dosbox uses RMETA only for hotkeys, it's
00555      * not really mapped to an emulated key) */
00556     SDLK_RMETA, SDLK_RSHIFT, SDLK_RALT, SDLK_RCTRL
00557 };
00558 #define MAX_SCANCODES (0x80+4)
00559 /* Make sure that the table above has the expected size.  This
00560    expression will raise a compiler error if the condition is false.  */
00561 typedef char assert_right_size [MAX_SCANCODES == (sizeof(sdlkey_map)/sizeof(sdlkey_map[0])) ? 1 : -1];
00562 
00563 #else // !MACOSX
00564 
00565 #define MAX_SCANCODES 0xdf
00566 static SDLKey sdlkey_map[MAX_SCANCODES]={SDLK_UNKNOWN,SDLK_ESCAPE,
00567     SDLK_1,SDLK_2,SDLK_3,SDLK_4,SDLK_5,SDLK_6,SDLK_7,SDLK_8,SDLK_9,SDLK_0,
00568     /* 0x0c: */
00569     SDLK_MINUS,SDLK_EQUALS,SDLK_BACKSPACE,SDLK_TAB,
00570     SDLK_q,SDLK_w,SDLK_e,SDLK_r,SDLK_t,SDLK_y,SDLK_u,SDLK_i,SDLK_o,SDLK_p,
00571     SDLK_LEFTBRACKET,SDLK_RIGHTBRACKET,SDLK_RETURN,SDLK_LCTRL,
00572     SDLK_a,SDLK_s,SDLK_d,SDLK_f,SDLK_g,SDLK_h,SDLK_j,SDLK_k,SDLK_l,
00573     SDLK_SEMICOLON,SDLK_QUOTE,SDLK_BACKQUOTE,SDLK_LSHIFT,SDLK_BACKSLASH,
00574     SDLK_z,SDLK_x,SDLK_c,SDLK_v,SDLK_b,SDLK_n,SDLK_m,
00575     /* 0x33: */
00576     SDLK_COMMA,SDLK_PERIOD,SDLK_SLASH,SDLK_RSHIFT,SDLK_KP_MULTIPLY,
00577     SDLK_LALT,SDLK_SPACE,SDLK_CAPSLOCK,
00578     SDLK_F1,SDLK_F2,SDLK_F3,SDLK_F4,SDLK_F5,SDLK_F6,SDLK_F7,SDLK_F8,SDLK_F9,SDLK_F10,
00579     /* 0x45: */
00580     SDLK_NUMLOCK,SDLK_SCROLLOCK,
00581     SDLK_KP7,SDLK_KP8,SDLK_KP9,SDLK_KP_MINUS,SDLK_KP4,SDLK_KP5,SDLK_KP6,SDLK_KP_PLUS,
00582     SDLK_KP1,SDLK_KP2,SDLK_KP3,SDLK_KP0,SDLK_KP_PERIOD,
00583     SDLK_UNKNOWN,SDLK_UNKNOWN,
00584     SDLK_LESS,SDLK_F11,SDLK_F12, Z, Z, Z, Z, Z, Z, Z,
00585     /* 0x60: */
00586     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00587     /* 0x70: */
00588     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00589     /* 0x80: */
00590     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00591     /* 0x90: */
00592     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00593     /* 0xA0: */
00594     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00595     /* 0xB0: */
00596     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00597     /* 0xC0: */
00598     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00599     /* 0xD0: */
00600     Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z//,Z,Z,
00601     /* 0xE0: */
00602     //Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z,
00603     /* 0xF0: */
00604 //  Z,Z,Z,Z, Z,Z,Z,Z, Z,Z,Z,Z, Z,Z//,Z,Z
00605 
00606 };
00607 #endif
00608 
00609 #undef Z
00610 
00611 
00612 SDLKey MapSDLCode(Bitu skey) {
00613 //  LOG_MSG("MapSDLCode %d %X",skey,skey);
00614     if (usescancodes) {
00615         if (skey<MAX_SCANCODES) return sdlkey_map[skey];
00616         else return SDLK_UNKNOWN;
00617     } else return (SDLKey)skey;
00618 }
00619 
00620 Bitu GetKeyCode(SDL_keysym keysym) {
00621 //  LOG_MSG("GetKeyCode %X %X %X",keysym.scancode,keysym.sym,keysym.mod);
00622     if (usescancodes) {
00623         Bitu key=(Bitu)keysym.scancode;
00624 
00625 #if defined (MACOSX)
00626         if ((keysym.scancode == 0) && (keysym.sym == 'a')) key = 0x5f;  // zero value makes the keyboar crazy
00627 #endif
00628 
00629         if (key==0
00630 #if defined (MACOSX)
00631             /* On Mac on US keyboards, scancode 0 is actually the 'a'
00632              * key.  For good measure exclude all printables from this
00633              * condition. */
00634             && (keysym.sym < SDLK_SPACE || keysym.sym > SDLK_WORLD_95)
00635 #endif
00636             ) {
00637             /* try to retrieve key from symbolic key as scancode is zero */
00638             if (keysym.sym<MAX_SDLKEYS) key=scancode_map[(Bitu)keysym.sym];
00639         } 
00640 #if !defined (WIN32) && !defined (MACOSX) && !defined(OS2)
00641         /* Linux adds 8 to all scancodes */
00642         else key-=8;
00643 #endif
00644 #if defined (WIN32)
00645         switch (key) {
00646             case 0x1c:  // ENTER
00647             case 0x1d:  // CONTROL
00648             case 0x35:  // SLASH
00649             case 0x37:  // PRINTSCREEN
00650             case 0x38:  // ALT
00651             case 0x45:  // PAUSE
00652             case 0x47:  // HOME
00653             case 0x48:  // cursor UP
00654             case 0x49:  // PAGE UP
00655             case 0x4b:  // cursor LEFT
00656             case 0x4d:  // cursor RIGHT
00657             case 0x4f:  // END
00658             case 0x50:  // cursor DOWN
00659             case 0x51:  // PAGE DOWN
00660             case 0x52:  // INSERT
00661             case 0x53:  // DELETE
00662                 if (GFX_SDLUsingWinDIB()) key=scancode_map[(Bitu)keysym.sym];
00663                 break;
00664         }
00665 #endif
00666         return key;
00667     } else {
00668 #if defined (WIN32)
00669         /* special handling of 102-key under windows */
00670         if ((keysym.sym==SDLK_BACKSLASH) && (keysym.scancode==0x56)) return (Bitu)SDLK_LESS;
00671         /* special case of the \ _ key on Japanese 106-keyboards. seems to be the same code whether or not you've told Windows it's a 106-key */
00672         /* NTS: SDL source on Win32 maps this key (VK_OEM_102) to SDLK_LESS */
00673         if (isJPkeyboard && (keysym.sym == 0) && (keysym.scancode == 0x73)) return (Bitu)SDLK_WORLD_10; //FIXME: There's no SDLK code for that key! Re-use one of the world keys!
00674         /* another hack, for the Yen \ pipe key on Japanese 106-keyboards.
00675            sym == 0 if English layout, sym == 0x5C if Japanese layout */
00676         if (isJPkeyboard && (keysym.sym == 0 || keysym.sym == 0x5C) && (keysym.scancode == 0x7D)) return (Bitu)SDLK_WORLD_11; //FIXME: There's no SDLK code for that key! Re-use one of the world keys!
00677         /* what is ~ ` on American keyboards is "Hankaku" on Japanese keyboards. Same scan code. */
00678         if (isJPkeyboard && keysym.sym == SDLK_BACKQUOTE) return (int)SDLK_WORLD_12;
00679         /* Muhenkan */
00680         if (isJPkeyboard && keysym.sym == 0 && keysym.scancode == 0x7B) return (int)SDLK_WORLD_13;
00681         /* Henkan/Zenkouho */
00682         if (isJPkeyboard && keysym.sym == 0 && keysym.scancode == 0x79) return (int)SDLK_WORLD_14;
00683         /* Hiragana/Katakana */
00684         if (isJPkeyboard && keysym.sym == 0 && keysym.scancode == 0x70) return (int)SDLK_WORLD_15;
00685 #endif
00686         return (Bitu)keysym.sym;
00687     }
00688 }
00689 
00690 #endif /* !defined(C_SDL2) */
00691 
00692 class CKeyBind;
00693 class CKeyBindGroup;
00694 
00695 class CKeyBind : public CBind {
00696 public:
00697     CKeyBind(CBindList * _list,SDLKey _key) : CBind(_list, CBind::keybind_t) {
00698         key = _key;
00699     }
00700     virtual ~CKeyBind() {}
00701     void BindName(char * buf) {
00702 #if defined(C_SDL2)
00703         sprintf(buf,"Key %s",SDL_GetScancodeName(key));
00704 #else
00705         sprintf(buf,"Key %s",SDL_GetKeyName(MapSDLCode((Bitu)key)));
00706 #endif
00707     }
00708     void ConfigName(char * buf) {
00709 #if defined(C_SDL2)
00710         sprintf(buf,"key %d",key);
00711 #else
00712         sprintf(buf,"key %d",MapSDLCode((Bitu)key));
00713 #endif
00714     }
00715     virtual std::string GetBindMenuText(void) {
00716         const char *s;
00717         std::string r,m;
00718 
00719 #if defined(C_SDL2)
00720         s = SDL_GetScancodeName(key);
00721 #else
00722         s = SDL_GetKeyName(MapSDLCode((Bitu)key));
00723 #endif
00724         if (s != NULL) r = s;
00725 
00726         m = GetModifierText();
00727         if (!m.empty()) r = m + "+" + r;
00728 
00729         return r;
00730     }
00731 public:
00732     SDLKey key;
00733 };
00734 
00735 std::string CEvent::GetBindMenuText(void) {
00736     std::string r;
00737 
00738     if (bindlist.empty())
00739         return std::string();
00740 
00741     for (auto i=bindlist.begin();i!=bindlist.end();i++) {
00742         CBind *b = *i;
00743         if (b == NULL) continue;
00744         if (b->type != CBind::keybind_t) continue;
00745 
00746         CKeyBind *kb = reinterpret_cast<CKeyBind*>(b);
00747         if (kb == NULL) continue;
00748 
00749         r += kb->GetBindMenuText();
00750         break;
00751     }
00752 
00753     return r;
00754 }
00755 
00756 class CKeyBindGroup : public  CBindGroup {
00757 public:
00758     CKeyBindGroup(Bitu _keys) : CBindGroup (){
00759         lists=new CBindList[_keys];
00760         for (Bitu i=0;i<_keys;i++) lists[i].clear();
00761         keys=_keys;
00762         configname="key";
00763     }
00764     virtual ~CKeyBindGroup() { delete[] lists; }
00765     CBind * CreateConfigBind(char *& buf) {
00766         if (strncasecmp(buf,configname,strlen(configname))) return 0;
00767         StripWord(buf);char * num=StripWord(buf);
00768         Bitu code=(Bitu)ConvDecWord(num);
00769 #if defined(C_SDL2)
00770         CBind * bind=CreateKeyBind((SDL_Scancode)code);
00771 #else
00772         if (usescancodes) {
00773             if (code<MAX_SDLKEYS) code=scancode_map[code];
00774             else code=0;
00775         }
00776         CBind * bind=CreateKeyBind((SDLKey)code);
00777 #endif
00778         return bind;
00779     }
00780     CBind * CreateEventBind(SDL_Event * event) {
00781         if (event->type!=SDL_KEYDOWN) return 0;
00782 #if defined(C_SDL2)
00783         return CreateKeyBind(event->key.keysym.scancode);
00784 #else
00785         return CreateKeyBind((SDLKey)GetKeyCode(event->key.keysym));
00786 #endif
00787     };
00788     bool CheckEvent(SDL_Event * event) {
00789         if (event->type!=SDL_KEYDOWN && event->type!=SDL_KEYUP) return false;
00790 #if defined(C_SDL2)
00791         Bitu key = event->key.keysym.scancode;
00792 #else
00793         Bitu key=GetKeyCode(event->key.keysym);
00794         assert(Bitu(event->key.keysym.sym)<keys);
00795 #endif
00796 //      LOG_MSG("key type %i is %x [%x %x]",event->type,key,event->key.keysym.sym,event->key.keysym.scancode);
00797 
00798 #if defined(WIN32) && !defined(C_SDL2)
00799         /* HACK: When setting up the Japanese keyboard layout, I'm seeing some bizarre keyboard handling
00800                  from within Windows when pressing the ~ ` (grave) aka Hankaku key. I know it's not hardware
00801                  because when you switch back to English the key works normally as the tilde/grave key.
00802                  What I'm seeing is that pressing the key only sends the "down" event (even though you're
00803                  not holding the key down). When you press the key again, an "up" event is sent immediately
00804                  followed by a "down" event. This is confusing to the mapper, so we work around it here. */
00805         if (isJPkeyboard && key == SDLK_WORLD_12/*Hankaku*/) {
00806             if (event->type == SDL_KEYDOWN) {
00807                 // send down, then up (right?)
00808                 ActivateBindList(&lists[key], 0x7fff, true);
00809                 DeactivateBindList(&lists[key], true);
00810             }
00811 
00812             return 0; // ignore up event
00813         }
00814 #endif
00815 
00816 #if !defined(C_SDL2)
00817         /* HACK: As requested on the issue tracker, on US keyboards, remap the Windows menu key
00818          *       to the "Ro" key.
00819          *
00820          *       If the user has un-bound the Ro key, then allow the menu key to go through
00821          *       unmodified.
00822          *
00823          * TODO: I understand that later PC-9821 systems (post Windows 95, prior to the platform's
00824          *       demise) actually did have Windows and Windows Menu keys.
00825          *
00826          *       I also understand from "Undocumented PC-98" that the actual keyboards for backwards
00827          *       compat reasons will not send these key codes unless a byte is sent to the keyboard
00828          *       on Windows 95 startup to tell the keyboard that it can send those keys.
00829          *
00830          *       This would explain why if you boot a PC-9821 system into Windows 95 "Safe mode"
00831          *       the Windows key does not work.
00832          *
00833          *       So later on, this remap should disable itself IF that byte is sent to signal
00834          *       Windows 95 is running and the Windows keys should be enabled. */
00835         if (IS_PC98_ARCH && host_keyboard_layout != DKM_JPN && key == SDLK_MENU) {
00836             CEvent *x = get_mapper_event_by_name("key_jp_ro");
00837             bool RoMenuRemap = false;
00838 
00839             if (x != NULL) {
00840                 if (!x->bindlist.empty()) {
00841                     RoMenuRemap = true;
00842 
00843                     /* but, if the Ro key has been bound to Menu, do not remap */
00844                     auto &i = x->bindlist.front();
00845                     if (i->type == CBind::keybind_t) {
00846                         auto ik = reinterpret_cast<CKeyBind*>(i);
00847                         RoMenuRemap = false;
00848                         if (ik->key == SDLK_JP_RO)
00849                             RoMenuRemap = true;
00850                     }
00851                 }
00852             }
00853 
00854             if (RoMenuRemap) key = SDLK_JP_RO;
00855         }
00856 #endif
00857 
00858         if (event->type==SDL_KEYDOWN) ActivateBindList(&lists[key],0x7fff,true);
00859         else DeactivateBindList(&lists[key],true);
00860         return 0;
00861     }
00862     CBind * CreateKeyBind(SDLKey _key) {
00863 #if !defined(C_SDL2)
00864         if (!usescancodes) assert((Bitu)_key<keys);
00865 #endif
00866         return new CKeyBind(&lists[(Bitu)_key],_key);
00867     }
00868 private:
00869     const char * ConfigStart(void) {
00870         return configname;
00871     }
00872     const char * BindStart(void) {
00873         return "Key";
00874     }
00875 protected:
00876     const char * configname;
00877     CBindList * lists;
00878     Bitu keys;
00879 };
00880 
00881 #define MAX_VJOY_BUTTONS 8
00882 #define MAX_VJOY_AXES 8
00883 
00884 static struct {
00885     bool button_pressed[MAX_VJOY_BUTTONS];
00886     Bit16s axis_pos[MAX_VJOY_AXES];
00887     bool hat_pressed[16];
00888 } virtual_joysticks[2];
00889 
00890 
00891 class CJAxisBind;
00892 class CJButtonBind;
00893 class CJHatBind;
00894 
00895 class CJAxisBind : public CBind {
00896 public:
00897     CJAxisBind(CBindList * _list,CBindGroup * _group,Bitu _axis,bool _positive) : CBind(_list){
00898         group = _group;
00899         axis = _axis;
00900         positive = _positive;
00901     }
00902     virtual ~CJAxisBind() {}
00903     void ConfigName(char * buf) {
00904         sprintf(buf,"%s axis %d %d",group->ConfigStart(),(int)axis,positive ? 1 : 0);
00905     }
00906     void BindName(char * buf) {
00907         sprintf(buf,"%s Axis %d%s",group->BindStart(),(int)axis,positive ? "+" : "-");
00908     }
00909 protected:
00910     CBindGroup * group;
00911     Bitu axis;
00912     bool positive;
00913 };
00914 
00915 class CJButtonBind : public CBind {
00916 public:
00917     CJButtonBind(CBindList * _list,CBindGroup * _group,Bitu _button) : CBind(_list) {
00918         group = _group;
00919         button=_button;
00920     }
00921     virtual ~CJButtonBind() {}
00922     void ConfigName(char * buf) {
00923         sprintf(buf,"%s button %d",group->ConfigStart(),(int)button);
00924     }
00925     void BindName(char * buf) {
00926         sprintf(buf,"%s Button %d",group->BindStart(),(int)button);
00927     }
00928 protected:
00929     CBindGroup * group;
00930     Bitu button;
00931 };
00932 
00933 class CJHatBind : public CBind {
00934 public:
00935     CJHatBind(CBindList * _list,CBindGroup * _group,Bitu _hat,Bit8u _dir) : CBind(_list) {
00936         group = _group;
00937         hat   = _hat;
00938         dir   = _dir;
00939         /* allow only one hat position */
00940         if (dir&SDL_HAT_UP) dir=SDL_HAT_UP;
00941         else if (dir&SDL_HAT_RIGHT) dir=SDL_HAT_RIGHT;
00942         else if (dir&SDL_HAT_DOWN) dir=SDL_HAT_DOWN;
00943         else if (dir&SDL_HAT_LEFT) dir=SDL_HAT_LEFT;
00944         else E_Exit("MAPPER:JOYSTICK:Invalid hat position");
00945     }
00946     virtual ~CJHatBind() {}
00947     void ConfigName(char * buf) {
00948         sprintf(buf,"%s hat %d %d",group->ConfigStart(),(int)hat,(int)dir);
00949     }
00950     void BindName(char * buf) {
00951         sprintf(buf,"%s Hat %d %s",group->BindStart(),(int)hat,(dir==SDL_HAT_UP)?"up":
00952                                                         ((dir==SDL_HAT_RIGHT)?"right":
00953                                                         ((dir==SDL_HAT_DOWN)?"down":"left")));
00954     }
00955 protected:
00956     CBindGroup * group;
00957     Bitu hat;
00958     Bit8u dir;
00959 };
00960 
00961 bool autofire = false;
00962 
00963 class CStickBindGroup : public  CBindGroup {
00964 public:
00965     CStickBindGroup(Bitu _stick,Bitu _emustick,bool _dummy=false) : CBindGroup (){
00966         stick=_stick;       // the number of the physical device (SDL numbering|)
00967         emustick=_emustick; // the number of the emulated device
00968         sprintf(configname,"stick_%d",(int)emustick);
00969 
00970         sdl_joystick=NULL;
00971         axes=0; buttons=0; hats=0;
00972         button_wrap=0;
00973         button_cap=0; axes_cap=0; hats_cap=0;
00974         emulated_buttons=0; emulated_axes=0; emulated_hats=0;
00975         pos_axis_lists = neg_axis_lists = NULL; /* <- Initialize the pointers to NULL. The C++ compiler won't do it for us. */
00976         button_lists = hat_lists = NULL;
00977 
00978         is_dummy=_dummy;
00979         if (_dummy) return;
00980 
00981         // initialize binding lists and position data
00982         pos_axis_lists=new CBindList[MAXAXIS];
00983         neg_axis_lists=new CBindList[MAXAXIS];
00984         button_lists=new CBindList[MAXBUTTON];
00985         hat_lists=new CBindList[4];
00986         Bitu i;
00987         for (i=0; i<MAXBUTTON; i++) {
00988             button_autofire[i]=0;
00989             old_button_state[i]=0;
00990         }
00991         for(i=0;i<16;i++) old_hat_state[i]=0;
00992         for (i=0; i<MAXAXIS; i++) {
00993             old_pos_axis_state[i]=false;
00994             old_neg_axis_state[i]=false;
00995         }
00996 
00997         // initialize emulated joystick state
00998         emulated_axes=2;
00999         emulated_buttons=2;
01000         emulated_hats=0;
01001         JOYSTICK_Enable(emustick,true);
01002 
01003         sdl_joystick=SDL_JoystickOpen(_stick);
01004         if (sdl_joystick==NULL) {
01005             button_wrap=emulated_buttons;
01006             return;
01007         }
01008 
01009         axes=(Bitu)SDL_JoystickNumAxes(sdl_joystick);
01010         if (axes > MAXAXIS) axes = MAXAXIS;
01011         axes_cap=emulated_axes;
01012         if (axes_cap>axes) axes_cap=axes;
01013 
01014         hats=(Bitu)SDL_JoystickNumHats(sdl_joystick);
01015         if (hats > MAXHAT) hats = MAXHAT;
01016         hats_cap=emulated_hats;
01017         if (hats_cap>hats) hats_cap=hats;
01018 
01019         buttons=(Bitu)SDL_JoystickNumButtons(sdl_joystick);
01020         button_wrap=buttons;
01021         button_cap=buttons;
01022         if (button_wrapping_enabled) {
01023             button_wrap=emulated_buttons;
01024             if (buttons>MAXBUTTON_CAP) button_cap = MAXBUTTON_CAP;
01025         }
01026         if (button_wrap > MAXBUTTON) button_wrap = MAXBUTTON;
01027 
01028 #if defined(C_SDL2)
01029         LOG_MSG("Using joystick %s with %d axes, %d buttons and %d hat(s)",SDL_JoystickNameForIndex(stick),(int)axes,(int)buttons,(int)hats);
01030 #else
01031         LOG_MSG("Using joystick %s with %d axes, %d buttons and %d hat(s)",SDL_JoystickName(stick),(int)axes,(int)buttons,(int)hats);
01032 #endif
01033     }
01034     virtual ~CStickBindGroup() {
01035         SDL_JoystickClose(sdl_joystick);
01036         if (pos_axis_lists != NULL) delete[] pos_axis_lists;
01037         if (neg_axis_lists != NULL) delete[] neg_axis_lists;
01038         if (button_lists != NULL) delete[] button_lists;
01039         if (hat_lists != NULL) delete[] hat_lists;
01040     }
01041 
01042     CBind * CreateConfigBind(char *& buf) {
01043         if (strncasecmp(configname,buf,strlen(configname))) return 0;
01044         StripWord(buf);char * type=StripWord(buf);
01045         CBind * bind=0;
01046         if (!strcasecmp(type,"axis")) {
01047             Bitu ax=(Bitu)ConvDecWord(StripWord(buf));
01048             bool pos=ConvDecWord(StripWord(buf)) > 0;
01049             bind=CreateAxisBind(ax,pos);
01050         } else if (!strcasecmp(type,"button")) {
01051             Bitu but=(Bitu)ConvDecWord(StripWord(buf));           
01052             bind=CreateButtonBind(but);
01053         } else if (!strcasecmp(type,"hat")) {
01054             Bitu hat=(Bitu)ConvDecWord(StripWord(buf));           
01055             Bit8u dir=(Bit8u)ConvDecWord(StripWord(buf));           
01056             bind=CreateHatBind(hat,dir);
01057         }
01058         return bind;
01059     }
01060     CBind * CreateEventBind(SDL_Event * event) {
01061         if (event->type==SDL_JOYAXISMOTION) {
01062             if ((unsigned int)event->jaxis.which!=(unsigned int)stick) return 0;
01063 #if defined (REDUCE_JOYSTICK_POLLING)
01064             if (event->jaxis.axis>=axes) return 0;
01065 #endif
01066             if (abs(event->jaxis.value)<25000) return 0;
01067             return CreateAxisBind(event->jaxis.axis,event->jaxis.value>0);
01068         } else if (event->type==SDL_JOYBUTTONDOWN) {
01069             if (event->button.which!=stick) return 0;
01070 #if defined (REDUCE_JOYSTICK_POLLING)
01071             return CreateButtonBind(event->jbutton.button%button_wrap);
01072 #else
01073             return CreateButtonBind(event->jbutton.button);
01074 #endif
01075         } else if (event->type==SDL_JOYHATMOTION) {
01076             if ((unsigned int)event->jhat.which!=(unsigned int)stick) return 0;
01077             if (event->jhat.value==0) return 0;
01078             if (event->jhat.value>(SDL_HAT_UP|SDL_HAT_RIGHT|SDL_HAT_DOWN|SDL_HAT_LEFT)) return 0;
01079             return CreateHatBind(event->jhat.hat,event->jhat.value);
01080         } else return 0;
01081     }
01082 
01083     virtual bool CheckEvent(SDL_Event * event) {
01084         SDL_JoyAxisEvent * jaxis = NULL;
01085         SDL_JoyButtonEvent * jbutton = NULL;
01086         Bitu but = 0;
01087 
01088         switch(event->type) {
01089             case SDL_JOYAXISMOTION:
01090                 jaxis = &event->jaxis;
01091                 if((unsigned int)jaxis->which == (unsigned int)stick) {
01092                     if(jaxis->axis == 0)
01093                         JOYSTICK_Move_X(emustick,(float)(jaxis->value/32768.0));
01094                     else if(jaxis->axis == 1)
01095                         JOYSTICK_Move_Y(emustick,(float)(jaxis->value/32768.0));
01096                 }
01097                 break;
01098             case SDL_JOYBUTTONDOWN:
01099             case SDL_JOYBUTTONUP:
01100                 if (emulated_buttons != 0) {
01101                     jbutton = &event->jbutton;
01102                     bool state;
01103                     state=jbutton->type==SDL_JOYBUTTONDOWN;
01104                     but = jbutton->button % emulated_buttons;
01105                     if ((unsigned int)jbutton->which == (unsigned int)stick) {
01106                         JOYSTICK_Button(emustick, but, state);
01107                     }
01108                 }
01109                 break;
01110         }
01111         return false;
01112     }
01113 
01114     virtual void UpdateJoystick() {
01115         if (is_dummy) return;
01116         /* query SDL joystick and activate bindings */
01117         ActivateJoystickBoundEvents();
01118 
01119         bool button_pressed[MAXBUTTON];
01120         Bitu i;
01121         for (i=0; i<MAXBUTTON; i++) button_pressed[i]=false;
01122         for (i=0; i<MAX_VJOY_BUTTONS; i++) {
01123             if (virtual_joysticks[emustick].button_pressed[i])
01124                 button_pressed[i % button_wrap]=true;
01125         }
01126         for (i=0; i<emulated_buttons; i++) {
01127             if (autofire && (button_pressed[i]))
01128                 JOYSTICK_Button(emustick,i,(++button_autofire[i])&1);
01129             else
01130                 JOYSTICK_Button(emustick,i,button_pressed[i]);
01131         }
01132 
01133         JOYSTICK_Move_X(emustick,((float)virtual_joysticks[emustick].axis_pos[0])/32768.0f);
01134         JOYSTICK_Move_Y(emustick,((float)virtual_joysticks[emustick].axis_pos[1])/32768.0f);
01135     }
01136 
01137     void ActivateJoystickBoundEvents() {
01138         if (GCC_UNLIKELY(sdl_joystick==NULL)) return;
01139 
01140         Bitu i;
01141 
01142         bool button_pressed[MAXBUTTON];
01143         for (i=0; i<MAXBUTTON; i++) button_pressed[i]=false;
01144         /* read button states */
01145         for (i=0; i<button_cap; i++) {
01146             if (SDL_JoystickGetButton(sdl_joystick,i))
01147                 button_pressed[i % button_wrap]=true;
01148         }
01149         for (i=0; i<button_wrap; i++) {
01150             /* activate binding if button state has changed */
01151             if (button_pressed[i]!=old_button_state[i]) {
01152                 if (button_pressed[i]) ActivateBindList(&button_lists[i],32767,true);
01153                 else DeactivateBindList(&button_lists[i],true);
01154                 old_button_state[i]=button_pressed[i];
01155             }
01156         }
01157 
01158         for (i=0; i<axes; i++) {
01159             Sint16 caxis_pos=SDL_JoystickGetAxis(sdl_joystick,i);
01160             /* activate bindings for joystick position */
01161             if (caxis_pos>1) {
01162                 if (old_neg_axis_state[i]) {
01163                     DeactivateBindList(&neg_axis_lists[i],false);
01164                     old_neg_axis_state[i] = false;
01165                 }
01166                 ActivateBindList(&pos_axis_lists[i],caxis_pos,false);
01167                 old_pos_axis_state[i] = true;
01168             } else if (caxis_pos<-1) {
01169                 if (old_pos_axis_state[i]) {
01170                     DeactivateBindList(&pos_axis_lists[i],false);
01171                     old_pos_axis_state[i] = false;
01172                 }
01173                 if (caxis_pos!=-32768) caxis_pos=(Sint16)abs(caxis_pos);
01174                 else caxis_pos=32767;
01175                 ActivateBindList(&neg_axis_lists[i],caxis_pos,false);
01176                 old_neg_axis_state[i] = true;
01177             } else {
01178                 /* center */
01179                 if (old_pos_axis_state[i]) {
01180                     DeactivateBindList(&pos_axis_lists[i],false);
01181                     old_pos_axis_state[i] = false;
01182                 }
01183                 if (old_neg_axis_state[i]) {
01184                     DeactivateBindList(&neg_axis_lists[i],false);
01185                     old_neg_axis_state[i] = false;
01186                 }
01187             }
01188         }
01189 
01190         for (i=0; i<hats; i++) {
01191             Uint8 chat_state=SDL_JoystickGetHat(sdl_joystick,i);
01192 
01193             /* activate binding if hat state has changed */
01194             if ((chat_state & SDL_HAT_UP) != (old_hat_state[i] & SDL_HAT_UP)) {
01195                 if (chat_state & SDL_HAT_UP) ActivateBindList(&hat_lists[(i<<2)+0],32767,true);
01196                 else DeactivateBindList(&hat_lists[(i<<2)+0],true);
01197             }
01198             if ((chat_state & SDL_HAT_RIGHT) != (old_hat_state[i] & SDL_HAT_RIGHT)) {
01199                 if (chat_state & SDL_HAT_RIGHT) ActivateBindList(&hat_lists[(i<<2)+1],32767,true);
01200                 else DeactivateBindList(&hat_lists[(i<<2)+1],true);
01201             }
01202             if ((chat_state & SDL_HAT_DOWN) != (old_hat_state[i] & SDL_HAT_DOWN)) {
01203                 if (chat_state & SDL_HAT_DOWN) ActivateBindList(&hat_lists[(i<<2)+2],32767,true);
01204                 else DeactivateBindList(&hat_lists[(i<<2)+2],true);
01205             }
01206             if ((chat_state & SDL_HAT_LEFT) != (old_hat_state[i] & SDL_HAT_LEFT)) {
01207                 if (chat_state & SDL_HAT_LEFT) ActivateBindList(&hat_lists[(i<<2)+3],32767,true);
01208                 else DeactivateBindList(&hat_lists[(i<<2)+3],true);
01209             }
01210             old_hat_state[i]=chat_state;
01211         }
01212     }
01213 
01214 private:
01215     CBind * CreateAxisBind(Bitu axis,bool positive) {
01216         if (axis<axes) {
01217             if (positive) return new CJAxisBind(&pos_axis_lists[axis],this,axis,positive);
01218             else return new CJAxisBind(&neg_axis_lists[axis],this,axis,positive);
01219         }
01220         return NULL;
01221     }
01222     CBind * CreateButtonBind(Bitu button) {
01223         if (button<button_wrap) 
01224             return new CJButtonBind(&button_lists[button],this,button);
01225         return NULL;
01226     }
01227     CBind * CreateHatBind(Bitu hat,Bit8u value) {
01228         Bitu hat_dir;
01229         if (value&SDL_HAT_UP) hat_dir=0;
01230         else if (value&SDL_HAT_RIGHT) hat_dir=1;
01231         else if (value&SDL_HAT_DOWN) hat_dir=2;
01232         else if (value&SDL_HAT_LEFT) hat_dir=3;
01233         else return NULL;
01234         return new CJHatBind(&hat_lists[(hat<<2)+hat_dir],this,hat,value);
01235     }
01236     const char * ConfigStart(void) {
01237         return configname;
01238     }
01239     const char * BindStart(void) {
01240 #if defined(C_SDL2)
01241         if (sdl_joystick!=NULL) return SDL_JoystickNameForIndex(stick);
01242 #else
01243         if (sdl_joystick!=NULL) return SDL_JoystickName(stick);
01244 #endif
01245         else return "[missing joystick]";
01246     }
01247 
01248 protected:
01249     CBindList * pos_axis_lists;
01250     CBindList * neg_axis_lists;
01251     CBindList * button_lists;
01252     CBindList * hat_lists;
01253     Bitu stick,emustick,axes,buttons,hats,emulated_axes,emulated_buttons,emulated_hats;
01254     Bitu button_wrap,button_cap,axes_cap,hats_cap;
01255     SDL_Joystick * sdl_joystick;
01256     char configname[10];
01257     Bitu button_autofire[MAXBUTTON];
01258     bool old_button_state[MAXBUTTON];
01259     bool old_pos_axis_state[MAXAXIS];
01260     bool old_neg_axis_state[MAXAXIS];
01261     Uint8 old_hat_state[16];
01262     bool is_dummy;
01263 };
01264 
01265 class C4AxisBindGroup : public  CStickBindGroup {
01266 public:
01267     C4AxisBindGroup(Bitu _stick,Bitu _emustick) : CStickBindGroup (_stick,_emustick){
01268         emulated_axes=4;
01269         emulated_buttons=4;
01270         if (button_wrapping_enabled) button_wrap=emulated_buttons;
01271 
01272         axes_cap=emulated_axes;
01273         if (axes_cap>axes) axes_cap=axes;
01274         hats_cap=emulated_hats;
01275         if (hats_cap>hats) hats_cap=hats;
01276 
01277         JOYSTICK_Enable(1,true);
01278     }
01279     virtual ~C4AxisBindGroup() {}
01280 
01281     bool CheckEvent(SDL_Event * event) {
01282         SDL_JoyAxisEvent * jaxis = NULL;
01283         SDL_JoyButtonEvent * jbutton = NULL;
01284         Bitu but = 0;
01285 
01286         switch(event->type) {
01287             case SDL_JOYAXISMOTION:
01288                 jaxis = &event->jaxis;
01289                 if((unsigned int)jaxis->which == (unsigned int)stick && jaxis->axis < 4) {
01290                     if(jaxis->axis & 1)
01291                         JOYSTICK_Move_Y(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0));
01292                     else
01293                         JOYSTICK_Move_X(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0));
01294                 }
01295                 break;
01296             case SDL_JOYBUTTONDOWN:
01297             case SDL_JOYBUTTONUP:
01298                 jbutton = &event->jbutton;
01299                 bool state;
01300                 state=jbutton->type==SDL_JOYBUTTONDOWN;
01301                 but = jbutton->button % emulated_buttons;
01302                 if ((unsigned int)jbutton->which == (unsigned int)stick) {
01303                     JOYSTICK_Button((but >> 1),(but & 1),state);
01304                 }
01305                 break;
01306         }
01307         return false;
01308     }
01309 
01310     virtual void UpdateJoystick() {
01311         /* query SDL joystick and activate bindings */
01312         ActivateJoystickBoundEvents();
01313 
01314         bool button_pressed[MAXBUTTON];
01315         Bitu i;
01316         for (i=0; i<MAXBUTTON; i++) button_pressed[i]=false;
01317         for (i=0; i<MAX_VJOY_BUTTONS; i++) {
01318             if (virtual_joysticks[0].button_pressed[i])
01319                 button_pressed[i % button_wrap]=true;
01320             
01321         }
01322         for (i=0; i<emulated_buttons; i++) {
01323             if (autofire && (button_pressed[i]))
01324                 JOYSTICK_Button(i>>1,i&1,(++button_autofire[i])&1);
01325             else
01326                 JOYSTICK_Button(i>>1,i&1,button_pressed[i]);
01327         }
01328 
01329         JOYSTICK_Move_X(0,((float)virtual_joysticks[0].axis_pos[0])/32768.0f);
01330         JOYSTICK_Move_Y(0,((float)virtual_joysticks[0].axis_pos[1])/32768.0f);
01331         JOYSTICK_Move_X(1,((float)virtual_joysticks[0].axis_pos[2])/32768.0f);
01332         JOYSTICK_Move_Y(1,((float)virtual_joysticks[0].axis_pos[3])/32768.0f);
01333     }
01334 };
01335 
01336 class CFCSBindGroup : public  CStickBindGroup {
01337 public:
01338     CFCSBindGroup(Bitu _stick,Bitu _emustick) : CStickBindGroup (_stick,_emustick){
01339         emulated_axes=4;
01340         emulated_buttons=4;
01341         old_hat_position=0;
01342         emulated_hats=1;
01343         if (button_wrapping_enabled) button_wrap=emulated_buttons;
01344 
01345         axes_cap=emulated_axes;
01346         if (axes_cap>axes) axes_cap=axes;
01347         hats_cap=emulated_hats;
01348         if (hats_cap>hats) hats_cap=hats;
01349 
01350         JOYSTICK_Enable(1,true);
01351         JOYSTICK_Move_Y(1,1.0);
01352     }
01353     virtual ~CFCSBindGroup() {}
01354 
01355     bool CheckEvent(SDL_Event * event) {
01356         SDL_JoyAxisEvent * jaxis = NULL;
01357         SDL_JoyButtonEvent * jbutton = NULL;
01358         SDL_JoyHatEvent * jhat = NULL;
01359         Bitu but = 0;
01360 
01361         switch(event->type) {
01362             case SDL_JOYAXISMOTION:
01363                 jaxis = &event->jaxis;
01364                 if((unsigned int)jaxis->which == (unsigned int)stick) {
01365                     if(jaxis->axis == 0)
01366                         JOYSTICK_Move_X(0,(float)(jaxis->value/32768.0));
01367                     else if(jaxis->axis == 1)
01368                         JOYSTICK_Move_Y(0,(float)(jaxis->value/32768.0));
01369                     else if(jaxis->axis == 2)
01370                         JOYSTICK_Move_X(1,(float)(jaxis->value/32768.0));
01371                 }
01372                 break;
01373             case SDL_JOYHATMOTION:
01374                 jhat = &event->jhat;
01375                 if((unsigned int)jhat->which == (unsigned int)stick) DecodeHatPosition(jhat->value);
01376                 break;
01377             case SDL_JOYBUTTONDOWN:
01378             case SDL_JOYBUTTONUP:
01379                 jbutton = &event->jbutton;
01380                 bool state;
01381                 state=jbutton->type==SDL_JOYBUTTONDOWN;
01382                 but = jbutton->button % emulated_buttons;
01383                 if ((unsigned int)jbutton->which == (unsigned int)stick) {
01384                         JOYSTICK_Button((but >> 1),(but & 1),state);
01385                 }
01386                 break;
01387         }
01388         return false;
01389     }
01390 
01391     virtual void UpdateJoystick() {
01392         /* query SDL joystick and activate bindings */
01393         ActivateJoystickBoundEvents();
01394 
01395         bool button_pressed[MAXBUTTON];
01396         Bitu i;
01397         for (i=0; i<MAXBUTTON; i++) button_pressed[i]=false;
01398         for (i=0; i<MAX_VJOY_BUTTONS; i++) {
01399             if (virtual_joysticks[0].button_pressed[i])
01400                 button_pressed[i % button_wrap]=true;
01401             
01402         }
01403         for (i=0; i<emulated_buttons; i++) {
01404             if (autofire && (button_pressed[i]))
01405                 JOYSTICK_Button(i>>1,i&1,(++button_autofire[i])&1);
01406             else
01407                 JOYSTICK_Button(i>>1,i&1,button_pressed[i]);
01408         }
01409 
01410         JOYSTICK_Move_X(0,((float)virtual_joysticks[0].axis_pos[0])/32768.0f);
01411         JOYSTICK_Move_Y(0,((float)virtual_joysticks[0].axis_pos[1])/32768.0f);
01412         JOYSTICK_Move_X(1,((float)virtual_joysticks[0].axis_pos[2])/32768.0f);
01413 
01414         Uint8 hat_pos=0;
01415         if (virtual_joysticks[0].hat_pressed[0]) hat_pos|=SDL_HAT_UP;
01416         else if (virtual_joysticks[0].hat_pressed[2]) hat_pos|=SDL_HAT_DOWN;
01417         if (virtual_joysticks[0].hat_pressed[3]) hat_pos|=SDL_HAT_LEFT;
01418         else if (virtual_joysticks[0].hat_pressed[1]) hat_pos|=SDL_HAT_RIGHT;
01419 
01420         if (hat_pos!=old_hat_position) {
01421             DecodeHatPosition(hat_pos);
01422             old_hat_position=hat_pos;
01423         }
01424     }
01425 
01426 private:
01427     Uint8 old_hat_position;
01428 
01429     void DecodeHatPosition(Uint8 hat_pos) {
01430         switch(hat_pos) {
01431             case SDL_HAT_CENTERED:
01432                 JOYSTICK_Move_Y(1,1.0);
01433                 break;
01434             case SDL_HAT_UP:
01435                 JOYSTICK_Move_Y(1,-1.0);
01436                 break;
01437             case SDL_HAT_RIGHT:
01438                 JOYSTICK_Move_Y(1,-0.5);
01439                 break;
01440             case SDL_HAT_DOWN:
01441                 JOYSTICK_Move_Y(1,0.0);
01442                 break;
01443             case SDL_HAT_LEFT:
01444                 JOYSTICK_Move_Y(1,0.5);
01445                 break;
01446             case SDL_HAT_LEFTUP:
01447                 if(JOYSTICK_GetMove_Y(1) < 0)
01448                     JOYSTICK_Move_Y(1,0.5);
01449                 else
01450                     JOYSTICK_Move_Y(1,-1.0);
01451                 break;
01452             case SDL_HAT_RIGHTUP:
01453                 if(JOYSTICK_GetMove_Y(1) < -0.7)
01454                     JOYSTICK_Move_Y(1,-0.5);
01455                 else
01456                     JOYSTICK_Move_Y(1,-1.0);
01457                 break;
01458             case SDL_HAT_RIGHTDOWN:
01459                 if(JOYSTICK_GetMove_Y(1) < -0.2)
01460                     JOYSTICK_Move_Y(1,0.0);
01461                 else
01462                     JOYSTICK_Move_Y(1,-0.5);
01463                 break;
01464             case SDL_HAT_LEFTDOWN:
01465                 if(JOYSTICK_GetMove_Y(1) > 0.2)
01466                     JOYSTICK_Move_Y(1,0.0);
01467                 else
01468                     JOYSTICK_Move_Y(1,0.5);
01469                 break;
01470         }
01471     }
01472 };
01473 
01474 class CCHBindGroup : public  CStickBindGroup {
01475 public:
01476     CCHBindGroup(Bitu _stick,Bitu _emustick) : CStickBindGroup (_stick,_emustick){
01477         emulated_axes=4;
01478         emulated_buttons=6;
01479         emulated_hats=1;
01480         if (button_wrapping_enabled) button_wrap=emulated_buttons;
01481 
01482         axes_cap=emulated_axes;
01483         if (axes_cap>axes) axes_cap=axes;
01484         hats_cap=emulated_hats;
01485         if (hats_cap>hats) hats_cap=hats;
01486 
01487         JOYSTICK_Enable(1,true);
01488         button_state=0;
01489     }
01490     virtual ~CCHBindGroup() {}
01491 
01492     bool CheckEvent(SDL_Event * event) {
01493         SDL_JoyAxisEvent * jaxis = NULL;
01494         SDL_JoyButtonEvent * jbutton = NULL;
01495         SDL_JoyHatEvent * jhat = NULL;
01496         Bitu but = 0;
01497         static unsigned const button_magic[6]={0x02,0x04,0x10,0x100,0x20,0x200};
01498         static unsigned const hat_magic[2][5]={{0x8888,0x8000,0x800,0x80,0x08},
01499                                {0x5440,0x4000,0x400,0x40,0x1000}};
01500         switch(event->type) {
01501             case SDL_JOYAXISMOTION:
01502                 jaxis = &event->jaxis;
01503                 if((unsigned int)jaxis->which == (unsigned int)stick && jaxis->axis < 4) {
01504                     if(jaxis->axis & 1)
01505                         JOYSTICK_Move_Y(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0));
01506                     else
01507                         JOYSTICK_Move_X(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0));
01508                 }
01509                 break;
01510             case SDL_JOYHATMOTION:
01511                 jhat = &event->jhat;
01512                 if((unsigned int)jhat->which == (unsigned int)stick && jhat->hat < 2) {
01513                     if(jhat->value == SDL_HAT_CENTERED)
01514                         button_state&=~hat_magic[jhat->hat][0];
01515                     if(jhat->value & SDL_HAT_UP)
01516                         button_state|=hat_magic[jhat->hat][1];
01517                     if(jhat->value & SDL_HAT_RIGHT)
01518                         button_state|=hat_magic[jhat->hat][2];
01519                     if(jhat->value & SDL_HAT_DOWN)
01520                         button_state|=hat_magic[jhat->hat][3];
01521                     if(jhat->value & SDL_HAT_LEFT)
01522                         button_state|=hat_magic[jhat->hat][4];
01523                 }
01524                 break;
01525             case SDL_JOYBUTTONDOWN:
01526                 jbutton = &event->jbutton;
01527                 but = jbutton->button % emulated_buttons;
01528                 if ((unsigned int)jbutton->which == (unsigned int)stick)
01529                     button_state|=button_magic[but];
01530                 break;
01531             case SDL_JOYBUTTONUP:
01532                 jbutton = &event->jbutton;
01533                 but = jbutton->button % emulated_buttons;
01534                 if ((unsigned int)jbutton->which == (unsigned int)stick)
01535                     button_state&=~button_magic[but];
01536                 break;
01537         }
01538 
01539         unsigned i;
01540         Bit16u j;
01541         j=button_state;
01542         for(i=0;i<16;i++) if (j & 1) break; else j>>=1;
01543         JOYSTICK_Button(0,0,i&1);
01544         JOYSTICK_Button(0,1,(i>>1)&1);
01545         JOYSTICK_Button(1,0,(i>>2)&1);
01546         JOYSTICK_Button(1,1,(i>>3)&1);
01547         return false;
01548     }
01549 
01550     void UpdateJoystick() {
01551         static unsigned const button_priority[6]={7,11,13,14,5,6};
01552         static unsigned const hat_priority[2][4]={{0,1,2,3},{8,9,10,12}};
01553 
01554         /* query SDL joystick and activate bindings */
01555         ActivateJoystickBoundEvents();
01556 
01557         JOYSTICK_Move_X(0,((float)virtual_joysticks[0].axis_pos[0])/32768.0f);
01558         JOYSTICK_Move_Y(0,((float)virtual_joysticks[0].axis_pos[1])/32768.0f);
01559         JOYSTICK_Move_X(1,((float)virtual_joysticks[0].axis_pos[2])/32768.0f);
01560         JOYSTICK_Move_Y(1,((float)virtual_joysticks[0].axis_pos[3])/32768.0f);
01561 
01562         Bitu bt_state=15;
01563 
01564         Bitu i;
01565         for (i=0; i<(hats<2?hats:2); i++) {
01566             Uint8 hat_pos=0;
01567             if (virtual_joysticks[0].hat_pressed[(i<<2)+0]) hat_pos|=SDL_HAT_UP;
01568             else if (virtual_joysticks[0].hat_pressed[(i<<2)+2]) hat_pos|=SDL_HAT_DOWN;
01569             if (virtual_joysticks[0].hat_pressed[(i<<2)+3]) hat_pos|=SDL_HAT_LEFT;
01570             else if (virtual_joysticks[0].hat_pressed[(i<<2)+1]) hat_pos|=SDL_HAT_RIGHT;
01571 
01572             if (hat_pos & SDL_HAT_UP)
01573                 if (bt_state>hat_priority[i][0]) bt_state=hat_priority[i][0];
01574             if (hat_pos & SDL_HAT_DOWN)
01575                 if (bt_state>hat_priority[i][1]) bt_state=hat_priority[i][1];
01576             if (hat_pos & SDL_HAT_RIGHT)
01577                 if (bt_state>hat_priority[i][2]) bt_state=hat_priority[i][2];
01578             if (hat_pos & SDL_HAT_LEFT)
01579                 if (bt_state>hat_priority[i][3]) bt_state=hat_priority[i][3];
01580         }
01581 
01582         bool button_pressed[MAXBUTTON];
01583         for (i=0; i<MAXBUTTON; i++) button_pressed[i]=false;
01584         for (i=0; i<MAX_VJOY_BUTTONS; i++) {
01585             if (virtual_joysticks[0].button_pressed[i])
01586                 button_pressed[i % button_wrap]=true;
01587             
01588         }
01589         for (i=0; i<6; i++) {
01590             if ((button_pressed[i]) && (bt_state>button_priority[i]))
01591                 bt_state=button_priority[i];
01592         }
01593 
01594         if (bt_state>15) bt_state=15;
01595         JOYSTICK_Button(0,0,(bt_state&8)==0);
01596         JOYSTICK_Button(0,1,(bt_state&4)==0);
01597         JOYSTICK_Button(1,0,(bt_state&2)==0);
01598         JOYSTICK_Button(1,1,(bt_state&1)==0);
01599     }
01600 
01601 protected:
01602     Bit16u button_state;
01603 };
01604 
01605 static struct CMapper {
01606 #if defined(C_SDL2)
01607     SDL_Window * window;
01608     SDL_Rect draw_rect;
01609     SDL_Surface * draw_surface_nonpaletted;
01610     SDL_Surface * draw_surface;
01611 #endif
01612     SDL_Surface * surface;
01613     bool exit;
01614     CEvent * aevent;                //Active Event
01615     CBind * abind;                  //Active Bind
01616     CBindList_it abindit;           //Location of active bind in list
01617     bool redraw;
01618     bool addbind;
01619     Bitu mods;
01620     struct {
01621         Bitu num_groups,num;
01622         CStickBindGroup * stick[MAXSTICKS];
01623     } sticks;
01624     std::string filename;
01625 } mapper;
01626 
01627 /* whether to run keystrokes through system but only to show how it comes out.
01628  * otherwise, do full mapper processing. */
01629 bool MAPPER_DemoOnly(void) {
01630     return !mapper.exit;
01631 }
01632 
01633 void CBindGroup::ActivateBindList(CBindList * list,Bits value,bool ev_trigger) {
01634     Bitu validmod=0;
01635     CBindList_it it;
01636     for (it=list->begin();it!=list->end();it++) {
01637         if (((*it)->mods & mapper.mods) == (*it)->mods) {
01638             if (validmod<(*it)->mods) validmod=(*it)->mods;
01639         }
01640     }
01641     for (it=list->begin();it!=list->end();it++) {
01642     /*BUG:CRASH if keymapper key is removed*/
01643         if (validmod==(*it)->mods) (*it)->ActivateBind(value,ev_trigger);
01644     }
01645 }
01646 
01647 void CBindGroup::DeactivateBindList(CBindList * list,bool ev_trigger) {
01648     CBindList_it it;
01649     for (it=list->begin();it!=list->end();it++) {
01650         (*it)->DeActivateBind(ev_trigger);
01651     }
01652 }
01653 
01654 static void DrawText(Bitu x,Bitu y,const char * text,Bit8u color,Bit8u bkcolor=CLR_BLACK) {
01655 #if defined(C_SDL2)
01656     Bit8u * draw=((Bit8u *)mapper.draw_surface->pixels)+(y*mapper.draw_surface->w)+x;
01657 #else
01658     Bit8u * draw=((Bit8u *)mapper.surface->pixels)+(y*mapper.surface->pitch)+x;
01659 #endif
01660     while (*text) {
01661         Bit8u * font=&int10_font_14[(*text)*14];
01662         Bitu i,j;Bit8u * draw_line=draw;
01663         for (i=0;i<14;i++) {
01664             Bit8u map=*font++;
01665             for (j=0;j<8;j++) {
01666                 if (map & 0x80) *(draw_line+j)=color;
01667                 else *(draw_line+j)=bkcolor;
01668                 map<<=1;
01669             }
01670 #if defined(C_SDL2)
01671             draw_line+=mapper.draw_surface->w;
01672 #else
01673             draw_line+=mapper.surface->pitch;
01674 #endif
01675         }
01676         text++;draw+=8;
01677     }
01678 }
01679 
01680 class CButton {
01681 public:
01682     virtual ~CButton(){};
01683     CButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy) {
01684         x=_x;y=_y;dx=_dx;dy=_dy;
01685         buttons.push_back(this);
01686         bkcolor=CLR_BLACK;
01687         color=CLR_WHITE;
01688         enabled=true;
01689         invert=false;
01690     }
01691     virtual void Draw(void) {
01692         Bit8u bg;
01693 
01694         if (!enabled) return;
01695 
01696         if (!invert)
01697             bg = bkcolor;
01698         else
01699             bg = color;
01700 
01701 #if defined(C_SDL2)
01702         Bit8u * point=((Bit8u *)mapper.draw_surface->pixels)+(y*mapper.draw_surface->w)+x;
01703 #else
01704         Bit8u * point=((Bit8u *)mapper.surface->pixels)+(y*mapper.surface->pitch)+x;
01705 #endif
01706         for (Bitu lines=0;lines<dy;lines++)  {
01707             if (lines==0 || lines==(dy-1)) {
01708                 for (Bitu cols=0;cols<dx;cols++) *(point+cols)=color;
01709             } else {
01710                 for (Bitu cols=1;cols<(dx-1);cols++) *(point+cols)=bg;
01711                 *point=color;*(point+dx-1)=color;
01712             }
01713 #if defined(C_SDL2)
01714             point+=mapper.draw_surface->w;
01715 #else
01716             point+=mapper.surface->pitch;
01717 #endif
01718         }
01719     }
01720     virtual bool OnTop(Bitu _x,Bitu _y) {
01721         return ( enabled && (_x>=x) && (_x<x+dx) && (_y>=y) && (_y<y+dy));
01722     }
01723     virtual void BindColor(void) {}
01724     virtual void Click(void) {}
01725     void Enable(bool yes) { 
01726         enabled=yes; 
01727         mapper.redraw=true;
01728     }
01729     void SetInvert(bool inv) {
01730         invert=inv;
01731         mapper.redraw=true;
01732     }
01733     void SetColor(Bit8u _col) { color=_col; }
01734 protected:
01735     Bitu x,y,dx,dy;
01736     Bit8u color;
01737     Bit8u bkcolor;
01738     bool invert;
01739     bool enabled;
01740 };
01741 
01742 class CTextButton : public CButton {
01743 public:
01744     CTextButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text) : CButton(_x,_y,_dx,_dy) { text=_text; invertw=0; }
01745     virtual ~CTextButton() {}
01746     void Draw(void) {
01747         Bit8u fg,bg;
01748 
01749         if (!enabled) return;
01750 
01751         if (!invert) {
01752             fg = color;
01753             bg = bkcolor;
01754         }
01755         else {
01756             fg = bkcolor;
01757             bg = color;
01758         }
01759 
01760         CButton::Draw();
01761         DrawText(x+2,y+2,text,fg,bg);
01762 
01763 #if defined(C_SDL2)
01764         Bit8u * point=((Bit8u *)mapper.draw_surface->pixels)+(y*mapper.draw_surface->w)+x;
01765 #else
01766         Bit8u * point=((Bit8u *)mapper.surface->pixels)+(y*mapper.surface->pitch)+x;
01767 #endif
01768         for (Bitu lines=0;lines<(dy-1);lines++) {
01769             if (lines != 0) {
01770                 for (Bitu cols=1;cols<=invertw;cols++) {
01771                     if (*(point+cols) == color)
01772                         *(point+cols) = bkcolor;
01773                     else
01774                         *(point+cols) = color;
01775                 }
01776             }
01777 #if defined(C_SDL2)
01778             point+=mapper.draw_surface->w;
01779 #else
01780             point+=mapper.surface->pitch;
01781 #endif
01782         }
01783     }
01784     void SetText(const char *_text) {
01785         text = _text;
01786     }
01787     void SetPartialInvert(double a) {
01788         if (a < 0) a = 0;
01789         if (a > 1) a = 1;
01790         invertw = (Bitu)floor((a * (dx - 2)) + 0.5);
01791         if (invertw > (dx - 2)) invertw = dx - 2;
01792         mapper.redraw=true;
01793     }
01794 protected:
01795     const char * text;
01796     Bitu invertw;
01797 };
01798 
01799 class CEventButton;
01800 static CEventButton * last_clicked = NULL;
01801 
01802 class CEventButton : public CTextButton {
01803 public:
01804     CEventButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text,CEvent * _event) 
01805     : CTextButton(_x,_y,_dx,_dy,_text)  { 
01806         event=_event;   
01807     }
01808     virtual ~CEventButton() {}
01809     void Click(void) {
01810         if (last_clicked) last_clicked->SetColor(CLR_WHITE);
01811         this->SetColor(CLR_GREEN);
01812         SetActiveEvent(event);
01813         last_clicked=this;
01814     }
01815 protected:
01816     CEvent * event;
01817 };
01818 
01819 class CCaptionButton : public CButton {
01820 public:
01821     CCaptionButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy) : CButton(_x,_y,_dx,_dy){
01822         caption[0]=0;
01823     }
01824     virtual ~CCaptionButton() {}
01825     void Change(const char * format,...) GCC_ATTRIBUTE(__format__(__printf__,2,3));
01826 
01827     void Draw(void) {
01828         if (!enabled) return;
01829         DrawText(x+2,y+2,caption,color);
01830     }
01831 protected:
01832     char caption[128];
01833 };
01834 
01835 void CCaptionButton::Change(const char * format,...) {
01836     va_list msg;
01837     va_start(msg,format);
01838     vsprintf(caption,format,msg);
01839     va_end(msg);
01840     mapper.redraw=true;
01841 }       
01842 
01843 static void change_action_text(const char* text,Bit8u col);
01844 
01845 static void MAPPER_SaveBinds(void);
01846 class CBindButton : public CTextButton {
01847 public: 
01848     CBindButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text,BB_Types _type) 
01849     : CTextButton(_x,_y,_dx,_dy,_text)  { 
01850         type=_type;
01851     }
01852     virtual ~CBindButton() {}
01853     void Click(void) {
01854         switch (type) {
01855         case BB_Add: 
01856             mapper.addbind=true;
01857             SetActiveBind(0);
01858             change_action_text("Press a key/joystick button or move the joystick.",CLR_RED);
01859             break;
01860         case BB_Del:
01861             if (mapper.abindit!=mapper.aevent->bindlist.end())  {
01862                 delete (*mapper.abindit);
01863                 mapper.abindit=mapper.aevent->bindlist.erase(mapper.abindit);
01864                 if (mapper.abindit==mapper.aevent->bindlist.end()) 
01865                     mapper.abindit=mapper.aevent->bindlist.begin();
01866             }
01867             if (mapper.abindit!=mapper.aevent->bindlist.end()) SetActiveBind(*(mapper.abindit));
01868             else SetActiveBind(0);
01869             break;
01870         case BB_Next:
01871             if (mapper.abindit!=mapper.aevent->bindlist.end()) 
01872                 mapper.abindit++;
01873             if (mapper.abindit==mapper.aevent->bindlist.end()) 
01874                 mapper.abindit=mapper.aevent->bindlist.begin();
01875             SetActiveBind(*(mapper.abindit));
01876             break;
01877         case BB_Save:
01878             MAPPER_SaveBinds();
01879             break;
01880         case BB_Exit:   
01881             mapper.exit=true;
01882             break;
01883         case BB_Capture:
01884             GFX_CaptureMouse();
01885             if (mouselocked) change_action_text("Capture enabled. Hit ESC to release capture.",CLR_WHITE);
01886             break;
01887         }
01888     }
01889 protected:
01890     BB_Types type;
01891 };
01892 
01893 class CCheckButton : public CTextButton {
01894 public: 
01895     CCheckButton(Bitu _x,Bitu _y,Bitu _dx,Bitu _dy,const char * _text,BC_Types _type) 
01896     : CTextButton(_x,_y,_dx,_dy,_text)  { 
01897         type=_type;
01898     }
01899     virtual ~CCheckButton() {}
01900     void Draw(void) {
01901         if (!enabled) return;
01902         bool checked=false;
01903         switch (type) {
01904         case BC_Mod1:
01905             checked=(mapper.abind->mods&BMOD_Mod1)>0;
01906             break;
01907         case BC_Mod2:
01908             checked=(mapper.abind->mods&BMOD_Mod2)>0;
01909             break;
01910         case BC_Mod3:
01911             checked=(mapper.abind->mods&BMOD_Mod3)>0;
01912             break;
01913         case BC_Host:
01914             checked=(mapper.abind->mods&BMOD_Host)>0;
01915             break;
01916         case BC_Hold:
01917             checked=(mapper.abind->flags&BFLG_Hold)>0;
01918             break;
01919         }
01920         CTextButton::Draw();
01921         if (checked) {
01922 #if defined(C_SDL2)
01923             Bit8u * point=((Bit8u *)mapper.draw_surface->pixels)+((y+2)*mapper.draw_surface->pitch)+x+dx-dy+2;
01924 #else
01925             Bit8u * point=((Bit8u *)mapper.surface->pixels)+((y+2)*mapper.surface->pitch)+x+dx-dy+2;
01926 #endif
01927             for (Bitu lines=0;lines<(dy-4);lines++)  {
01928                 memset(point,color,dy-4);
01929 #if defined(C_SDL2)
01930                 point+=mapper.draw_surface->w;
01931 #else
01932                 point+=mapper.surface->pitch;
01933 #endif
01934             }
01935         }
01936     }
01937     void Click(void) {
01938         switch (type) {
01939         case BC_Mod1:
01940             mapper.abind->mods^=BMOD_Mod1;
01941             break;
01942         case BC_Mod2:
01943             mapper.abind->mods^=BMOD_Mod2;
01944             break;
01945         case BC_Mod3:
01946             mapper.abind->mods^=BMOD_Mod3;
01947             break;
01948         case BC_Host:
01949             mapper.abind->mods^=BMOD_Host;
01950             break;
01951         case BC_Hold:
01952             mapper.abind->flags^=BFLG_Hold;
01953             break;
01954         }
01955         mapper.redraw=true;
01956     }
01957 protected:
01958     BC_Types type;
01959 };
01960 
01962 class CKeyEvent : public CTriggeredEvent {
01963 public:
01965     CKeyEvent(char const * const _entry,KBD_KEYS _key) : CTriggeredEvent(_entry), notify_button(NULL) {
01966         key=_key;
01967     }
01968 
01969     virtual ~CKeyEvent() {}
01970 
01971     virtual void Active(bool yesno) {
01972         if (MAPPER_DemoOnly()) {
01973             if (notify_button != NULL)
01974                 notify_button->SetInvert(yesno);
01975         }
01976         else {
01977             KEYBOARD_AddKey(key,yesno);
01978         }
01979 
01980         active=yesno;
01981     };
01982 
01984     void notifybutton(CTextButton *n) {
01985         notify_button = n;
01986     }
01987 
01989     CTextButton *notify_button;
01990 
01992     KBD_KEYS key;
01993 };
01994 
01996 class CJAxisEvent : public CContinuousEvent {
01997 public:
01999     CJAxisEvent(char const * const _entry,Bitu _stick,Bitu _axis,bool _positive,CJAxisEvent * _opposite_axis) : CContinuousEvent(_entry) {
02000         notify_button=NULL;
02001         stick=_stick;
02002         axis=_axis;
02003         positive=_positive;
02004         opposite_axis=_opposite_axis;
02005         if (_opposite_axis) {
02006             _opposite_axis->SetOppositeAxis(this);
02007         }
02008     }
02009 
02010     virtual ~CJAxisEvent() {}
02011 
02012     virtual void Active(bool /*moved*/) {
02013         if (notify_button != NULL)
02014             notify_button->SetPartialInvert(GetValue()/32768.0);
02015 
02016         virtual_joysticks[stick].axis_pos[axis]=(Bit16s)(GetValue()*(positive?1:-1));
02017     }
02018 
02019     virtual Bitu GetActivityCount(void) {
02020         return activity|opposite_axis->activity;
02021     }
02022 
02023     virtual void RepostActivity(void) {
02024         /* caring for joystick movement into the opposite direction */
02025         opposite_axis->Active(true);
02026     }
02027 
02029     void notifybutton(CTextButton *n) {
02030         notify_button = n;
02031     }
02032 
02034     CTextButton *notify_button;
02035 protected:
02037     void SetOppositeAxis(CJAxisEvent * _opposite_axis) {
02038         opposite_axis=_opposite_axis;
02039     }
02040 
02042     Bitu stick;
02043 
02045     Bitu axis;
02046 
02048     bool positive;
02049 
02051     CJAxisEvent * opposite_axis;
02052 };
02053 
02055 class CJButtonEvent : public CTriggeredEvent {
02056 public:
02058     CJButtonEvent(char const * const _entry,Bitu _stick,Bitu _button) : CTriggeredEvent(_entry) {
02059         stick=_stick;
02060         button=_button;
02061         notify_button=NULL;
02062     }
02063 
02064     virtual ~CJButtonEvent() {}
02065     
02066     virtual void Active(bool pressed) {
02067         if (notify_button != NULL)
02068             notify_button->SetInvert(pressed);
02069 
02070         virtual_joysticks[stick].button_pressed[button]=pressed;
02071         active=pressed;
02072     }
02073     
02075     void notifybutton(CTextButton *n) {
02076         notify_button = n;
02077     }
02078 
02080     CTextButton *notify_button;
02081 protected:
02083     Bitu stick;
02084 
02086     Bitu button;
02087 };
02088 
02090 class CJHatEvent : public CTriggeredEvent {
02091 public:
02093     CJHatEvent(char const * const _entry,Bitu _stick,Bitu _hat,Bitu _dir) : CTriggeredEvent(_entry) {
02094         stick=_stick;
02095         hat=_hat;
02096         dir=_dir;
02097     }
02098 
02099     virtual ~CJHatEvent() {}
02100 
02101     virtual void Active(bool pressed) {
02102         virtual_joysticks[stick].hat_pressed[(hat<<2)+dir]=pressed;
02103     }
02104 protected:
02106     Bitu stick;
02107 
02109     Bitu hat;
02110 
02112     Bitu dir;
02113 };
02114 
02116 class CModEvent : public CTriggeredEvent {
02117 public:
02119     CModEvent(char const * const _entry,Bitu _wmod) : CTriggeredEvent(_entry), notify_button(NULL) {
02120         wmod=_wmod;
02121     }
02122 
02123     virtual ~CModEvent() {}
02124 
02125     virtual void Active(bool yesno) {
02126         if (notify_button != NULL)
02127             notify_button->SetInvert(yesno);
02128 
02129         if (yesno) mapper.mods|=(1u << (wmod-1u));
02130         else mapper.mods&=~(1u << (wmod-1u));
02131     };
02132 
02134     void notifybutton(CTextButton *n) {
02135         notify_button = n;
02136     }
02137 
02139     CTextButton *notify_button;
02140 protected:
02142     Bitu wmod;
02143 };
02144 
02145 static CModEvent* mod_event[8] = {NULL};
02146 
02147 std::string CBind::GetModifierText(void) {
02148     std::string r,t;
02149 
02150     for (size_t m=4u/*Host key first*/;m >= 1u;m--) {
02151         if ((mods & (1u << (m - 1u))) && mod_event[m] != NULL) {
02152             t = mod_event[m]->GetBindMenuText();
02153             if (!r.empty()) r += "+";
02154             r += t;
02155         }
02156     }
02157 
02158     return r;
02159 }
02160 
02162 class CHandlerEvent : public CTriggeredEvent {
02163 public:
02165     CHandlerEvent(char const * const _entry,MAPPER_Handler * _handler,MapKeys _key,Bitu _mod,char const * const _buttonname) : CTriggeredEvent(_entry), notify_button(NULL) {
02166         handler=_handler;
02167         defmod=_mod;
02168         defkey=_key;
02169         buttonname=_buttonname;
02170         handlergroup.push_back(this);
02171         type = handler_event_t;
02172     }
02173 
02174     virtual ~CHandlerEvent() {}
02175 
02176     virtual void Active(bool yesno) {
02177         if (MAPPER_DemoOnly()) {
02178             if (notify_button != NULL)
02179                 notify_button->SetInvert(yesno);
02180         }
02181         else {
02182             (*handler)(yesno);
02183         }
02184 
02185         active=yesno;
02186     };
02187 
02189     const char * ButtonName(void) {
02190         return buttonname;
02191     }
02192 
02194 #if defined(C_SDL2)
02195     void MakeDefaultBind(char * buf) {
02196         Bitu key=0;
02197         switch (defkey) {
02198         case MK_nothing: *buf = 0; return;
02199         case MK_f1:case MK_f2:case MK_f3:case MK_f4:
02200         case MK_f5:case MK_f6:case MK_f7:case MK_f8:
02201         case MK_f9:case MK_f10:case MK_f11:case MK_f12: 
02202             key=SDL_SCANCODE_F1+(defkey-MK_f1);
02203             break;
02204         case MK_rightarrow:
02205             key=SDL_SCANCODE_RIGHT;
02206             break;
02207         case MK_return:
02208             key=SDL_SCANCODE_RETURN;
02209             break;
02210         case MK_kpminus:
02211             key=SDL_SCANCODE_KP_MINUS;
02212             break;
02213         case MK_minus:
02214             key=SDL_SCANCODE_MINUS;
02215             break;
02216         case MK_equals:
02217             key=SDL_SCANCODE_EQUALS;
02218             break;
02219         case MK_scrolllock:
02220             key=SDL_SCANCODE_SCROLLLOCK;
02221             break;
02222         case MK_pause:
02223             key=SDL_SCANCODE_PAUSE;
02224             break;
02225         case MK_printscreen:
02226             key=SDL_SCANCODE_PRINTSCREEN;
02227             break;
02228         case MK_home: 
02229             key=SDL_SCANCODE_HOME;
02230             break;
02231         case MK_1:
02232             key=SDL_SCANCODE_1;
02233             break;
02234         case MK_2:
02235             key=SDL_SCANCODE_2;
02236             break;
02237         case MK_3:
02238             key=SDL_SCANCODE_3;
02239             break;
02240         case MK_4:
02241             key=SDL_SCANCODE_4;
02242             break;
02243         case MK_c:
02244             key=SDL_SCANCODE_C;
02245             break;
02246         case MK_d:
02247             key=SDL_SCANCODE_D;
02248             break;
02249         case MK_f:
02250             key=SDL_SCANCODE_F;
02251             break;
02252         case MK_m:
02253             key=SDL_SCANCODE_M;
02254             break;
02255         case MK_r:
02256             key=SDL_SCANCODE_R;
02257             break;
02258         case MK_s:
02259             key=SDL_SCANCODE_S;
02260             break;
02261         case MK_v:
02262             key=SDL_SCANCODE_V;
02263             break;
02264         case MK_w:
02265             key=SDL_SCANCODE_W;
02266             break;
02267         case MK_escape:
02268             key=SDL_SCANCODE_ESCAPE;
02269             break;
02270         default:
02271             break;
02272         }
02273         sprintf(buf,"%s \"key %d%s%s%s%s\"",
02274             entry,
02275             (int)key,
02276             defmod & 1 ? " mod1" : "",
02277             defmod & 2 ? " mod2" : "",
02278             defmod & 4 ? " mod3" : "",
02279             defmod & 8 ? " host" : ""
02280         );
02281     }
02282 #else
02283     void MakeDefaultBind(char * buf) {
02284         Bitu key=0;
02285         switch (defkey) {
02286         case MK_nothing: *buf = 0; return;
02287         case MK_f1:case MK_f2:case MK_f3:case MK_f4:
02288         case MK_f5:case MK_f6:case MK_f7:case MK_f8:
02289         case MK_f9:case MK_f10:case MK_f11:case MK_f12: 
02290             key=(Bitu)(SDLK_F1+(defkey-MK_f1));
02291             break;
02292         case MK_rightarrow:
02293             key=SDLK_RIGHT;
02294             break;
02295         case MK_return:
02296             key=SDLK_RETURN;
02297             break;
02298         case MK_kpminus:
02299             key=SDLK_KP_MINUS;
02300             break;
02301         case MK_kpplus:
02302             key=SDLK_KP_PLUS;
02303             break;
02304         case MK_minus:
02305             key=SDLK_MINUS;
02306             break;
02307         case MK_equals:
02308             key=SDLK_EQUALS;
02309             break;
02310         case MK_scrolllock:
02311 #if defined(C_SDL2)
02312             key=SDLK_SCROLLLOCK;
02313 #else
02314             key=SDLK_SCROLLOCK;
02315 #endif
02316             break;
02317         case MK_pause:
02318             key=SDLK_PAUSE;
02319             break;
02320         case MK_printscreen:
02321 #if defined(C_SDL2)
02322             key=SDLK_PRINTSCREEN;
02323 #else
02324             key=SDLK_PRINT;
02325 #endif
02326             break;
02327         case MK_home: 
02328             key=SDLK_HOME; 
02329             break;
02330         case MK_1:
02331             key=SDLK_1;
02332             break;
02333         case MK_2:
02334             key=SDLK_2;
02335             break;
02336         case MK_3:
02337             key=SDLK_3;
02338             break;
02339         case MK_4:
02340             key=SDLK_4;
02341             break;
02342         case MK_c:
02343             key=SDLK_c;
02344             break;
02345         case MK_d:
02346             key=SDLK_d;
02347             break;
02348         case MK_f:
02349             key=SDLK_f;
02350             break;
02351         case MK_m:
02352             key=SDLK_m;
02353             break;
02354         case MK_r:
02355             key=SDLK_r;
02356             break;
02357         case MK_s:
02358             key=SDLK_s;
02359             break;
02360         case MK_v:
02361             key=SDLK_v;
02362             break;
02363         case MK_w:
02364             key=SDLK_w;
02365             break;
02366         case MK_escape:
02367             key=SDLK_ESCAPE;
02368             break;
02369         default:
02370             *buf = 0;
02371             return;
02372         }
02373         sprintf(buf,"%s \"key %d%s%s%s%s\"",
02374             entry,
02375             (int)key,
02376             defmod & 1 ? " mod1" : "",
02377             defmod & 2 ? " mod2" : "",
02378             defmod & 4 ? " mod3" : "",
02379             defmod & 8 ? " host" : ""
02380         );
02381     }
02382 #endif
02383 
02384     void notifybutton(CTextButton *n) {
02385         notify_button = n;
02386     }
02387 
02389     CTextButton *notify_button;
02390 
02392     MAPPER_Handler * handler;
02393 protected:
02395     MapKeys defkey;
02396 
02398     Bitu defmod;
02399 public:
02401     const char * buttonname;
02402 };
02403 
02404 void MAPPER_TriggerEventByName(const std::string name) {
02405     CEvent *event = get_mapper_event_by_name(name);
02406     if (event != NULL) {
02407         if (event->type == CEvent::handler_event_t) {
02408             CHandlerEvent *he = reinterpret_cast<CHandlerEvent*>(event);
02409             if (he->handler != NULL) {
02410                 he->handler(true);
02411                 he->handler(false);
02412             }
02413         }
02414     }
02415 }
02416 
02417 static struct {
02418     CCaptionButton *  event_title;
02419     CCaptionButton *  bind_title;
02420     CCaptionButton *  selected;
02421     CCaptionButton *  action;
02422     CCaptionButton *  dbg2;
02423     CCaptionButton *  dbg;
02424     CBindButton * save;
02425     CBindButton * exit;   
02426     CBindButton * cap;
02427     CBindButton * add;
02428     CBindButton * del;
02429     CBindButton * next;
02430     CCheckButton * mod1,* mod2,* mod3,* host,* hold;
02431 } bind_but;
02432 
02433 
02434 static void change_action_text(const char* text,Bit8u col) {
02435     bind_but.action->Change(text,"");
02436     bind_but.action->SetColor(col);
02437 }
02438 
02439 
02440 static void SetActiveBind(CBind * _bind) {
02441     mapper.abind=_bind;
02442     if (_bind) {
02443         bind_but.bind_title->Enable(true);
02444         char buf[256];_bind->BindName(buf);
02445         bind_but.bind_title->Change("BIND:%s",buf);
02446         bind_but.del->Enable(true);
02447         bind_but.next->Enable(true);
02448         bind_but.mod1->Enable(true);
02449         bind_but.mod2->Enable(true);
02450         bind_but.mod3->Enable(true);
02451         bind_but.host->Enable(true);
02452         bind_but.hold->Enable(true);
02453     } else {
02454         bind_but.bind_title->Enable(false);
02455         bind_but.del->Enable(false);
02456         bind_but.next->Enable(false);
02457         bind_but.mod1->Enable(false);
02458         bind_but.mod2->Enable(false);
02459         bind_but.mod3->Enable(false);
02460         bind_but.host->Enable(false);
02461         bind_but.hold->Enable(false);
02462     }
02463 }
02464 
02465 static void SetActiveEvent(CEvent * event) {
02466     mapper.aevent=event;
02467     mapper.redraw=true;
02468     mapper.addbind=false;
02469     bind_but.event_title->Change("EVENT:%s",event ? event->GetName(): "none");
02470     if (!event) {
02471         change_action_text("Select an event to change.",CLR_WHITE);
02472         bind_but.add->Enable(false);
02473         SetActiveBind(0);
02474     } else {
02475         change_action_text("Select a different event or hit the Add/Del/Next buttons.",CLR_WHITE);
02476         mapper.abindit=event->bindlist.begin();
02477         if (mapper.abindit!=event->bindlist.end()) {
02478             SetActiveBind(*(mapper.abindit));
02479         } else SetActiveBind(0);
02480         bind_but.add->Enable(true);
02481     }
02482 }
02483 
02484 #if defined(C_SDL2)
02485 extern SDL_Window * GFX_SetSDLSurfaceWindow(Bit16u width, Bit16u height);
02486 extern SDL_Rect GFX_GetSDLSurfaceSubwindowDims(Bit16u width, Bit16u height);
02487 extern void GFX_UpdateDisplayDimensions(int width, int height);
02488 #endif
02489 
02490 static void DrawButtons(void) {
02491     SDL_FillRect(mapper.surface,0,0);
02492 #if !defined(C_SDL2)
02493     SDL_LockSurface(mapper.surface);
02494 #endif
02495     for (CButton_it but_it = buttons.begin();but_it!=buttons.end();but_it++) {
02496         (*but_it)->Draw();
02497     }
02498 #if defined(C_SDL2)
02499     // We can't just use SDL_BlitScaled (say for Android) in one step
02500     SDL_BlitSurface(mapper.draw_surface, NULL, mapper.draw_surface_nonpaletted, NULL);
02501     SDL_BlitScaled(mapper.draw_surface_nonpaletted, NULL, mapper.surface, &mapper.draw_rect);
02502 //    SDL_BlitSurface(mapper.draw_surface, NULL, mapper.surface, NULL);
02503     SDL_UpdateWindowSurface(mapper.window);
02504 #else
02505     SDL_UnlockSurface(mapper.surface);
02506     SDL_Flip(mapper.surface);
02507 #endif
02508 }
02509 
02510 static CKeyEvent * AddKeyButtonEvent(Bitu x,Bitu y,Bitu dx,Bitu dy,char const * const title,char const * const entry,KBD_KEYS key) {
02511     char buf[64];
02512     strcpy(buf,"key_");
02513     strcat(buf,entry);
02514     CKeyEvent * event=new CKeyEvent(buf,key);
02515     CEventButton *button=new CEventButton(x,y,dx,dy,title,event);
02516     event->notifybutton(button);
02517     return event;
02518 }
02519 
02520 static CJAxisEvent * AddJAxisButton(Bitu x,Bitu y,Bitu dx,Bitu dy,char const * const title,Bitu stick,Bitu axis,bool positive,CJAxisEvent * opposite_axis) {
02521     char buf[64];
02522     sprintf(buf,"jaxis_%d_%d%s",(int)stick,(int)axis,positive ? "+" : "-");
02523     CJAxisEvent * event=new CJAxisEvent(buf,stick,axis,positive,opposite_axis);
02524     CEventButton *button=new CEventButton(x,y,dx,dy,title,event);
02525     event->notifybutton(button);
02526     return event;
02527 }
02528 static CJAxisEvent * AddJAxisButton_hidden(Bitu stick,Bitu axis,bool positive,CJAxisEvent * opposite_axis) {
02529     char buf[64];
02530     sprintf(buf,"jaxis_%d_%d%s",(int)stick,(int)axis,positive ? "+" : "-");
02531     return new CJAxisEvent(buf,stick,axis,positive,opposite_axis);
02532 }
02533 
02534 static void AddJButtonButton(Bitu x,Bitu y,Bitu dx,Bitu dy,char const * const title,Bitu stick,Bitu button) {
02535     char buf[64];
02536     sprintf(buf,"jbutton_%d_%d",(int)stick,(int)button);
02537     CJButtonEvent * event=new CJButtonEvent(buf,stick,button);
02538     CEventButton *evbutton=new CEventButton(x,y,dx,dy,title,event);
02539     event->notifybutton(evbutton);
02540 }
02541 static void AddJButtonButton_hidden(Bitu stick,Bitu button) {
02542     char buf[64];
02543     sprintf(buf,"jbutton_%d_%d",(int)stick,(int)button);
02544     new CJButtonEvent(buf,stick,button);
02545 }
02546 
02547 static void AddJHatButton(Bitu x,Bitu y,Bitu dx,Bitu dy,char const * const title,Bitu _stick,Bitu _hat,Bitu _dir) {
02548     char buf[64];
02549     sprintf(buf,"jhat_%d_%d_%d",(int)_stick,(int)_hat,(int)_dir);
02550     CJHatEvent * event=new CJHatEvent(buf,_stick,_hat,_dir);
02551     new CEventButton(x,y,dx,dy,title,event);
02552 }
02553 
02554 static void AddModButton(Bitu x,Bitu y,Bitu dx,Bitu dy,char const * const title,Bitu _mod) {
02555     char buf[64];
02556 
02557     if (_mod == 4)
02558         sprintf(buf,"host");
02559     else
02560         sprintf(buf,"mod_%d",(int)_mod);
02561 
02562     CModEvent * event=new CModEvent(buf,_mod);
02563     CEventButton *button=new CEventButton(x,y,dx,dy,title,event);
02564     event->notifybutton(button);
02565 
02566     assert(_mod < 8);
02567     mod_event[_mod] = event;
02568 }
02569 
02570 struct KeyBlock {
02571     const char * title;
02572     const char * entry;
02573     KBD_KEYS key;
02574 };
02575 static KeyBlock combo_f[12]={
02576     {"F1","f1",KBD_f1},     {"F2","f2",KBD_f2},     {"F3","f3",KBD_f3},     
02577     {"F4","f4",KBD_f4},     {"F5","f5",KBD_f5},     {"F6","f6",KBD_f6},
02578     {"F7","f7",KBD_f7},     {"F8","f8",KBD_f8},     {"F9","f9",KBD_f9},
02579     {"F10","f10",KBD_f10},  {"F11","f11",KBD_f11},  {"F12","f12",KBD_f12},
02580 };
02581 
02582 static KeyBlock combo_1[14]={
02583     {"`~","grave",KBD_grave},   {"1!","1",KBD_1},   {"2@","2",KBD_2},
02584     {"3#","3",KBD_3},           {"4$","4",KBD_4},   {"5%","5",KBD_5},
02585     {"6^","6",KBD_6},           {"7&","7",KBD_7},   {"8*","8",KBD_8},
02586     {"9(","9",KBD_9},           {"0)","0",KBD_0},   {"-_","minus",KBD_minus},   
02587     {"=+","equals",KBD_equals}, {"\x1B","bspace",KBD_backspace},
02588 };
02589 
02590 static KeyBlock combo_1_pc98[14]={
02591     {"`~","grave",KBD_grave},   {"1!","1",KBD_1},   {"2\"","2",KBD_2},
02592     {"3#","3",KBD_3},           {"4$","4",KBD_4},   {"5%","5",KBD_5},
02593     {"6&","6",KBD_6},           {"7'","7",KBD_7},   {"8(","8",KBD_8},
02594     {"9)","9",KBD_9},           {"0","0",KBD_0},    {"-=","minus",KBD_minus},   
02595     {"=+","equals",KBD_equals}, {"\x1B","bspace",KBD_backspace},
02596 };
02597 
02598 static KeyBlock combo_2[12]={
02599     {"q","q",KBD_q},            {"w","w",KBD_w},    {"e","e",KBD_e},
02600     {"r","r",KBD_r},            {"t","t",KBD_t},    {"y","y",KBD_y},
02601     {"u","u",KBD_u},            {"i","i",KBD_i},    {"o","o",KBD_o},    
02602     {"p","p",KBD_p},            {"[","lbracket",KBD_leftbracket},   
02603     {"]","rbracket",KBD_rightbracket},  
02604 };
02605 
02606 static KeyBlock combo_3[12]={
02607     {"a","a",KBD_a},            {"s","s",KBD_s},    {"d","d",KBD_d},
02608     {"f","f",KBD_f},            {"g","g",KBD_g},    {"h","h",KBD_h},
02609     {"j","j",KBD_j},            {"k","k",KBD_k},    {"l","l",KBD_l},
02610     {";","semicolon",KBD_semicolon},                {"'","quote",KBD_quote},
02611     {"\\","backslash",KBD_backslash},   
02612 };
02613 
02614 static KeyBlock combo_3_pc98[12]={
02615     {"a","a",KBD_a},            {"s","s",KBD_s},    {"d","d",KBD_d},
02616     {"f","f",KBD_f},            {"g","g",KBD_g},    {"h","h",KBD_h},
02617     {"j","j",KBD_j},            {"k","k",KBD_k},    {"l","l",KBD_l},
02618     {";+","semicolon",KBD_semicolon},               {"'","quote",KBD_quote},
02619     {"\\","backslash",KBD_backslash},   
02620 };
02621 
02622 static KeyBlock combo_4[11]={
02623     {"<","lessthan",KBD_extra_lt_gt},
02624     {"z","z",KBD_z},            {"x","x",KBD_x},    {"c","c",KBD_c},
02625     {"v","v",KBD_v},            {"b","b",KBD_b},    {"n","n",KBD_n},
02626     {"m","m",KBD_m},            {",","comma",KBD_comma},
02627     {".","period",KBD_period},                      {"/","slash",KBD_slash},        
02628 };
02629 
02630 static CKeyEvent * caps_lock_event=NULL;
02631 static CKeyEvent * num_lock_event=NULL;
02632 
02633 static void CreateLayout(void) {
02634     Bitu i;
02635     /* Create the buttons for the Keyboard */
02636 #define BW 28
02637 #define BH 18
02638 #define DX 5
02639 #define PX(_X_) ((_X_)*BW + DX)
02640 #define PY(_Y_) (10+(_Y_)*BH)
02641     AddKeyButtonEvent(PX(0),PY(0),BW,BH,"ESC","esc",KBD_esc);
02642     for (i=0;i<12;i++) AddKeyButtonEvent(PX(2+i),PY(0),BW,BH,combo_f[i].title,combo_f[i].entry,combo_f[i].key);
02643 
02644     if (IS_PC98_ARCH) {
02645         for (i=0;i<14;i++) AddKeyButtonEvent(PX(  i),PY(1),BW,BH,combo_1_pc98[i].title,combo_1_pc98[i].entry,combo_1_pc98[i].key);
02646     }
02647     else {
02648         for (i=0;i<14;i++) AddKeyButtonEvent(PX(  i),PY(1),BW,BH,combo_1[i].title,combo_1[i].entry,combo_1[i].key);
02649     }
02650 
02651     AddKeyButtonEvent(PX(0),PY(2),BW*2,BH,"TAB","tab",KBD_tab);
02652     for (i=0;i<12;i++) AddKeyButtonEvent(PX(2+i),PY(2),BW,BH,combo_2[i].title,combo_2[i].entry,combo_2[i].key);
02653 
02654     AddKeyButtonEvent(PX(14),PY(2),BW*2,BH*2,"ENTER","enter",KBD_enter);
02655     
02656     caps_lock_event=AddKeyButtonEvent(PX(0),PY(3),BW*2,BH,"CLCK","capslock",KBD_capslock);
02657 
02658     if (IS_PC98_ARCH) {
02659         for (i=0;i<12;i++) AddKeyButtonEvent(PX(2+i),PY(3),BW,BH,combo_3_pc98[i].title,combo_3_pc98[i].entry,combo_3_pc98[i].key);
02660     }
02661     else {
02662         for (i=0;i<12;i++) AddKeyButtonEvent(PX(2+i),PY(3),BW,BH,combo_3[i].title,combo_3[i].entry,combo_3[i].key);
02663     }
02664 
02665     AddKeyButtonEvent(PX(0),PY(4),BW*2,BH,"SHIFT","lshift",KBD_leftshift);
02666     for (i=0;i<11;i++) AddKeyButtonEvent(PX(2+i),PY(4),BW,BH,combo_4[i].title,combo_4[i].entry,combo_4[i].key);
02667     AddKeyButtonEvent(PX(13),PY(4),BW*3,BH,"SHIFT","rshift",KBD_rightshift);
02668 
02669     /* Last Row */
02670     AddKeyButtonEvent(PX(0) ,PY(5),BW*2,BH,"CTRL","lctrl",KBD_leftctrl);
02671     AddKeyButtonEvent(PX(2) ,PY(5),BW*1,BH,"WIN","lwindows",KBD_lwindows);
02672     AddKeyButtonEvent(PX(3) ,PY(5),BW*1,BH,"ALT","lalt",KBD_leftalt);
02673     AddKeyButtonEvent(PX(4) ,PY(5),BW*7,BH,"SPACE","space",KBD_space);
02674     AddKeyButtonEvent(PX(11),PY(5),BW*1,BH,"ALT","ralt",KBD_rightalt);
02675     AddKeyButtonEvent(PX(12),PY(5),BW*1,BH,"WIN","rwindows",KBD_rwindows);
02676     AddKeyButtonEvent(PX(13),PY(5),BW*1,BH,"WMN","rwinmenu",KBD_rwinmenu);
02677     AddKeyButtonEvent(PX(14),PY(5),BW*2,BH,"CTRL","rctrl",KBD_rightctrl);
02678 
02679     /* Arrow Keys */
02680 #define XO 17
02681 #define YO 0
02682 
02683     AddKeyButtonEvent(PX(XO+0),PY(YO),BW,BH,"PRT","printscreen",KBD_printscreen);
02684     AddKeyButtonEvent(PX(XO+1),PY(YO),BW,BH,"SCL","scrolllock",KBD_scrolllock);
02685     AddKeyButtonEvent(PX(XO+2),PY(YO),BW,BH,"PAU","pause",KBD_pause);
02686     AddKeyButtonEvent(PX(XO+3),PY(YO),BW,BH,"NEQ","kp_equals",KBD_kpequals);
02687     AddKeyButtonEvent(PX(XO+0),PY(YO+1),BW,BH,"INS","insert",KBD_insert);
02688     AddKeyButtonEvent(PX(XO+1),PY(YO+1),BW,BH,"HOM","home",KBD_home);
02689     AddKeyButtonEvent(PX(XO+2),PY(YO+1),BW,BH,"PUP","pageup",KBD_pageup);
02690     AddKeyButtonEvent(PX(XO+0),PY(YO+2),BW,BH,"DEL","delete",KBD_delete);
02691     AddKeyButtonEvent(PX(XO+1),PY(YO+2),BW,BH,"END","end",KBD_end);
02692     AddKeyButtonEvent(PX(XO+2),PY(YO+2),BW,BH,"PDN","pagedown",KBD_pagedown);
02693     AddKeyButtonEvent(PX(XO+1),PY(YO+4),BW,BH,"\x18","up",KBD_up);
02694     AddKeyButtonEvent(PX(XO+0),PY(YO+5),BW,BH,"\x1B","left",KBD_left);
02695     AddKeyButtonEvent(PX(XO+1),PY(YO+5),BW,BH,"\x19","down",KBD_down);
02696     AddKeyButtonEvent(PX(XO+2),PY(YO+5),BW,BH,"\x1A","right",KBD_right);
02697 #undef XO
02698 #undef YO
02699 #define XO 0
02700 #define YO 7
02701     /* Numeric KeyPad */
02702     num_lock_event=AddKeyButtonEvent(PX(XO),PY(YO),BW,BH,"NUM","numlock",KBD_numlock);
02703     AddKeyButtonEvent(PX(XO+1),PY(YO),BW,BH,"/","kp_divide",KBD_kpdivide);
02704     AddKeyButtonEvent(PX(XO+2),PY(YO),BW,BH,"*","kp_multiply",KBD_kpmultiply);
02705     AddKeyButtonEvent(PX(XO+3),PY(YO),BW,BH,"-","kp_minus",KBD_kpminus);
02706     AddKeyButtonEvent(PX(XO+0),PY(YO+1),BW,BH,"7","kp_7",KBD_kp7);
02707     AddKeyButtonEvent(PX(XO+1),PY(YO+1),BW,BH,"8","kp_8",KBD_kp8);
02708     AddKeyButtonEvent(PX(XO+2),PY(YO+1),BW,BH,"9","kp_9",KBD_kp9);
02709     AddKeyButtonEvent(PX(XO+3),PY(YO+1),BW,BH*2,"+","kp_plus",KBD_kpplus);
02710     AddKeyButtonEvent(PX(XO),PY(YO+2),BW,BH,"4","kp_4",KBD_kp4);
02711     AddKeyButtonEvent(PX(XO+1),PY(YO+2),BW,BH,"5","kp_5",KBD_kp5);
02712     AddKeyButtonEvent(PX(XO+2),PY(YO+2),BW,BH,"6","kp_6",KBD_kp6);
02713     AddKeyButtonEvent(PX(XO+0),PY(YO+3),BW,BH,"1","kp_1",KBD_kp1);
02714     AddKeyButtonEvent(PX(XO+1),PY(YO+3),BW,BH,"2","kp_2",KBD_kp2);
02715     AddKeyButtonEvent(PX(XO+2),PY(YO+3),BW,BH,"3","kp_3",KBD_kp3);
02716     AddKeyButtonEvent(PX(XO+3),PY(YO+3),BW,BH*2,"ENT","kp_enter",KBD_kpenter);
02717     if (IS_PC98_ARCH) {
02718         AddKeyButtonEvent(PX(XO+0),PY(YO+4),BW*1,BH,"0","kp_0",KBD_kp0);
02719         AddKeyButtonEvent(PX(XO+1),PY(YO+4),BW*1,BH,",","kp_comma",KBD_kpcomma);
02720     }
02721     else {
02722         AddKeyButtonEvent(PX(XO+0),PY(YO+4),BW*2,BH,"0","kp_0",KBD_kp0);
02723     }
02724     AddKeyButtonEvent(PX(XO+2),PY(YO+4),BW,BH,".","kp_period",KBD_kpperiod);
02725 #undef XO
02726 #undef YO
02727 #define XO 5
02728 #define YO 7
02729     if (IS_PC98_ARCH) {
02730         /* PC-98 extra keys */
02731         AddKeyButtonEvent(PX(XO+0),PY(YO+0),BW*2,BH,"STOP","stop",KBD_stop);
02732         AddKeyButtonEvent(PX(XO+2),PY(YO+0),BW*2,BH,"HELP","help",KBD_help);
02733 
02734         AddKeyButtonEvent(PX(XO+0),PY(YO+1),BW*2,BH,"COPY","copy",KBD_copy);
02735         AddKeyButtonEvent(PX(XO+2),PY(YO+1),BW*2,BH,"KANA","kana",KBD_kana);
02736 
02737         AddKeyButtonEvent(PX(XO+0),PY(YO+2),BW*2,BH,"NFER","nfer",KBD_nfer);
02738         AddKeyButtonEvent(PX(XO+2),PY(YO+2),BW*2,BH,"XFER","xfer",KBD_xfer);
02739 
02740         AddKeyButtonEvent(PX(XO+0),PY(YO+3),BW*1,BH,"VF1","vf1",KBD_vf1);
02741         AddKeyButtonEvent(PX(XO+1),PY(YO+3),BW*1,BH,"VF2","vf2",KBD_vf2);
02742         AddKeyButtonEvent(PX(XO+2),PY(YO+3),BW*1,BH,"VF3","vf3",KBD_vf3);
02743         AddKeyButtonEvent(PX(XO+0),PY(YO+4),BW*1,BH,"VF4","vf4",KBD_vf4);
02744         AddKeyButtonEvent(PX(XO+1),PY(YO+4),BW*1,BH,"VF5","vf5",KBD_vf5);
02745         AddKeyButtonEvent(PX(XO+2),PY(YO+4),BW*1,BH,"Ro","jp_ro",KBD_jp_ro);
02746     }
02747     else {
02748         /* F13-F24 block */
02749         AddKeyButtonEvent(PX(XO+0),PY(YO+0),BW,BH,"F13","f13",KBD_f13);
02750         AddKeyButtonEvent(PX(XO+1),PY(YO+0),BW,BH,"F14","f14",KBD_f14);
02751         AddKeyButtonEvent(PX(XO+2),PY(YO+0),BW,BH,"F15","f15",KBD_f15);
02752         AddKeyButtonEvent(PX(XO+3),PY(YO+0),BW,BH,"F16","f16",KBD_f16);
02753         AddKeyButtonEvent(PX(XO+0),PY(YO+1),BW,BH,"F17","f17",KBD_f17);
02754         AddKeyButtonEvent(PX(XO+1),PY(YO+1),BW,BH,"F18","f18",KBD_f18);
02755         AddKeyButtonEvent(PX(XO+2),PY(YO+1),BW,BH,"F19","f19",KBD_f19);
02756         AddKeyButtonEvent(PX(XO+3),PY(YO+1),BW,BH,"F20","f20",KBD_f20);
02757         AddKeyButtonEvent(PX(XO+0),PY(YO+2),BW,BH,"F21","f21",KBD_f21);
02758         AddKeyButtonEvent(PX(XO+1),PY(YO+2),BW,BH,"F22","f22",KBD_f22);
02759         AddKeyButtonEvent(PX(XO+2),PY(YO+2),BW,BH,"F23","f23",KBD_f23);
02760         AddKeyButtonEvent(PX(XO+3),PY(YO+2),BW,BH,"F24","f24",KBD_f24);
02761     }
02762 #undef XO
02763 #undef YO
02764 #define XO 0
02765 #define YO 13
02766     /* Japanese keys */
02767     AddKeyButtonEvent(PX(XO+0),PY(YO+0),BW*3,BH,"HANKAKU", "jp_hankaku", KBD_jp_hankaku);
02768     AddKeyButtonEvent(PX(XO+0),PY(YO+1),BW*3,BH,"MUHENKAN","jp_muhenkan",KBD_jp_muhenkan);
02769     AddKeyButtonEvent(PX(XO+0),PY(YO+2),BW*3,BH,"HENKAN",  "jp_henkan",  KBD_jp_henkan);
02770     AddKeyButtonEvent(PX(XO+3),PY(YO+0),BW*3,BH,"HIRAGANA","jp_hiragana",KBD_jp_hiragana);
02771     AddKeyButtonEvent(PX(XO+6),PY(YO+0),BW*1,BH,"YEN",     "jp_yen",     KBD_jp_yen);
02772     AddKeyButtonEvent(PX(XO+6),PY(YO+1),BW*1,BH,"\\",      "jp_bckslash",KBD_jp_backslash);
02773     AddKeyButtonEvent(PX(XO+6),PY(YO+2),BW*1,BH,":*",      "colon",      KBD_colon);
02774     AddKeyButtonEvent(PX(XO+7),PY(YO+0),BW*1,BH,"^`",      "caret",      KBD_caret);
02775     AddKeyButtonEvent(PX(XO+7),PY(YO+1),BW*1,BH,"@~",      "atsign",     KBD_atsign);
02776     /* Korean */
02777     AddKeyButtonEvent(PX(XO+3),PY(YO+1),BW*3,BH,"HANCHA",  "kor_hancha", KBD_kor_hancha);
02778     AddKeyButtonEvent(PX(XO+3),PY(YO+2),BW*3,BH,"HANYONG", "kor_hanyong",KBD_kor_hanyong);
02779 #undef XO
02780 #undef YO
02781 #define XO 10
02782 #define YO 8
02783     /* Joystick Buttons/Texts */
02784     /* Buttons 1+2 of 1st Joystick */
02785     AddJButtonButton(PX(XO),PY(YO),BW,BH,"1" ,0,0);
02786     AddJButtonButton(PX(XO+2),PY(YO),BW,BH,"2" ,0,1);
02787     /* Axes 1+2 (X+Y) of 1st Joystick */
02788     CJAxisEvent * cjaxis=AddJAxisButton(PX(XO+1),PY(YO),BW,BH,"Y-",0,1,false,NULL);
02789     AddJAxisButton  (PX(XO+1),PY(YO+1),BW,BH,"Y+",0,1,true,cjaxis);
02790     cjaxis=AddJAxisButton  (PX(XO),PY(YO+1),BW,BH,"X-",0,0,false,NULL);
02791     AddJAxisButton  (PX(XO+2),PY(YO+1),BW,BH,"X+",0,0,true,cjaxis);
02792 
02793     if (joytype==JOY_2AXIS) {
02794         /* Buttons 1+2 of 2nd Joystick */
02795         AddJButtonButton(PX(XO+4),PY(YO),BW,BH,"1" ,1,0);
02796         AddJButtonButton(PX(XO+4+2),PY(YO),BW,BH,"2" ,1,1);
02797         /* Buttons 3+4 of 1st Joystick, not accessible */
02798         AddJButtonButton_hidden(0,2);
02799         AddJButtonButton_hidden(0,3);
02800 
02801         /* Axes 1+2 (X+Y) of 2nd Joystick */
02802         cjaxis= AddJAxisButton(PX(XO+4),PY(YO+1),BW,BH,"X-",1,0,false,NULL);
02803                 AddJAxisButton(PX(XO+4+2),PY(YO+1),BW,BH,"X+",1,0,true,cjaxis);
02804         cjaxis= AddJAxisButton(PX(XO+4+1),PY(YO+0),BW,BH,"Y-",1,1,false,NULL);
02805                 AddJAxisButton(PX(XO+4+1),PY(YO+1),BW,BH,"Y+",1,1,true,cjaxis);
02806         /* Axes 3+4 (X+Y) of 1st Joystick, not accessible */
02807         cjaxis= AddJAxisButton_hidden(0,2,false,NULL);
02808                 AddJAxisButton_hidden(0,2,true,cjaxis);
02809         cjaxis= AddJAxisButton_hidden(0,3,false,NULL);
02810                 AddJAxisButton_hidden(0,3,true,cjaxis);
02811     } else {
02812         /* Buttons 3+4 of 1st Joystick */
02813         AddJButtonButton(PX(XO+4),PY(YO),BW,BH,"3" ,0,2);
02814         AddJButtonButton(PX(XO+4+2),PY(YO),BW,BH,"4" ,0,3);
02815         /* Buttons 1+2 of 2nd Joystick, not accessible */
02816         AddJButtonButton_hidden(1,0);
02817         AddJButtonButton_hidden(1,1);
02818 
02819         /* Axes 3+4 (X+Y) of 1st Joystick */
02820         cjaxis= AddJAxisButton(PX(XO+4),PY(YO+1),BW,BH,"X-",0,2,false,NULL);
02821                 AddJAxisButton(PX(XO+4+2),PY(YO+1),BW,BH,"X+",0,2,true,cjaxis);
02822         cjaxis= AddJAxisButton(PX(XO+4+1),PY(YO+0),BW,BH,"Y-",0,3,false,NULL);
02823                 AddJAxisButton(PX(XO+4+1),PY(YO+1),BW,BH,"Y+",0,3,true,cjaxis);
02824         /* Axes 1+2 (X+Y) of 2nd Joystick , not accessible*/
02825         cjaxis= AddJAxisButton_hidden(1,0,false,NULL);
02826                 AddJAxisButton_hidden(1,0,true,cjaxis);
02827         cjaxis= AddJAxisButton_hidden(1,1,false,NULL);
02828                 AddJAxisButton_hidden(1,1,true,cjaxis);
02829     }
02830 
02831     if (joytype==JOY_CH) {
02832         /* Buttons 5+6 of 1st Joystick */
02833         AddJButtonButton(PX(XO+8),PY(YO),BW,BH,"5" ,0,4);
02834         AddJButtonButton(PX(XO+8+2),PY(YO),BW,BH,"6" ,0,5);
02835     } else {
02836         /* Buttons 5+6 of 1st Joystick, not accessible */
02837         AddJButtonButton_hidden(0,4);
02838         AddJButtonButton_hidden(0,5);
02839     }
02840 
02841     /* Hat directions up, left, down, right */
02842     AddJHatButton(PX(XO+8+1),PY(YO),BW,BH,"UP",0,0,0);
02843     AddJHatButton(PX(XO+8+0),PY(YO+1),BW,BH,"LFT",0,0,3);
02844     AddJHatButton(PX(XO+8+1),PY(YO+1),BW,BH,"DWN",0,0,2);
02845     AddJHatButton(PX(XO+8+2),PY(YO+1),BW,BH,"RGT",0,0,1);
02846 
02847     /* Labels for the joystick */
02848     if (joytype ==JOY_2AXIS) {
02849         new CTextButton(PX(XO+0),PY(YO-1),3*BW,20,"Joystick 1");
02850         new CTextButton(PX(XO+4),PY(YO-1),3*BW,20,"Joystick 2");
02851         new CTextButton(PX(XO+8),PY(YO-1),3*BW,20,"Disabled");
02852     } else if(joytype ==JOY_4AXIS || joytype == JOY_4AXIS_2) {
02853         new CTextButton(PX(XO+0),PY(YO-1),3*BW,20,"Axis 1/2");
02854         new CTextButton(PX(XO+4),PY(YO-1),3*BW,20,"Axis 3/4");
02855         new CTextButton(PX(XO+8),PY(YO-1),3*BW,20,"Disabled");
02856     } else if(joytype == JOY_CH) {
02857         new CTextButton(PX(XO+0),PY(YO-1),3*BW,20,"Axis 1/2");
02858         new CTextButton(PX(XO+4),PY(YO-1),3*BW,20,"Axis 3/4");
02859         new CTextButton(PX(XO+8),PY(YO-1),3*BW,20,"Hat/D-pad");
02860     } else if ( joytype==JOY_FCS) {
02861         new CTextButton(PX(XO+0),PY(YO-1),3*BW,20,"Axis 1/2");
02862         new CTextButton(PX(XO+4),PY(YO-1),3*BW,20,"Axis 3");
02863         new CTextButton(PX(XO+8),PY(YO-1),3*BW,20,"Hat/D-pad");
02864     } else if(joytype == JOY_NONE) {
02865         new CTextButton(PX(XO+0),PY(YO-1),3*BW,20,"Disabled");
02866         new CTextButton(PX(XO+4),PY(YO-1),3*BW,20,"Disabled");
02867         new CTextButton(PX(XO+8),PY(YO-1),3*BW,20,"Disabled");
02868     }
02869    
02870    
02871    
02872     /* The modifier buttons */
02873     AddModButton(PX(0),PY(17),50,20,"Mod1",1);
02874     AddModButton(PX(2),PY(17),50,20,"Mod2",2);
02875     AddModButton(PX(4),PY(17),50,20,"Mod3",3);
02876     AddModButton(PX(6),PY(17),50,20,"Host",4);
02877     /* Create Handler buttons */
02878     Bitu xpos=3;Bitu ypos=11;
02879     for (CHandlerEventVector_it hit=handlergroup.begin();hit!=handlergroup.end();hit++) {
02880         unsigned int columns = ((unsigned int)strlen((*hit)->ButtonName()) + 9U) / 10U;
02881         if ((xpos+columns-1)>6) {
02882             xpos=3;ypos++;
02883         }
02884         CEventButton *button=new CEventButton(PX(xpos*3),PY(ypos),BW*3*columns,BH,(*hit)->ButtonName(),(*hit));
02885         (*hit)->notifybutton(button);
02886         xpos += columns;
02887         if (xpos>6) {
02888             xpos=3;ypos++;
02889         }
02890     }
02891     next_handler_xpos = xpos;
02892     next_handler_ypos = ypos;
02893     /* Create some text buttons */
02894 //  new CTextButton(PX(6),0,124,20,"Keyboard Layout");
02895 //  new CTextButton(PX(17),0,124,20,"Joystick Layout");
02896 
02897     bind_but.action=new CCaptionButton(180,420,0,0);
02898 
02899     bind_but.event_title=new CCaptionButton(0,350,0,0);
02900     bind_but.bind_title=new CCaptionButton(0,365,0,0);
02901 
02902     /* Create binding support buttons */
02903     
02904     bind_but.mod1=new CCheckButton(20,410,60,20, "mod1",BC_Mod1);
02905     bind_but.mod2=new CCheckButton(20,432,60,20, "mod2",BC_Mod2);
02906     bind_but.mod3=new CCheckButton(20,454,60,20, "mod3",BC_Mod3);
02907     bind_but.host=new CCheckButton(100,410,60,20,"host",BC_Host);
02908     bind_but.hold=new CCheckButton(100,432,60,20,"hold",BC_Hold);
02909 
02910     bind_but.add=new CBindButton(20,384,50,20,"Add",BB_Add);
02911     bind_but.del=new CBindButton(70,384,50,20,"Del",BB_Del);
02912     bind_but.next=new CBindButton(120,384,50,20,"Next",BB_Next);
02913 
02914     bind_but.save=new CBindButton(180,440,50,20,"Save",BB_Save);
02915     bind_but.exit=new CBindButton(230,440,50,20,"Exit",BB_Exit);
02916     bind_but.cap=new CBindButton(280,440,50,20,"Capt",BB_Capture);
02917 
02918     bind_but.dbg = new CCaptionButton(180, 462, 460, 20); // right below the Save button
02919     bind_but.dbg->Change("(event debug)");
02920 
02921     bind_but.dbg2 = new CCaptionButton(330, 440, 310, 20); // right next to the Save button
02922     bind_but.dbg2->Change("");
02923 
02924     bind_but.bind_title->Change("Bind Title");
02925 
02926     mapper_addhandler_create_buttons = true;
02927 }
02928 
02929 static SDL_Color map_pal[5]={
02930     {0x00,0x00,0x00,0x00},          //0=black
02931     {0xff,0xff,0xff,0x00},          //1=white
02932     {0xff,0x00,0x00,0x00},          //2=red
02933     {0x10,0x30,0xff,0x00},          //3=blue
02934     {0x00,0xff,0x20,0x00}           //4=green
02935 };
02936 
02937 static void CreateStringBind(char * line,bool loading=false) {
02938     std::string o_line = line;
02939 
02940     line=trim(line);
02941     if (*line == 0) return;
02942     char * eventname=StripWord(line);
02943     CEvent * event;
02944     for (CEventVector_it ev_it=events.begin();ev_it!=events.end();ev_it++) {
02945         if (!strcasecmp((*ev_it)->GetName(),eventname)) {
02946             event=*ev_it;
02947             goto foundevent;
02948         }
02949     }
02950 
02951     if (loading) {
02952         /* NTS: StripWord() updates line pointer after ASCIIZ snipping the event name */
02953         pending_string_binds[eventname] = line; /* perhaps code will register it later (i.e. Herc pal change) */
02954         LOG(LOG_MISC,LOG_WARN)("Can't find matching event for %s = %s yet. It may exist later when registered elsewhere in this emulator.",eventname,line);
02955     }
02956     else {
02957         LOG(LOG_MISC,LOG_WARN)("Can't find matching event for %s",eventname);
02958     }
02959 
02960     return ;
02961 foundevent:
02962     CBind * bind;
02963     for (char * bindline=StripWord(line);*bindline;bindline=StripWord(line)) {
02964         for (CBindGroup_it it=bindgroups.begin();it!=bindgroups.end();it++) {
02965             bind=(*it)->CreateConfigBind(bindline);
02966             if (bind) {
02967                 event->AddBind(bind);
02968                 bind->SetFlags(bindline);
02969                 event->update_menu_shortcut();
02970                 break;
02971             }
02972         }
02973     }
02974 }
02975 
02976 #if defined(C_SDL2)
02977 
02978 static struct {
02979     const char * eventend;
02980     Bitu key;
02981 } DefaultKeys[]={
02982 
02983     {"f1",SDL_SCANCODE_F1},     {"f2",SDL_SCANCODE_F2},     {"f3",SDL_SCANCODE_F3},     {"f4",SDL_SCANCODE_F4},
02984     {"f5",SDL_SCANCODE_F5},     {"f6",SDL_SCANCODE_F6},     {"f7",SDL_SCANCODE_F7},     {"f8",SDL_SCANCODE_F8},
02985     {"f9",SDL_SCANCODE_F9},     {"f10",SDL_SCANCODE_F10},   {"f11",SDL_SCANCODE_F11},   {"f12",SDL_SCANCODE_F12},
02986 
02987     {"1",SDL_SCANCODE_1},       {"2",SDL_SCANCODE_2},       {"3",SDL_SCANCODE_3},       {"4",SDL_SCANCODE_4},
02988     {"5",SDL_SCANCODE_5},       {"6",SDL_SCANCODE_6},       {"7",SDL_SCANCODE_7},       {"8",SDL_SCANCODE_8},
02989     {"9",SDL_SCANCODE_9},       {"0",SDL_SCANCODE_0},
02990 
02991     {"a",SDL_SCANCODE_A},       {"b",SDL_SCANCODE_B},       {"c",SDL_SCANCODE_C},       {"d",SDL_SCANCODE_D},
02992     {"e",SDL_SCANCODE_E},       {"f",SDL_SCANCODE_F},       {"g",SDL_SCANCODE_G},       {"h",SDL_SCANCODE_H},
02993     {"i",SDL_SCANCODE_I},       {"j",SDL_SCANCODE_J},       {"k",SDL_SCANCODE_K},       {"l",SDL_SCANCODE_L},
02994     {"m",SDL_SCANCODE_M},       {"n",SDL_SCANCODE_N},       {"o",SDL_SCANCODE_O},       {"p",SDL_SCANCODE_P},
02995     {"q",SDL_SCANCODE_Q},       {"r",SDL_SCANCODE_R},       {"s",SDL_SCANCODE_S},       {"t",SDL_SCANCODE_T},
02996     {"u",SDL_SCANCODE_U},       {"v",SDL_SCANCODE_V},       {"w",SDL_SCANCODE_W},       {"x",SDL_SCANCODE_X},
02997     {"y",SDL_SCANCODE_Y},       {"z",SDL_SCANCODE_Z},       {"space",SDL_SCANCODE_SPACE},
02998     {"esc",SDL_SCANCODE_ESCAPE},    {"equals",SDL_SCANCODE_EQUALS},     {"grave",SDL_SCANCODE_GRAVE},
02999     {"tab",SDL_SCANCODE_TAB},       {"enter",SDL_SCANCODE_RETURN},      {"bspace",SDL_SCANCODE_BACKSPACE},
03000     {"lbracket",SDL_SCANCODE_LEFTBRACKET},                      {"rbracket",SDL_SCANCODE_RIGHTBRACKET},
03001     {"minus",SDL_SCANCODE_MINUS},   {"capslock",SDL_SCANCODE_CAPSLOCK}, {"semicolon",SDL_SCANCODE_SEMICOLON},
03002     {"quote", SDL_SCANCODE_APOSTROPHE}, {"backslash",SDL_SCANCODE_BACKSLASH},   {"lshift",SDL_SCANCODE_LSHIFT},
03003     {"rshift",SDL_SCANCODE_RSHIFT}, {"lalt",SDL_SCANCODE_LALT},         {"ralt",SDL_SCANCODE_RALT},
03004     {"lctrl",SDL_SCANCODE_LCTRL},   {"rctrl",SDL_SCANCODE_RCTRL},       {"comma",SDL_SCANCODE_COMMA},
03005     {"period",SDL_SCANCODE_PERIOD}, {"slash",SDL_SCANCODE_SLASH},       {"printscreen",SDL_SCANCODE_PRINTSCREEN},
03006     {"scrolllock",SDL_SCANCODE_SCROLLLOCK}, {"pause",SDL_SCANCODE_PAUSE},       {"pagedown",SDL_SCANCODE_PAGEDOWN},
03007     {"pageup",SDL_SCANCODE_PAGEUP}, {"insert",SDL_SCANCODE_INSERT},     {"home",SDL_SCANCODE_HOME},
03008     {"delete",SDL_SCANCODE_DELETE}, {"end",SDL_SCANCODE_END},           {"up",SDL_SCANCODE_UP},
03009     {"left",SDL_SCANCODE_LEFT},     {"down",SDL_SCANCODE_DOWN},         {"right",SDL_SCANCODE_RIGHT},
03010     {"kp_0",SDL_SCANCODE_KP_0}, {"kp_1",SDL_SCANCODE_KP_1}, {"kp_2",SDL_SCANCODE_KP_2}, {"kp_3",SDL_SCANCODE_KP_3},
03011     {"kp_4",SDL_SCANCODE_KP_4}, {"kp_5",SDL_SCANCODE_KP_5}, {"kp_6",SDL_SCANCODE_KP_6}, {"kp_7",SDL_SCANCODE_KP_7},
03012     {"kp_8",SDL_SCANCODE_KP_8}, {"kp_9",SDL_SCANCODE_KP_9}, {"numlock",SDL_SCANCODE_NUMLOCKCLEAR},
03013     {"kp_divide",SDL_SCANCODE_KP_DIVIDE},   {"kp_multiply",SDL_SCANCODE_KP_MULTIPLY},
03014     {"kp_minus",SDL_SCANCODE_KP_MINUS},     {"kp_plus",SDL_SCANCODE_KP_PLUS},
03015     {"kp_period",SDL_SCANCODE_KP_PERIOD},   {"kp_enter",SDL_SCANCODE_KP_ENTER},
03016 
03017     /* Is that the extra backslash key ("less than" key) */
03018     /* on some keyboards with the 102-keys layout??      */
03019     {"lessthan",SDL_SCANCODE_NONUSBACKSLASH},
03020     {0,0}
03021 };
03022 
03023 #else
03024 
03025 static struct {
03026     const char * eventend;
03027     Bitu key;
03028 } DefaultKeys[]={
03029     {"f1",SDLK_F1},     {"f2",SDLK_F2},     {"f3",SDLK_F3},     {"f4",SDLK_F4},
03030     {"f5",SDLK_F5},     {"f6",SDLK_F6},     {"f7",SDLK_F7},     {"f8",SDLK_F8},
03031     {"f9",SDLK_F9},     {"f10",SDLK_F10},   {"f11",SDLK_F11},   {"f12",SDLK_F12},
03032     {"f13",SDLK_F13},   {"f14",SDLK_F14},   {"f15",SDLK_F15},
03033 
03034     {"1",SDLK_1},       {"2",SDLK_2},       {"3",SDLK_3},       {"4",SDLK_4},
03035     {"5",SDLK_5},       {"6",SDLK_6},       {"7",SDLK_7},       {"8",SDLK_8},
03036     {"9",SDLK_9},       {"0",SDLK_0},
03037 
03038     {"a",SDLK_a},       {"b",SDLK_b},       {"c",SDLK_c},       {"d",SDLK_d},
03039     {"e",SDLK_e},       {"f",SDLK_f},       {"g",SDLK_g},       {"h",SDLK_h},
03040     {"i",SDLK_i},       {"j",SDLK_j},       {"k",SDLK_k},       {"l",SDLK_l},
03041     {"m",SDLK_m},       {"n",SDLK_n},       {"o",SDLK_o},       {"p",SDLK_p},
03042     {"q",SDLK_q},       {"r",SDLK_r},       {"s",SDLK_s},       {"t",SDLK_t},
03043     {"u",SDLK_u},       {"v",SDLK_v},       {"w",SDLK_w},       {"x",SDLK_x},
03044     {"y",SDLK_y},       {"z",SDLK_z},       {"space",SDLK_SPACE},
03045     {"esc",SDLK_ESCAPE},    {"equals",SDLK_EQUALS},     {"grave",SDLK_BACKQUOTE},
03046     {"tab",SDLK_TAB},       {"enter",SDLK_RETURN},      {"bspace",SDLK_BACKSPACE},
03047     {"lbracket",SDLK_LEFTBRACKET},                      {"rbracket",SDLK_RIGHTBRACKET},
03048     {"minus",SDLK_MINUS},   {"capslock",SDLK_CAPSLOCK}, {"semicolon",SDLK_SEMICOLON},
03049     {"quote", SDLK_QUOTE},  {"backslash",SDLK_BACKSLASH},   {"lshift",SDLK_LSHIFT},
03050     {"rshift",SDLK_RSHIFT}, {"lalt",SDLK_LALT},         {"ralt",SDLK_RALT},
03051     {"lctrl",SDLK_LCTRL},   {"rctrl",SDLK_RCTRL},       {"comma",SDLK_COMMA},
03052     {"period",SDLK_PERIOD}, {"slash",SDLK_SLASH},
03053 
03054 #if defined(C_SDL2)
03055     {"printscreen",SDLK_PRINTSCREEN},
03056     {"scrolllock",SDLK_SCROLLLOCK},
03057 #else
03058     {"printscreen",SDLK_PRINT},
03059     {"scrolllock",SDLK_SCROLLOCK},
03060 #endif
03061 
03062     {"pause",SDLK_PAUSE},       {"pagedown",SDLK_PAGEDOWN},
03063     {"pageup",SDLK_PAGEUP}, {"insert",SDLK_INSERT},     {"home",SDLK_HOME},
03064     {"delete",SDLK_DELETE}, {"end",SDLK_END},           {"up",SDLK_UP},
03065     {"left",SDLK_LEFT},     {"down",SDLK_DOWN},         {"right",SDLK_RIGHT},
03066 
03067 #if defined(C_SDL2)
03068     {"kp_0",SDLK_KP_0}, {"kp_1",SDLK_KP_1}, {"kp_2",SDLK_KP_2}, {"kp_3",SDLK_KP_3},
03069     {"kp_4",SDLK_KP_4}, {"kp_5",SDLK_KP_5}, {"kp_6",SDLK_KP_6}, {"kp_7",SDLK_KP_7},
03070     {"kp_8",SDLK_KP_8}, {"kp_9",SDLK_KP_9},
03071     {"numlock",SDLK_NUMLOCKCLEAR},
03072 #else
03073     {"kp_0",SDLK_KP0},  {"kp_1",SDLK_KP1},  {"kp_2",SDLK_KP2},  {"kp_3",SDLK_KP3},
03074     {"kp_4",SDLK_KP4},  {"kp_5",SDLK_KP5},  {"kp_6",SDLK_KP6},  {"kp_7",SDLK_KP7},
03075     {"kp_8",SDLK_KP8},  {"kp_9",SDLK_KP9},
03076     {"numlock",SDLK_NUMLOCK},
03077 #endif
03078 
03079     {"kp_divide",SDLK_KP_DIVIDE},   {"kp_multiply",SDLK_KP_MULTIPLY},
03080     {"kp_minus",SDLK_KP_MINUS},     {"kp_plus",SDLK_KP_PLUS},
03081     {"kp_period",SDLK_KP_PERIOD},   {"kp_enter",SDLK_KP_ENTER},
03082 
03083     /* NTS: IBM PC keyboards as far as I know do not have numeric keypad equals sign.
03084      *      This default assignment should allow Apple Mac users (who's keyboards DO have one)
03085      *      to use theirs as a normal equals sign. */
03086     {"kp_equals",SDLK_KP_EQUALS},
03087 
03088 #if defined(C_SDL2)
03089     // TODO??
03090 #else
03091     /* Windows 95 keyboard stuff */
03092     {"lwindows",SDLK_LSUPER},
03093     {"rwindows",SDLK_RSUPER},
03094 #endif
03095     {"rwinmenu",SDLK_MENU},
03096 
03097 #if defined (MACOSX)
03098     /* Intl Mac keyboards in US layout actually put U+00A7 SECTION SIGN here */
03099     {"lessthan",SDLK_WORLD_0},
03100 #else
03101     {"lessthan",SDLK_LESS},
03102 #endif
03103 
03104 #if defined(C_SDL2)
03105     // TODO??
03106 #else
03107     /* hack for Japanese keyboards with \ and _ */
03108     {"jp_bckslash",SDLK_JP_RO}, // Same difference
03109     {"jp_ro",SDLK_JP_RO}, // DOSBox proprietary
03110     /* hack for Japanese keyboards with Yen and | */
03111     {"jp_yen",SDLK_JP_YEN },
03112     /* more */
03113     {"jp_hankaku", SDLK_WORLD_12 },
03114     {"jp_muhenkan", SDLK_WORLD_13 },
03115     {"jp_henkan", SDLK_WORLD_14 },
03116     {"jp_hiragana", SDLK_WORLD_15 },
03117     {"colon", SDLK_COLON },
03118     {"caret", SDLK_CARET },
03119     {"atsign", SDLK_AT },
03120 #endif
03121 
03122     {0,0}
03123 };
03124 
03125 #endif
03126 
03127 static void CreateDefaultBinds(void) {
03128     char buffer[512];
03129     Bitu i=0;
03130     while (DefaultKeys[i].eventend) {
03131         sprintf(buffer,"key_%s \"key %d\"",DefaultKeys[i].eventend,(int)DefaultKeys[i].key);
03132         CreateStringBind(buffer);
03133         i++;
03134     }
03135 
03136 #if defined(C_SDL2)
03137     sprintf(buffer,"mod_1 \"key %d\"",SDL_SCANCODE_RCTRL);CreateStringBind(buffer);
03138     sprintf(buffer,"mod_1 \"key %d\"",SDL_SCANCODE_LCTRL);CreateStringBind(buffer);
03139     sprintf(buffer,"mod_2 \"key %d\"",SDL_SCANCODE_RALT);CreateStringBind(buffer);
03140     sprintf(buffer,"mod_2 \"key %d\"",SDL_SCANCODE_LALT);CreateStringBind(buffer);
03141     sprintf(buffer,"mod_3 \"key %d\"",SDL_SCANCODE_RSHIFT);CreateStringBind(buffer);
03142     sprintf(buffer,"mod_3 \"key %d\"",SDL_SCANCODE_LSHIFT);CreateStringBind(buffer);
03143 # if defined(WIN32) && !defined(C_HX_DOS) /* F12 is not a good modifier key in Windows: https://stackoverflow.com/questions/18997754/how-to-disable-f12-to-debug-application-in-visual-studio-2012 */
03144     sprintf(buffer,"host \"key %d\"",SDL_SCANCODE_F11);CreateStringBind(buffer);
03145 # else
03146     sprintf(buffer,"host \"key %d\"",SDL_SCANCODE_F12);CreateStringBind(buffer);
03147 # endif
03148 #else
03149     sprintf(buffer,"mod_1 \"key %d\"",SDLK_RCTRL);CreateStringBind(buffer);
03150     sprintf(buffer,"mod_1 \"key %d\"",SDLK_LCTRL);CreateStringBind(buffer);
03151     sprintf(buffer,"mod_2 \"key %d\"",SDLK_RALT);CreateStringBind(buffer);
03152     sprintf(buffer,"mod_2 \"key %d\"",SDLK_LALT);CreateStringBind(buffer);
03153     sprintf(buffer,"mod_3 \"key %d\"",SDLK_RSHIFT);CreateStringBind(buffer);
03154     sprintf(buffer,"mod_3 \"key %d\"",SDLK_LSHIFT);CreateStringBind(buffer);
03155 # if defined(WIN32) && !defined(C_HX_DOS) /* F12 is not a good modifier key in Windows: https://stackoverflow.com/questions/18997754/how-to-disable-f12-to-debug-application-in-visual-studio-2012 */
03156     sprintf(buffer,"host \"key %d\"",SDLK_F11);CreateStringBind(buffer);
03157 # else
03158     sprintf(buffer,"host \"key %d\"",SDLK_F12);CreateStringBind(buffer);
03159 # endif
03160 #endif
03161 
03162     for (CHandlerEventVector_it hit=handlergroup.begin();hit!=handlergroup.end();hit++) {
03163         (*hit)->MakeDefaultBind(buffer);
03164         CreateStringBind(buffer);
03165     }
03166 
03167     /* joystick1, buttons 1-6 */
03168     sprintf(buffer,"jbutton_0_0 \"stick_0 button 0\" ");CreateStringBind(buffer);
03169     sprintf(buffer,"jbutton_0_1 \"stick_0 button 1\" ");CreateStringBind(buffer);
03170     sprintf(buffer,"jbutton_0_2 \"stick_0 button 2\" ");CreateStringBind(buffer);
03171     sprintf(buffer,"jbutton_0_3 \"stick_0 button 3\" ");CreateStringBind(buffer);
03172     sprintf(buffer,"jbutton_0_4 \"stick_0 button 4\" ");CreateStringBind(buffer);
03173     sprintf(buffer,"jbutton_0_5 \"stick_0 button 5\" ");CreateStringBind(buffer);
03174     /* joystick2, buttons 1-2 */
03175     sprintf(buffer,"jbutton_1_0 \"stick_1 button 0\" ");CreateStringBind(buffer);
03176     sprintf(buffer,"jbutton_1_1 \"stick_1 button 1\" ");CreateStringBind(buffer);
03177 
03178     /* joystick1, axes 1-4 */
03179     sprintf(buffer,"jaxis_0_0- \"stick_0 axis 0 0\" ");CreateStringBind(buffer);
03180     sprintf(buffer,"jaxis_0_0+ \"stick_0 axis 0 1\" ");CreateStringBind(buffer);
03181     sprintf(buffer,"jaxis_0_1- \"stick_0 axis 1 0\" ");CreateStringBind(buffer);
03182     sprintf(buffer,"jaxis_0_1+ \"stick_0 axis 1 1\" ");CreateStringBind(buffer);
03183     sprintf(buffer,"jaxis_0_2- \"stick_0 axis 2 0\" ");CreateStringBind(buffer);
03184     sprintf(buffer,"jaxis_0_2+ \"stick_0 axis 2 1\" ");CreateStringBind(buffer);
03185     sprintf(buffer,"jaxis_0_3- \"stick_0 axis 3 0\" ");CreateStringBind(buffer);
03186     sprintf(buffer,"jaxis_0_3+ \"stick_0 axis 3 1\" ");CreateStringBind(buffer);
03187     /* joystick2, axes 1-2 */
03188     sprintf(buffer,"jaxis_1_0- \"stick_1 axis 0 0\" ");CreateStringBind(buffer);
03189     sprintf(buffer,"jaxis_1_0+ \"stick_1 axis 0 1\" ");CreateStringBind(buffer);
03190     sprintf(buffer,"jaxis_1_1- \"stick_1 axis 1 0\" ");CreateStringBind(buffer);
03191     sprintf(buffer,"jaxis_1_1+ \"stick_1 axis 1 1\" ");CreateStringBind(buffer);
03192 
03193     /* joystick1, hat */
03194     sprintf(buffer,"jhat_0_0_0 \"stick_0 hat 0 1\" ");CreateStringBind(buffer);
03195     sprintf(buffer,"jhat_0_0_1 \"stick_0 hat 0 2\" ");CreateStringBind(buffer);
03196     sprintf(buffer,"jhat_0_0_2 \"stick_0 hat 0 4\" ");CreateStringBind(buffer);
03197     sprintf(buffer,"jhat_0_0_3 \"stick_0 hat 0 8\" ");CreateStringBind(buffer);
03198 }
03199 
03200 void MAPPER_AddHandler(MAPPER_Handler * handler,MapKeys key,Bitu mods,char const * const eventname,char const * const buttonname,DOSBoxMenu::item **ret_menuitem) {
03201     if (ret_menuitem != NULL)
03202         *ret_menuitem = NULL;
03203 
03204     char tempname[27];
03205     strcpy(tempname,"hand_");
03206     strcat(tempname,eventname);
03207 
03208     //Check if it already exists=> if so return.
03209     for(CHandlerEventVector_it it=handlergroup.begin();it!=handlergroup.end();it++) {
03210         if(strcmp((*it)->buttonname,buttonname) == 0) {
03211             if (ret_menuitem != NULL)
03212                 *ret_menuitem = &mainMenu.get_item(std::string("mapper_") + std::string(eventname));
03213 
03214             return;
03215         }
03216     }
03217 
03218     CHandlerEvent *event = new CHandlerEvent(tempname,handler,key,mods,buttonname);
03219     event->eventname = eventname;
03220 
03221     /* The mapper now automatically makes menu items for mapper events */
03222     DOSBoxMenu::item &menuitem = mainMenu.alloc_item(DOSBoxMenu::item_type_id, std::string("mapper_") + std::string(eventname));
03223     menuitem.set_mapper_event(tempname);
03224 
03225     if (ret_menuitem == NULL)
03226         menuitem.set_text(buttonname);
03227     else
03228         *ret_menuitem = &menuitem;
03229 
03230     if (mapper_addhandler_create_buttons) {
03231         // and a button in the mapper UI
03232         {
03233             unsigned int columns = ((unsigned int)strlen(buttonname) + 9U) / 10U;
03234             if ((next_handler_xpos+columns-1)>6) {
03235                 next_handler_xpos=3;next_handler_ypos++;
03236             }
03237             CEventButton *button=new CEventButton(PX(next_handler_xpos*3),PY(next_handler_ypos),BW*3*columns,BH,buttonname,event);
03238             event->notifybutton(button);
03239             next_handler_xpos += columns;
03240             if (next_handler_xpos>6) {
03241                 next_handler_xpos=3;next_handler_ypos++;
03242             }
03243         }
03244 
03245         // this event may have appeared in the user's mapper file, and been ignored.
03246         // now is the time to register it.
03247         {
03248             auto i = pending_string_binds.find(tempname);
03249             char tmp[512];
03250 
03251             if (i != pending_string_binds.end()) {
03252                 LOG(LOG_MISC,LOG_WARN)("Found pending event for %s from user's file, applying now",tempname);
03253 
03254                 snprintf(tmp,sizeof(tmp),"%s %s",tempname,i->second.c_str());
03255 
03256                 CreateStringBind(tmp);
03257 
03258                 pending_string_binds.erase(i);
03259             }
03260             else {
03261                 /* use default binding.
03262                  * redundant? Yes! But, apparently necessary. */
03263                 event->MakeDefaultBind(tmp);
03264                 CreateStringBind(tmp);
03265             }
03266         }
03267     }
03268 
03269     return ;
03270 }
03271 
03272 static void MAPPER_SaveBinds(void) {
03273     FILE * savefile=fopen(mapper.filename.c_str(),"wt+");
03274     if (!savefile) {
03275         LOG_MSG("Can't open %s for saving the mappings",mapper.filename.c_str());
03276         return;
03277     }
03278     char buf[128];
03279     for (CEventVector_it event_it=events.begin();event_it!=events.end();event_it++) {
03280         CEvent * event=*(event_it);
03281         fprintf(savefile,"%s ",event->GetName());
03282         for (CBindList_it bind_it=event->bindlist.begin();bind_it!=event->bindlist.end();bind_it++) {
03283             CBind * bind=*(bind_it);
03284             bind->ConfigName(buf);
03285             bind->AddFlags(buf);
03286             fprintf(savefile,"\"%s\" ",buf);
03287         }
03288         fprintf(savefile,"\n");
03289     }
03290     fclose(savefile);
03291     change_action_text("Mapper file saved.",CLR_WHITE);
03292 }
03293 
03294 static bool MAPPER_LoadBinds(void) {
03295     FILE * loadfile=fopen(mapper.filename.c_str(),"rt");
03296     if (!loadfile) return false;
03297     char linein[512];
03298     while (fgets(linein,512,loadfile)) {
03299         CreateStringBind(linein,/*loading*/true);
03300     }
03301     fclose(loadfile);
03302     LOG(LOG_MISC,LOG_NORMAL)("MAPPER: Loading mapper settings from %s", mapper.filename.c_str());
03303     return true;
03304 }
03305 
03306 bool log_keyboard_scan_codes = false;
03307 
03308 void MAPPER_CheckEvent(SDL_Event * event) {
03309     for (CBindGroup_it it=bindgroups.begin();it!=bindgroups.end();it++) {
03310         if ((*it)->CheckEvent(event)) return;
03311     }
03312 
03313     if (log_keyboard_scan_codes) {
03314         if (event->type == SDL_KEYDOWN || event->type == SDL_KEYUP)
03315             LOG_MSG("MAPPER: SDL keyboard event (%s): scancode=0x%X sym=0x%X mod=0x%X",
03316                 event->type == SDL_KEYDOWN?"down":"up",
03317                 event->key.keysym.scancode,event->key.keysym.sym,event->key.keysym.mod);
03318     }
03319 }
03320 
03321 void Mapper_MouseInputEvent(SDL_Event &event) {
03322     /* Check the press */
03323     for (CButton_it but_it = buttons.begin();but_it!=buttons.end();but_it++) {
03324         if ((*but_it)->OnTop(event.button.x,event.button.y)) {
03325             (*but_it)->Click();
03326         }
03327     }
03328 }
03329 
03330 #if defined(C_SDL2)
03331 void Mapper_FingerInputEvent(SDL_Event &event) {
03332     SDL_Event ev;
03333 
03334     memset(&ev,0,sizeof(ev));
03335     ev.type = SDL_MOUSEBUTTONUP;
03336 
03337 #if defined(WIN32)
03338     /* NTS: Windows versions of SDL2 do normalize the coordinates */
03339     ev.button.x = (Sint32)(event.tfinger.x * mapper.surface->w);
03340     ev.button.y = (Sint32)(event.tfinger.y * mapper.surface->h);
03341 #else
03342     /* NTS: Linux versions of SDL2 don't normalize the coordinates? */
03343     ev.button.x = event.tfinger.x;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03344     ev.button.y = event.tfinger.y;     /* Contrary to SDL_events.h the x/y coordinates are NOT normalized to 0...1 */
03345 #endif
03346 
03347     Mapper_MouseInputEvent(ev);
03348 }
03349 #endif
03350 
03351 Bitu GUI_JoystickCount(void);
03352 
03353 void BIND_MappingEvents(void) {
03354     SDL_Event event;
03355 
03356     if (GUI_JoystickCount()>0) SDL_JoystickUpdate();
03357     MAPPER_UpdateJoysticks();
03358 
03359     while (SDL_PollEvent(&event)) {
03360         switch (event.type) {
03361 #if defined(C_SDL2)
03362         case SDL_FINGERUP:
03363             Mapper_FingerInputEvent(event);
03364             break;
03365 #endif
03366         case SDL_MOUSEBUTTONUP:
03367 #if defined(C_SDL2)
03368             if (event.button.which != SDL_TOUCH_MOUSEID) /* don't handle mouse events faked by touchscreen */
03369                 Mapper_MouseInputEvent(event);
03370 #else
03371             Mapper_MouseInputEvent(event);
03372 #endif
03373             break;
03374         case SDL_QUIT:
03375             mapper.exit=true;
03376             break;
03377         case SDL_KEYDOWN: /* help the user determine keyboard problems by showing keyboard event, scan code, etc. */
03378         case SDL_KEYUP:
03379             {
03380                 static int event_count = 0;
03381 #if defined(C_SDL2)
03382                 SDL_Keysym &s = event.key.keysym;
03383 #else
03384                 SDL_keysym &s = event.key.keysym;
03385 #endif
03386                 char tmp[256];
03387 
03388                 // ESC is your magic key out of capture
03389                 if (s.sym == SDLK_ESCAPE && mouselocked) GFX_CaptureMouse();
03390 
03391                 size_t tmpl;
03392 #if defined(C_SDL2)
03393                 tmpl = (size_t)sprintf(tmp,"%c%02x: scan=%u sym=%u mod=%xh name=%s",
03394                     (event.type == SDL_KEYDOWN ? 'D' : 'U'),
03395                     event_count&0xFF,
03396                     s.scancode,
03397                     s.sym,
03398                     s.mod,
03399                     SDL_GetScancodeName(s.scancode));
03400 #else
03401                 tmpl = (size_t)sprintf(tmp,"%c%02x: scan=%u sym=%u mod=%xh u=%xh name=%s",
03402                     (event.type == SDL_KEYDOWN ? 'D' : 'U'),
03403                     event_count&0xFF,
03404                     s.scancode,
03405                     s.sym,
03406                     s.mod,
03407                     s.unicode,
03408                     SDL_GetKeyName((SDLKey)MapSDLCode((Bitu)s.sym)));
03409 #endif
03410                 while (tmpl < (440/8)) tmp[tmpl++] = ' ';
03411                 assert(tmpl < sizeof(tmp));
03412                 tmp[tmpl] = 0;
03413 
03414                 LOG(LOG_GUI,LOG_DEBUG)("Mapper keyboard event: %s",tmp);
03415                 bind_but.dbg->Change("%s",tmp);
03416 
03417                 tmpl = 0;
03418 #if defined(WIN32)
03419 # if defined(C_SDL2)
03420 # else
03421                 {
03422                     char nm[256];
03423 
03424                     nm[0] = 0;
03425 #if !defined(HX_DOS) /* I assume HX DOS doesn't bother with keyboard scancode names */
03426                     GetKeyNameText(s.scancode << 16,nm,sizeof(nm)-1);
03427 #endif
03428 
03429                     tmpl = sprintf(tmp, "Win32: VK=0x%x kn=%s",(unsigned int)s.win32_vk,nm);
03430                 }
03431 # endif
03432 #endif
03433 #if defined(SDL_VIDEO_DRIVER_X11)
03434 # if defined(C_SDL2)
03435 # else
03436                 {
03437                     char *LinuxX11_KeySymName(Uint32 x);
03438 
03439                     char *name;
03440 
03441                     name = LinuxX11_KeySymName(s.x11_sym);
03442                     tmpl = (size_t)sprintf(tmp,"X11: Sym=0x%x sn=%s",(unsigned int)s.x11_sym,name ? name : "");
03443                 }
03444 # endif
03445 #endif
03446                 while (tmpl < (310 / 8)) tmp[tmpl++] = ' ';
03447                 assert(tmpl < sizeof(tmp));
03448                 tmp[tmpl] = 0;
03449                 bind_but.dbg2->Change("%s", tmp);
03450 
03451                 event_count++;
03452             }
03453             /* fall through to mapper UI processing */
03454         default:
03455             if (mapper.addbind) {
03456                 for (CBindGroup_it it=bindgroups.begin();it!=bindgroups.end();it++) {
03457                     CBind * newbind=(*it)->CreateEventBind(&event);
03458                     if (!newbind) continue;
03459                     mapper.aevent->AddBind(newbind);
03460                     SetActiveEvent(mapper.aevent);
03461                     mapper.addbind=false;
03462                     mapper.aevent->update_menu_shortcut();
03463                     break;
03464                 }
03465             }
03466 
03467             void MAPPER_CheckEvent(SDL_Event * event);
03468             MAPPER_CheckEvent(&event);
03469         }
03470     }
03471 }
03472 
03473 static void InitializeJoysticks(void) {
03474     mapper.sticks.num=0;
03475     mapper.sticks.num_groups=0;
03476     if (joytype != JOY_NONE) {
03477         mapper.sticks.num=(Bitu)SDL_NumJoysticks();
03478         LOG(LOG_MISC,LOG_DEBUG)("Joystick type != none, SDL reports %u sticks",(unsigned int)mapper.sticks.num);
03479         if (joytype==JOY_AUTO) {
03480             // try to figure out what joystick type to select
03481             // depending on the number of physically attached joysticks
03482             if (mapper.sticks.num>1) {
03483                 // more than one joystick present; if all are acceptable use 2axis
03484                 // to allow emulation of two joysticks
03485                 bool first_usable=false;
03486                 SDL_Joystick* tmp_stick1=SDL_JoystickOpen(0);
03487                 if (tmp_stick1) {
03488                     if ((SDL_JoystickNumAxes(tmp_stick1)>1) || (SDL_JoystickNumButtons(tmp_stick1)>0)) {
03489                         first_usable=true;
03490                     }
03491                     SDL_JoystickClose(tmp_stick1);
03492                 }
03493                 bool second_usable=false;
03494                 SDL_Joystick* tmp_stick2=SDL_JoystickOpen(1);
03495                 if (tmp_stick2) {
03496                     if ((SDL_JoystickNumAxes(tmp_stick2)>1) || (SDL_JoystickNumButtons(tmp_stick2)>0)) {
03497                         second_usable=true;
03498                     }
03499                     SDL_JoystickClose(tmp_stick2);
03500                 }
03501                 // choose joystick type now that we know which physical joysticks are usable
03502                 if (first_usable) {
03503                     if (second_usable) {
03504                         joytype=JOY_2AXIS;
03505                         LOG_MSG("Two or more joysticks reported, initializing with 2axis");
03506                     } else {
03507                         joytype=JOY_4AXIS;
03508                         LOG_MSG("One joystick reported, initializing with 4axis");
03509                     }
03510                 } else if (second_usable) {
03511                     joytype=JOY_4AXIS_2;
03512                     LOG_MSG("One joystick reported, initializing with 4axis_2");
03513                 }
03514             } else if (mapper.sticks.num) {
03515                 // one joystick present; if it is acceptable use 4axis
03516                 joytype=JOY_NONE;
03517                 SDL_Joystick* tmp_stick1=SDL_JoystickOpen(0);
03518                 if (tmp_stick1) {
03519                     if ((SDL_JoystickNumAxes(tmp_stick1)>0) || (SDL_JoystickNumButtons(tmp_stick1)>0)) {
03520                         joytype=JOY_4AXIS;
03521                         LOG_MSG("One joystick reported, initializing with 4axis");
03522                     }
03523                 }
03524             } else {
03525                 joytype=JOY_NONE;
03526             }
03527         }
03528     }
03529     else {
03530         LOG(LOG_MISC,LOG_DEBUG)("Joystick type none, not initializing");
03531     }
03532 }
03533 
03534 static void CreateBindGroups(void) {
03535     bindgroups.clear();
03536 #if defined(C_SDL2)
03537     new CKeyBindGroup(SDL_NUM_SCANCODES);
03538 #else
03539     new CKeyBindGroup(SDLK_LAST);
03540 #endif
03541     if (joytype != JOY_NONE) {
03542 #if defined (REDUCE_JOYSTICK_POLLING)
03543         // direct access to the SDL joystick, thus removed from the event handling
03544         if (mapper.sticks.num) SDL_JoystickEventState(SDL_DISABLE);
03545 #else
03546         // enable joystick event handling
03547         if (mapper.sticks.num) SDL_JoystickEventState(SDL_ENABLE);
03548         else return;
03549 #endif
03550         Bit8u joyno=0;
03551         switch (joytype) {
03552         case JOY_NONE:
03553             break;
03554         case JOY_4AXIS:
03555             mapper.sticks.stick[mapper.sticks.num_groups++]=new C4AxisBindGroup(joyno,joyno);
03556             new CStickBindGroup(joyno+1U,joyno+1U,true);
03557             break;
03558         case JOY_4AXIS_2:
03559             mapper.sticks.stick[mapper.sticks.num_groups++]=new C4AxisBindGroup(joyno+1U,joyno);
03560             new CStickBindGroup(joyno,joyno+1U,true);
03561             break;
03562         case JOY_FCS:
03563             mapper.sticks.stick[mapper.sticks.num_groups++]=new CFCSBindGroup(joyno,joyno);
03564             new CStickBindGroup(joyno+1U,joyno+1U,true);
03565             break;
03566         case JOY_CH:
03567             mapper.sticks.stick[mapper.sticks.num_groups++]=new CCHBindGroup(joyno,joyno);
03568             new CStickBindGroup(joyno+1U,joyno+1U,true);
03569             break;
03570         case JOY_2AXIS:
03571         default:
03572             mapper.sticks.stick[mapper.sticks.num_groups++]=new CStickBindGroup(joyno,joyno);
03573             if((joyno+1U) < mapper.sticks.num) {
03574                 mapper.sticks.stick[mapper.sticks.num_groups++]=new CStickBindGroup(joyno+1U,joyno+1U);
03575             } else {
03576                 new CStickBindGroup(joyno+1U,joyno+1U,true);
03577             }
03578             break;
03579         }
03580     }
03581 }
03582 
03583 #if defined (REDUCE_JOYSTICK_POLLING)
03584 void MAPPER_UpdateJoysticks(void) {
03585     for (Bitu i=0; i<mapper.sticks.num_groups; i++) {
03586         mapper.sticks.stick[i]->UpdateJoystick();
03587     }
03588 }
03589 #endif
03590 
03591 void MAPPER_LosingFocus(void) {
03592     for (CEventVector_it evit=events.begin();evit!=events.end();evit++) {
03593         if(*evit != caps_lock_event && *evit != num_lock_event)
03594             (*evit)->DeActivateAll();
03595     }
03596 }
03597 
03598 void MAPPER_ReleaseAllKeys(void) {
03599     for (CEventVector_it evit=events.begin();evit!=events.end();evit++) {
03600         if ((*evit)->active) {
03601             LOG_MSG("Release");
03602             (*evit)->Active(false);
03603         }
03604     }
03605 }
03606 
03607 void MAPPER_RunEvent(Bitu /*val*/) {
03608     KEYBOARD_ClrBuffer();   //Clear buffer
03609     GFX_LosingFocus();      //Release any keys pressed (buffer gets filled again).
03610     MAPPER_RunInternal();
03611 }
03612 
03613 void MAPPER_Run(bool pressed) {
03614     if (pressed)
03615         return;
03616     PIC_AddEvent(MAPPER_RunEvent,0.0001f);  //In case mapper deletes the key object that ran it
03617 }
03618 
03619 void MAPPER_RunInternal() {
03620     bool GFX_GetPreventFullscreen(void);
03621 
03622     MAPPER_ReleaseAllKeys();
03623 
03624     /* Sorry, the MAPPER screws up 3Dfx OpenGL emulation.
03625      * Remove this block when fixed. */
03626     if (GFX_GetPreventFullscreen()) {
03627         LOG_MSG("MAPPER ui is not available while 3Dfx OpenGL emulation is running");
03628         return;
03629     }
03630 
03631 #if defined(__WIN32__) && !defined(C_SDL2)
03632     if(menu.maxwindow) ShowWindow(GetHWND(), SW_RESTORE);
03633 #endif
03634     int cursor = SDL_ShowCursor(SDL_QUERY);
03635     SDL_ShowCursor(SDL_ENABLE);
03636     bool mousetoggle=false;
03637     if(mouselocked) {
03638         mousetoggle=true;
03639         GFX_CaptureMouse();
03640     }
03641 
03642     /* Be sure that there is no update in progress */
03643     GFX_EndUpdate( 0 );
03644 #if defined(C_SDL2)
03645     mapper.window=GFX_SetSDLSurfaceWindow(640,480);
03646     if (mapper.window == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError());
03647     mapper.surface=SDL_GetWindowSurface(mapper.window);
03648     if (mapper.surface == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError());
03649     mapper.draw_surface=SDL_CreateRGBSurface(0,640,480,8,0,0,0,0);
03650     // Needed for SDL_BlitScaled
03651     mapper.draw_surface_nonpaletted=SDL_CreateRGBSurface(0,640,480,32,0x0000ff00,0x00ff0000,0xff000000,0);
03652     mapper.draw_rect=GFX_GetSDLSurfaceSubwindowDims(640,480);
03653     // Sorry, but SDL_SetSurfacePalette requires a full palette.
03654     SDL_Palette *sdl2_map_pal_ptr = SDL_AllocPalette(256);
03655     SDL_SetPaletteColors(sdl2_map_pal_ptr, map_pal, 0, 6);
03656     SDL_SetSurfacePalette(mapper.draw_surface, sdl2_map_pal_ptr);
03657     if (last_clicked) {
03658         last_clicked->BindColor();
03659         last_clicked=NULL;
03660     }
03661 #else
03662     mapper.surface=SDL_SetVideoMode(640,480,8,0);
03663     if (mapper.surface == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError());
03664 
03665     /* Set some palette entries */
03666     SDL_SetPalette(mapper.surface, SDL_LOGPAL|SDL_PHYSPAL, map_pal, 0, 5);
03667     if (last_clicked) {
03668         last_clicked->SetColor(CLR_WHITE);
03669         last_clicked=NULL;
03670     }
03671 #endif
03672     /* Go in the event loop */
03673     mapper.exit=false;  
03674     mapper.redraw=true;
03675     SetActiveEvent(0);
03676 #if defined (REDUCE_JOYSTICK_POLLING)
03677     SDL_JoystickEventState(SDL_ENABLE);
03678 #endif
03679     while (!mapper.exit) {
03680         if (mapper.redraw) {
03681             mapper.redraw=false;        
03682             DrawButtons();
03683         } else {
03684 #if defined(C_SDL2)
03685             SDL_UpdateWindowSurface(mapper.window);
03686 #endif
03687         }
03688         BIND_MappingEvents();
03689         SDL_Delay(1);
03690     }
03691 #if defined(C_SDL2)
03692     SDL_FreeSurface(mapper.draw_surface);
03693     SDL_FreeSurface(mapper.draw_surface_nonpaletted);
03694     SDL_FreePalette(sdl2_map_pal_ptr);
03695 #endif
03696 #if defined (REDUCE_JOYSTICK_POLLING)
03697     SDL_JoystickEventState(SDL_DISABLE);
03698 #endif
03699     if((mousetoggle && !mouselocked) || (!mousetoggle && mouselocked)) GFX_CaptureMouse();
03700     SDL_ShowCursor(cursor);
03701 #if defined(__WIN32__) && !defined(C_SDL2)
03702     GUI_Shortcut(0);
03703 #endif
03704 #if !defined(C_SDL2)
03705     DOSBox_RefreshMenu();
03706 #endif
03707     if(!menu_gui) GFX_RestoreMode();
03708 #if defined(__WIN32__) && !defined(HX_DOS)
03709     if(GetAsyncKeyState(0x11)) {
03710         INPUT ip;
03711 
03712         // Set up a generic keyboard event.
03713         ip.type = INPUT_KEYBOARD;
03714         ip.ki.wScan = 0; // hardware scan code for key
03715         ip.ki.time = 0;
03716         ip.ki.dwExtraInfo = 0;
03717 
03718         ip.ki.wVk = 0x11;
03719         ip.ki.dwFlags = 0; // 0 for key press
03720         SendInput(1, &ip, sizeof(INPUT));
03721 
03722         // Release the "ctrl" key
03723         ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release
03724         SendInput(1, &ip, sizeof(INPUT));
03725     }
03726 #endif
03727 //  KEYBOARD_ClrBuffer();
03728     GFX_LosingFocus();
03729 
03730     /* and then the menu items need to be updated */
03731     for (auto &ev : events) {
03732         if (ev != NULL) ev->update_menu_shortcut();
03733     }
03734 
03735 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
03736     mainMenu.rebuild();
03737 #endif
03738 
03739     void GFX_ForceRedrawScreen(void);
03740     GFX_ForceRedrawScreen();
03741 }
03742 
03743 void MAPPER_CheckKeyboardLayout() {
03744 #if defined(WIN32)
03745     WORD cur_kb_layout = LOWORD(GetKeyboardLayout(0));
03746 
03747     isJPkeyboard = false;
03748 
03749     if (cur_kb_layout == 1041/*JP106*/) {
03750         isJPkeyboard = true;
03751     }
03752 #endif
03753 }
03754 
03755 void MAPPER_Init(void) {
03756     LOG(LOG_MISC,LOG_DEBUG)("Initializing DOSBox mapper");
03757 
03758     mapper.exit=true;
03759 
03760     MAPPER_CheckKeyboardLayout();
03761     InitializeJoysticks();
03762     CreateLayout();
03763     CreateBindGroups();
03764     if (!MAPPER_LoadBinds()) CreateDefaultBinds();
03765     if (SDL_GetModState()&KMOD_CAPS) {
03766         for (CBindList_it bit=caps_lock_event->bindlist.begin();bit!=caps_lock_event->bindlist.end();bit++) {
03767 #if SDL_VERSION_ATLEAST(1, 2, 14)
03768             (*bit)->ActivateBind(32767,true,false);
03769             (*bit)->DeActivateBind(false);
03770 #else
03771             (*bit)->ActivateBind(32767,true,true); //Skip the action itself as bios_keyboard.cpp handles the startup state.
03772 #endif
03773         }
03774     }
03775     if (SDL_GetModState()&KMOD_NUM) {
03776         for (CBindList_it bit=num_lock_event->bindlist.begin();bit!=num_lock_event->bindlist.end();bit++) {
03777 #if SDL_VERSION_ATLEAST(1, 2, 14)
03778             (*bit)->ActivateBind(32767,true,false);
03779             (*bit)->DeActivateBind(false);
03780 #else
03781             (*bit)->ActivateBind(32767,true,true);
03782 #endif
03783         }
03784     }
03785 
03786     /* and then the menu items need to be updated */
03787     for (auto &ev : events) {
03788         if (ev != NULL) ev->update_menu_shortcut();
03789     }
03790 }
03791 //Somehow including them at the top conflicts with something in setup.h
03792 #ifdef C_X11_XKB
03793 #include "SDL_syswm.h"
03794 #include <X11/XKBlib.h>
03795 #endif
03796 void MAPPER_StartUp() {
03797     Section_prop * section=static_cast<Section_prop *>(control->GetSection("sdl"));
03798     mapper.sticks.num=0;
03799     mapper.sticks.num_groups=0;
03800     Bitu i;
03801 
03802     LOG(LOG_MISC,LOG_DEBUG)("MAPPER starting up");
03803 
03804     for (i=0; i<MAX_VJOY_BUTTONS; i++) {
03805         virtual_joysticks[0].button_pressed[i]=false;
03806         virtual_joysticks[1].button_pressed[i]=false;
03807         virtual_joysticks[0].hat_pressed[i]=false;
03808         virtual_joysticks[1].hat_pressed[i]=false;
03809     }
03810     for (i=0; i<MAX_VJOY_AXES; i++) {
03811         virtual_joysticks[0].axis_pos[i]=0;
03812         virtual_joysticks[1].axis_pos[i]=0;
03813     }
03814 
03815 #if !defined(C_SDL2)
03816     usescancodes = false;
03817 
03818     if (section->Get_bool("usescancodes")) {
03819         usescancodes=true;
03820 
03821         /* Note: table has to be tested/updated for various OSs */
03822 #if defined (MACOSX)
03823         /* nothing */
03824 #elif defined(OS2)
03825         sdlkey_map[0x61]=SDLK_UP;
03826         sdlkey_map[0x66]=SDLK_DOWN;
03827         sdlkey_map[0x63]=SDLK_LEFT;
03828         sdlkey_map[0x64]=SDLK_RIGHT;
03829         sdlkey_map[0x60]=SDLK_HOME;
03830         sdlkey_map[0x65]=SDLK_END;
03831         sdlkey_map[0x62]=SDLK_PAGEUP;
03832         sdlkey_map[0x67]=SDLK_PAGEDOWN;
03833         sdlkey_map[0x68]=SDLK_INSERT;
03834         sdlkey_map[0x69]=SDLK_DELETE;
03835         sdlkey_map[0x5C]=SDLK_KP_DIVIDE;
03836         sdlkey_map[0x5A]=SDLK_KP_ENTER;
03837         sdlkey_map[0x5B]=SDLK_RCTRL;
03838         sdlkey_map[0x5F]=SDLK_PAUSE;
03839 //      sdlkey_map[0x00]=SDLK_PRINT;
03840         sdlkey_map[0x5E]=SDLK_RALT;
03841         sdlkey_map[0x40]=SDLK_KP5;
03842         sdlkey_map[0x41]=SDLK_KP6;
03843 #elif !defined (WIN32) /* => Linux & BSDs */
03844         bool evdev_input = false;
03845 #ifdef C_X11_XKB
03846         SDL_SysWMinfo info;
03847         SDL_VERSION(&info.version);
03848         if (SDL_GetWMInfo(&info)) {
03849             XkbDescPtr desc = NULL;
03850             if((desc = XkbGetMap(info.info.x11.display,XkbAllComponentsMask,XkbUseCoreKbd))) {
03851                 if(XkbGetNames(info.info.x11.display,XkbAllNamesMask,desc) == 0) {
03852                     const char* keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
03853 //                  const char* geom = XGetAtomName(info.info.x11.display, desc->names->geometry);
03854                     if(keycodes) {
03855                         LOG(LOG_MISC,LOG_NORMAL)("keyboard type %s",keycodes);
03856                         if (strncmp(keycodes,"evdev",5) == 0) evdev_input = true;
03857                     }
03858                     XkbFreeNames(desc,XkbAllNamesMask,True);
03859                 }
03860             XkbFreeClientMap(desc,0,True);
03861             }
03862         }
03863 #endif
03864         if (evdev_input) {
03865             sdlkey_map[0x67]=SDLK_UP;
03866             sdlkey_map[0x6c]=SDLK_DOWN;
03867             sdlkey_map[0x69]=SDLK_LEFT;
03868             sdlkey_map[0x6a]=SDLK_RIGHT;
03869             sdlkey_map[0x66]=SDLK_HOME;
03870             sdlkey_map[0x6b]=SDLK_END;
03871             sdlkey_map[0x68]=SDLK_PAGEUP;
03872             sdlkey_map[0x6d]=SDLK_PAGEDOWN;
03873             sdlkey_map[0x6e]=SDLK_INSERT;
03874             sdlkey_map[0x6f]=SDLK_DELETE;
03875             sdlkey_map[0x62]=SDLK_KP_DIVIDE;
03876             sdlkey_map[0x60]=SDLK_KP_ENTER;
03877             sdlkey_map[0x61]=SDLK_RCTRL;
03878             sdlkey_map[0x77]=SDLK_PAUSE;
03879             sdlkey_map[0x63]=SDLK_PRINT;
03880             sdlkey_map[0x64]=SDLK_RALT;
03881 
03882             //Win-keys
03883             sdlkey_map[0x7d]=SDLK_LSUPER;
03884             sdlkey_map[0x7e]=SDLK_RSUPER;
03885             sdlkey_map[0x7f]=SDLK_MENU;
03886         } else {
03887             sdlkey_map[0x5a]=SDLK_UP;
03888             sdlkey_map[0x60]=SDLK_DOWN;
03889             sdlkey_map[0x5c]=SDLK_LEFT;
03890             sdlkey_map[0x5e]=SDLK_RIGHT;
03891             sdlkey_map[0x59]=SDLK_HOME;
03892             sdlkey_map[0x5f]=SDLK_END;
03893             sdlkey_map[0x5b]=SDLK_PAGEUP;
03894             sdlkey_map[0x61]=SDLK_PAGEDOWN;
03895             sdlkey_map[0x62]=SDLK_INSERT;
03896             sdlkey_map[0x63]=SDLK_DELETE;
03897             sdlkey_map[0x68]=SDLK_KP_DIVIDE;
03898             sdlkey_map[0x64]=SDLK_KP_ENTER;
03899             sdlkey_map[0x65]=SDLK_RCTRL;
03900             sdlkey_map[0x66]=SDLK_PAUSE;
03901             sdlkey_map[0x67]=SDLK_PRINT;
03902             sdlkey_map[0x69]=SDLK_RALT;
03903         }
03904 #else
03905         sdlkey_map[0xc8]=SDLK_UP;
03906         sdlkey_map[0xd0]=SDLK_DOWN;
03907         sdlkey_map[0xcb]=SDLK_LEFT;
03908         sdlkey_map[0xcd]=SDLK_RIGHT;
03909         sdlkey_map[0xc7]=SDLK_HOME;
03910         sdlkey_map[0xcf]=SDLK_END;
03911         sdlkey_map[0xc9]=SDLK_PAGEUP;
03912         sdlkey_map[0xd1]=SDLK_PAGEDOWN;
03913         sdlkey_map[0xd2]=SDLK_INSERT;
03914         sdlkey_map[0xd3]=SDLK_DELETE;
03915         sdlkey_map[0xb5]=SDLK_KP_DIVIDE;
03916         sdlkey_map[0x9c]=SDLK_KP_ENTER;
03917         sdlkey_map[0x9d]=SDLK_RCTRL;
03918         sdlkey_map[0xc5]=SDLK_PAUSE;
03919         sdlkey_map[0xb7]=SDLK_PRINT;
03920         sdlkey_map[0xb8]=SDLK_RALT;
03921 
03922         //Win-keys
03923         sdlkey_map[0xdb]=SDLK_LMETA;
03924         sdlkey_map[0xdc]=SDLK_RMETA;
03925         sdlkey_map[0xdd]=SDLK_MENU;
03926 
03927 #endif
03928 
03929         Bitu i;
03930         for (i=0; i<MAX_SDLKEYS; i++) scancode_map[i]=0;
03931         for (i=0; i<MAX_SCANCODES; i++) {
03932             SDLKey key=sdlkey_map[i];
03933             if (key<MAX_SDLKEYS) scancode_map[key]=(Bit8u)i;
03934         }
03935     }
03936 #endif
03937 
03938     Prop_path* pp = section->Get_path("mapperfile");
03939     mapper.filename = pp->realpath;
03940 
03941     {
03942         DOSBoxMenu::item *itemp = NULL;
03943 
03944         MAPPER_AddHandler(&MAPPER_Run,MK_m,MMODHOST,"mapper","Mapper",&itemp);
03945         itemp->set_accelerator(DOSBoxMenu::accelerator('m'));
03946         itemp->set_description("Bring up the mapper UI");
03947         itemp->set_text("Mapper editor");
03948     }
03949 }
03950 
03951 void MAPPER_Shutdown() {
03952     for (size_t i=0;i < events.size();i++) {
03953         if (events[i] != NULL) {
03954             delete events[i];
03955             events[i] = NULL;
03956         }
03957     }
03958     name_to_events.clear();
03959     events.clear();
03960 
03961     for (size_t i=0;i < buttons.size();i++) {
03962         if (buttons[i] != NULL) {
03963             delete buttons[i];
03964             buttons[i] = NULL;
03965         }
03966     }
03967     buttons.clear();
03968 
03969     for (size_t i=0;i < bindgroups.size();i++) {
03970         if (bindgroups[i] != NULL) {
03971             delete bindgroups[i];
03972             bindgroups[i] = NULL;
03973         }
03974     }
03975     bindgroups.clear();
03976 
03977     for (size_t i=0;i < handlergroup.size();i++) {
03978         if (handlergroup[i] != NULL) {
03979 #if 0 /* FIXME: Is this list simply another copy of other pointers? Allowing this delete[] to commence triggers double-free warnings */
03980             delete handlergroup[i];
03981 #endif
03982             handlergroup[i] = NULL;
03983         }
03984     }
03985     handlergroup.clear();
03986 }
03987