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