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