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