/* * input.cpp * * Copyright (C) 2001 Matt Ownby * * This file is part of DAPHNE, a laserdisc arcade game emulator * * DAPHNE is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * DAPHNE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // Handles SDL input functions (low-level keyboard/joystick input) #ifdef WIN32 #include // for ScreenToClient -- rdg #endif #include "SDL_syswm.h" #include #include "input.h" #include "conout.h" #include "homedir.h" #include "../video/video.h" #include "../video/SDL_Console.h" #include "../daphne.h" #include "../timer/timer.h" #include "../game/game.h" //#include "../game/thayers.h" #include "../game/singe.h" // by RDG2010 #include "../ldp-out/ldp.h" #include "fileparse.h" #include "../manymouse/manymouse.h" // by RDG #ifdef UNIX #include // for non-blocking i/o #endif #include // STL queue for coin queue using namespace std; // Win32 doesn't use strcasecmp, it uses stricmp (lame) #ifdef WIN32 #define strcasecmp stricmp #endif const int JOY_AXIS_MID = (int) (32768 * (0.75)); // how far they have to move the joystick before it 'grabs' SDL_Joystick *G_joystick = NULL; // pointer to joystick object bool g_use_joystick = true; // use a joystick by default bool g_consoledown = false; // whether the console is down or not bool g_alt_pressed = false; // whether the ALT key is presssed (for ALT-Enter combo) unsigned int idle_timer; // added by JFA for -idleexit const double STICKY_COIN_SECONDS = 0.125; // how many seconds a coin acceptor is forced to be "depressed" and how many seconds it is forced to be "released" Uint32 g_sticky_coin_cycles = 0; // STICKY_COIN_SECONDS * get_cpu_hz(0), cannot be calculated statically queue g_coin_queue; // keeps track of coin input to guarantee that coins don't get missed if the cpu is busy (during seeks for example) Uint64 g_last_coin_cycle_used = 0; // the cycle value that our last coin press used static int available_mice = 0; //rdg static ManyMouseEvent mm_event; static int bolGrab = false; #define SDL_MOUSE 100 #define MANY_MOUSE 200 static int g_mouse_mode = SDL_MOUSE; // the ASCII key words that the parser looks at for the key values // NOTE : these are in a specific order, corresponding to the enum in daphne.h const char *g_key_names[] = { "KEY_UP", "KEY_LEFT", "KEY_DOWN", "KEY_RIGHT", "KEY_START1", "KEY_START2", "KEY_BUTTON1", "KEY_BUTTON2", "KEY_BUTTON3", "KEY_COIN1", "KEY_COIN2", "KEY_SKILL1", "KEY_SKILL2", "KEY_SKILL3", "KEY_SERVICE", "KEY_TEST", "KEY_RESET", "KEY_SCREENSHOT", "KEY_QUIT", "KEY_PAUSE", "KEY_CONSOLE", "KEY_TILT" }; // default key assignments, in case .ini file is missing // Notice each switch can have two keys assigned to it // NOTE : These are in a specific order, corresponding to the enum in daphne.h int g_key_defs[SWITCH_COUNT][2] = { { SDLK_UP, SDLK_KP8 }, // up { SDLK_LEFT, SDLK_KP4 }, // left { SDLK_DOWN, SDLK_KP2 }, // down { SDLK_RIGHT, SDLK_KP6 }, // right { SDLK_1, 0 }, // 1 player start { SDLK_2, 0 }, // 2 player start { SDLK_SPACE, SDLK_LCTRL }, // action button 1 { SDLK_LALT, 0 }, // action button 2 { SDLK_LSHIFT, 0 }, // action button 3 { SDLK_5, SDLK_c }, // coin chute left { SDLK_6, 0 }, // coin chute right { SDLK_KP_DIVIDE, 0 }, // skill easy { SDLK_KP_MULTIPLY, 0 }, // skill medium { SDLK_KP_MINUS, 0 }, // skill hard { SDLK_9, 0 }, // service coin { SDLK_F2, 0 }, // test mode { SDLK_F3, 0 }, // reset cpu { SDLK_F12, SDLK_F11 }, // take screenshot { SDLK_ESCAPE, SDLK_q }, // Quit DAPHNE { SDLK_p, 0 }, // pause game { SDLK_BACKQUOTE, 0 }, // toggle console { SDLK_t, 0 }, // Tilt/Slam switch }; //////////// #ifndef GP2X // added by Russ // global button mapping array. just hardcoded room for 10 buttons max int joystick_buttons_map[10] = { SWITCH_BUTTON1, // button 1 SWITCH_BUTTON2, // button 2 SWITCH_BUTTON3, // button 3 SWITCH_BUTTON1, // button 4 SWITCH_COIN1, // button 5 SWITCH_START1, // button 6 SWITCH_BUTTON1, // button 7 SWITCH_BUTTON1, // button 8 SWITCH_BUTTON1, // button 9 SWITCH_BUTTON1, // button 10 }; #else // button mapping for gp2x int joystick_buttons_map[18] = { SWITCH_UP, // 0 (up) SWITCH_UP, // 1 (up-left) SWITCH_LEFT, // 2 (left) SWITCH_DOWN, // 3 (down-left) SWITCH_DOWN, // 4 (down) SWITCH_DOWN, // 5 (down-right) SWITCH_RIGHT, // 6 (right) SWITCH_UP, // 7 (up-right) SWITCH_START1, // 8 (start) SWITCH_COIN1, // 9 (select) SWITCH_QUIT, // 10 (left) SWITCH_PAUSE, // 11 (right) SWITCH_BUTTON1, // 12 (A) SWITCH_BUTTON2, // 13 (B) SWITCH_BUTTON3, // 14 (X) SWITCH_CONSOLE, // 15 (Y) SWITCH_BUTTON1, // 16 is vol + SWITCH_BUTTON1 // 17 is vol - }; #endif // Mouse button to key mappings // Added by ScottD for Singe int mouse_buttons_map[6] = { SWITCH_BUTTON1, // 0 (Left Button) SWITCH_BUTTON3, // 1 (Middle Button) SWITCH_BUTTON2, // 2 (Right Button) SWITCH_BUTTON1, // 3 (Wheel Up) SWITCH_BUTTON2, // 4 (Wheel Down) SWITCH_MOUSE_DISCONNECT // this is a dummy value so SDL mouse array matches Many Mouse array }; // ManyMouse button mapping to be backwards compatible with Scott's original. /* int mouse_buttons_map[6] = { SWITCH_BUTTON3, // 0 (Left Button) SWITCH_BUTTON1, // 1 (Right Button) SWITCH_BUTTON2, // 2 (Middle Up) SWITCH_MOUSE_SCROLL_UP, // 4 (Wheel UP) SWITCH_MOUSE_SCROLL_DOWN, // 3 (Wheel Down) SWITCH_MOUSE_DISCONNECT }; */ //////////// void CFG_Keys() { struct mpo_io *io; string cur_line = ""; string key_name = "", sval1 = "", sval2 = "", sval3 = "", eq_sign = ""; int val1 = 0, val2 = 0, val3 = 0; // bool done = false; // find where the dapinput ini file is (if the file doesn't exist, this string will be empty) string strDapInput = g_homedir.find_file("dapinput.ini", true); io = mpo_open(strDapInput.c_str(), MPO_OPEN_READONLY); if (io) { printline("Remapping input ..."); cur_line = ""; // read lines until we find the keyboard header or we hit EOF while (strcasecmp(cur_line.c_str(), "[KEYBOARD]") != 0) { read_line(io, cur_line); if (io->eof) { printline("CFG_Keys() : never found [KEYBOARD] header, aborting"); break; } } // go until we hit EOF, or we break inside this loop (which is the expected behavior) while (!io->eof) { // if we read in something besides a blank line if (read_line(io, cur_line) > 0) { bool corrupt_file = true; // we use this to avoid doing multiple if/else/break statements // if we are able to read in the key name if (find_word(cur_line.c_str(), key_name, cur_line)) { if (strcasecmp(key_name.c_str(), "END") == 0) break; // if we hit the 'END' keyword, we're done // equals sign if (find_word(cur_line.c_str(), eq_sign, cur_line) && (eq_sign == "=")) { if (find_word(cur_line.c_str(), sval1, cur_line)) { if (find_word(cur_line.c_str(), sval2, cur_line)) { if (find_word(cur_line.c_str(), sval3, cur_line)) { val1 = atoi(sval1.c_str()); val2 = atoi(sval2.c_str()); val3 = atoi(sval3.c_str()); corrupt_file = false; // looks like we're good bool found_match = false; for (int i = 0; i < SWITCH_COUNT; i++) { // if we can match up a key name (see list above) ... if (strcasecmp(key_name.c_str(), g_key_names[i])==0) { g_key_defs[i][0] = val1; g_key_defs[i][1] = val2; // if zero then no mapping necessary, just use default, if any if (val3 > 0) joystick_buttons_map[val3 - 1] = i; found_match = true; break; } } // if the key line was unknown if (!found_match) { cur_line = "CFG_Keys() : Unrecognized key name " + key_name; printline(cur_line.c_str()); corrupt_file = true; } } else printline("CFG_Keys() : Expected 3 integers, only found 2"); } else printline("CFG_Keys() : Expected 3 integers, only found 1"); } else printline("CFG_Keys() : Expected 3 integers, found none"); } // end equals sign else printline("CFG_Keys() : Expected an '=' sign, didn't find it"); } // end if we found key_name else printline("CFG_Keys() : Weird unexpected error happened"); // this really shouldn't ever happen if (corrupt_file) { printline("CFG_Keys() : input remapping file was not in proper format, so we are aborting"); break; } } // end if we didn't find a blank line // else it's a blank line so we just ignore it } // end while not EOF mpo_close(io); } // end if file was opened successfully } // By RDG == ManyMouse code follows static void ManyMouse_Init_Mice(void) { printline("Using ManyMouse for mice input."); available_mice = ManyMouse_Init(); g_game->set_mice_detected(available_mice); if (available_mice > MAX_MICE) available_mice = MAX_MICE; if (available_mice <= 0) printline("No mice detected!\n"); else { int i; char s1[255]; if (available_mice == 1) printline("Only 1 mouse found."); else { sprintf(s1,"Found %d mice devices:",available_mice); printline(s1); } for (i = 0; i < available_mice; i++) { const char *name = ManyMouse_DeviceName(i); strncpy(mice[i].name, name, sizeof (mice[i].name)); mice[i].name[sizeof (mice[i].name) - 1] = '\0'; mice[i].connected = 1; sprintf(s1,"#%d: %s", i, mice[i].name); printline(s1); } SDL_WM_GrabInput(SDL_GRAB_ON); } } static void ManyMouse_Update_Mice() { while (ManyMouse_PollEvent(&mm_event)) { Mouse *mouse; if (mm_event.device >= (unsigned int) available_mice) continue; mouse = &mice[mm_event.device]; if (mm_event.type == MANYMOUSE_EVENT_RELMOTION) { if (mm_event.item == 0) mouse->relx += mm_event.value; else if (mm_event.item == 1) mouse->rely += mm_event.value; if (mouse->relx < 0) mouse->relx = 0; else if (mouse->relx >= get_video_width()) mouse->relx = get_video_width(); if (mouse->rely < 0) mouse->rely = 0; else if (mouse->rely >= get_video_height()) mouse->rely = get_video_height(); g_game->OnMouseMotion(mouse->x, mouse->y, mouse->relx, mouse->rely, mm_event.device); } else if (mm_event.type == MANYMOUSE_EVENT_ABSMOTION) { float val = (float) (mm_event.value - mm_event.minval); float maxval = (float) (mm_event.maxval - mm_event.minval); if (mm_event.item == 0) //mouse->x = (val / maxval) * screen_w; mouse->x = mm_event.value; else if (mm_event.item == 1) //mouse->y = (val / maxval) * screen_h; mouse->y = mm_event.value; g_game->OnMouseMotion(mouse->x, mouse->y, mouse->relx, mouse->rely, mm_event.device); /* LPPOINT absPoint = new POINT; // Access to SDL's OS specific structure. SDL_SysWMinfo windowInfo; SDL_VERSION(&windowInfo.version); if(SDL_GetWMInfo(&windowInfo)) { // Retrieve the Windows handle to the SDL window. HWND handle = windowInfo.window; if (mm_event.item == 0) { absPoint->x = mm_event.value; absPoint->y = 0; //if (ClientToScreen(handle, absPoint) != 0) MapWindowPoints(NULL, handle,absPoint,2); mouse->x = absPoint->x; } /* else if (mm_event.item == 1) { absPoint.y = mm_event.value; if (ScreenToClient(handle,LPPOINT) absPoint.y) == 0) mouse->y = absPoint.y; } } */ } else if (mm_event.type == MANYMOUSE_EVENT_BUTTON) { if (mm_event.item < 32) { if (mm_event.value == 1) // 0 == release, 1 == pressed { input_enable((Uint8)mouse_buttons_map[mm_event.item], mm_event.device); mouse->buttons |= (1 << mm_event.item); } else { input_disable((Uint8)mouse_buttons_map[mm_event.item], mm_event.device); mouse->buttons &= ~(1 << mm_event.item); } } } else if (mm_event.type == MANYMOUSE_EVENT_SCROLL) { if (mm_event.item == 0) // vertical scroll wheel { if (mm_event.value > 0) // scroll up input_disable(SWITCH_MOUSE_SCROLL_UP, mm_event.device); else // scroll down input_disable(SWITCH_MOUSE_SCROLL_DOWN, mm_event.device); } } else if (mm_event.type == MANYMOUSE_EVENT_DISCONNECT) { mice[mm_event.device].connected = 0; input_disable(SWITCH_MOUSE_DISCONNECT, mm_event.device); } } } ////// end manymouse implementation int SDL_input_init() // initializes the keyboard (and joystick if one is present) // returns 1 if successful, 0 on error // NOTE: Video has to be initialized BEFORE this is or else it won't work { int result = 0; // make sure the coin queue is empty (it should be, this is just a safety check) while (!g_coin_queue.empty()) { g_coin_queue.pop(); } g_sticky_coin_cycles = 0;//(Uint32) (STICKY_COIN_SECONDS * get_cpu_hz(0)); // only needs to be calculated once if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0) { // if joystick usage is enabled if (g_use_joystick) { // if there is at least 1 joystick and we are authorized to use the joystick for input if (SDL_NumJoysticks() > 0) { G_joystick = SDL_JoystickOpen(0); // FIXME: right now we automatically choose the first joystick if (G_joystick != NULL) { printline("Joystick #0 was successfully opened"); } else { printline("Error opening joystick!"); } } else { printline("No joysticks detected"); } } // notify user that their attempt to disable the joystick is successful else { printline("Joystick usage disabled"); } CFG_Keys(); // NOTE : for some freak reason, this should not be done BEFORE the joystick is initialized, I don't know why! result = 1; } else { printline("Input initialization failed!"); } idle_timer = refresh_ms_time(); // added by JFA for -idleexit #ifdef UNIX // enable non-blocking stdin (see conin.cpp UNIX stdin stuff) /*int iRes =*/ fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); #endif /* // if the mouse is disabled, then filter mouse events out ... if (!g_game->get_mouse_enabled()) { FilterMouseEvents(true); } */ // Manymouse implementation by RDG if (!g_game->get_mouse_enabled()) { FilterMouseEvents(true); if (g_game->get_mouse_enabled()) ManyMouse_Init_Mice(); } else FilterMouseEvents(false); return(result); } void FilterMouseEvents(bool bFilteredOut) { int iState = SDL_ENABLE; if (bFilteredOut) { iState = SDL_IGNORE; } SDL_EventState(SDL_MOUSEMOTION, iState); SDL_EventState(SDL_MOUSEBUTTONDOWN, iState); SDL_EventState(SDL_MOUSEBUTTONUP, iState); } // does any shutting down necessary // 1 = success, 0 = failure int SDL_input_shutdown(void) { SDL_QuitSubSystem(SDL_INIT_JOYSTICK); if ((g_game->get_mouse_enabled()) && (g_mouse_mode == MANY_MOUSE)) ManyMouse_Quit(); return(1); } // checks to see if there is incoming input, and acts on it void SDL_check_input() { SDL_Event event; while ((SDL_PollEvent (&event)) && (!get_quitflag())) { // if they press the tilda key to bring down the console // this is somewhat of a hacked if statement but I can't see // a better way based on the SDL_Console API ... if ((event.type == SDL_KEYDOWN) && (event.key.keysym.sym == SDLK_BACKQUOTE)) { // we must not bring down the console if blitting is not allowed if (g_ldp->is_blitting_allowed()) { #ifdef CPU_DEBUG toggle_console(); #endif } } // if we've got the console down, process events else if (g_consoledown) { ConsoleEvents(&event); } // else handle events normally else { process_event(&event); } } if (g_game->get_mouse_enabled() && (g_mouse_mode == MANY_MOUSE)) ManyMouse_Update_Mice(); check_console_refresh(); // added by JFA for -idleexit if (get_idleexit() > 0 && elapsed_ms_time(idle_timer) > get_idleexit()) set_quitflag(); // if the coin queue has something entered into it if (!g_coin_queue.empty()) { struct coin_input coin = g_coin_queue.front(); // examine the next element in the queue to be considered // NOTE : when cpu timers are flushed, the coin queue is automatically "reshuffled" // so it is safe not to check to see whether the cpu timers were flushed here // if it's safe to activate the coin //if (get_total_cycles_executed(0) > coin.cycles_when_to_enable) { // if we're supposed to enable this coin if (coin.coin_enabled) { g_game->input_enable(coin.coin_val, NOMOUSE); } // else we are supposed to disable this coin else { g_game->input_disable(coin.coin_val, NOMOUSE); } g_coin_queue.pop(); // remove coin entry from queue } // else it's not safe to activate the coin, so we just wait } // else the coin queue is empty, so we needn't do anything ... } #ifdef CPU_DEBUG void toggle_console() { if (get_console_initialized()) { // if console is down, get rid of it if (g_consoledown) { g_consoledown = false; SDL_EnableUNICODE(0); display_repaint(); } // if console is not down, display it else { g_consoledown = true; SDL_EnableUNICODE(1); } } } #endif // processes incoming input void process_event(SDL_Event *event) { unsigned int i = 0; // by RDG2010 // make things easier to read... SDLKey keyPressed = event->key.keysym.sym; switch (event->type) { case SDL_KEYDOWN: reset_idle(); // added by JFA for -idleexit // by RDG2010 // Get SINGE full access to keyboard input (like Thayers) { singe *l_singe = dynamic_cast(g_game); if (l_singe) l_singe->process_keydown(keyPressed, g_key_defs); } break; case SDL_KEYUP: // MPO : since con_getkey doesn't catch the key up event, we shouldn't call reset_idle here. //reset_idle(); // added by JFA for -idleexit // by RDG2010 // Get SINGE full access to keyboard input (like Thayers) if (keyPressed == SDLK_g) { if ((g_game->get_mouse_enabled()) && (g_mouse_mode == MANY_MOUSE)) { bolGrab = !bolGrab; if (bolGrab) { SDL_WM_GrabInput(SDL_GRAB_ON); ManyMouse_Quit(); ManyMouse_Init_Mice(); } else SDL_WM_GrabInput(SDL_GRAB_OFF); } } else { singe *l_singe = dynamic_cast(g_game); if (l_singe) l_singe->process_keyup(keyPressed, g_key_defs); } break; case SDL_JOYAXISMOTION: //reset_idle(); // added by JFA for -idleexit // reset_idle removed here because the analog controls were registering // even when the joystick was not in use. Joystick buttons still reset the idle. process_joystick_motion(event); break; case SDL_JOYHATMOTION: // only process events for the first hat if ( event->jhat.hat == 0 ) { reset_idle(); process_joystick_hat_motion(event); } break; case SDL_JOYBUTTONDOWN: reset_idle(); // added by JFA for -idleexit // added by Russ // loop through buttons and look for a press for (i = 0; i < (sizeof(joystick_buttons_map) / sizeof(int)); i++) { if (event->jbutton.button == i) { input_enable((Uint8) joystick_buttons_map[i], NOMOUSE); break; } } break; case SDL_JOYBUTTONUP: reset_idle(); // added by JFA for -idleexit // added by Russ for (i = 0; i < (sizeof(joystick_buttons_map) / sizeof(int)); i++) { if (event->jbutton.button == i) { input_disable((Uint8) joystick_buttons_map[i], NOMOUSE); break; } } break; /* case SDL_MOUSEBUTTONDOWN: // added by ScottD // loop through buttons and look for a press for (i = 0; i < (sizeof(mouse_buttons_map) / sizeof(int)); i++) { if (event->button.button == i) { input_enable((Uint8)mouse_buttons_map[i]); break; } } break; case SDL_MOUSEBUTTONUP: // added by ScottD for (i = 0; i < (sizeof(mouse_buttons_map) / sizeof(int)); i++) { if (event->button.button == i) { input_disable((Uint8)mouse_buttons_map[i]); break; } } break; case SDL_MOUSEMOTION: // added by ScottD g_game->OnMouseMotion(event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel); break; */ case SDL_QUIT: // if they are trying to close the window set_quitflag(); break; default: break; } if (g_game->get_mouse_enabled() && (g_mouse_mode == SDL_MOUSE)) { switch (event->type) { case SDL_MOUSEBUTTONDOWN: // added by ScottD // loop through buttons and look for a press for (i = 0; i < (sizeof(mouse_buttons_map) / sizeof(int)); i++) { if (event->button.button == i) { //input_enable((Uint8)mouse_buttons_map[i]); g_game->input_enable((Uint8)mouse_buttons_map[i], NOMOUSE); break; } } break; case SDL_MOUSEBUTTONUP: // added by ScottD for (i = 0; i < (sizeof(mouse_buttons_map) / sizeof(int)); i++) { if (event->button.button == i) { //input_disable((Uint8)mouse_buttons_map[i]); g_game->input_disable((Uint8)mouse_buttons_map[i], NOMOUSE); break; } } break; case SDL_MOUSEMOTION: // added by ScottD g_game->OnMouseMotion(event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel, NOMOUSE); // Last parameter is for ManyMouse use only. break; } } // added by JFA for -idleexit if (get_idleexit() > 0 && elapsed_ms_time(idle_timer) > get_idleexit()) set_quitflag(); } // if a key is pressed, we go here void process_keydown(SDLKey key) { // go through each key def (defined in enum in daphne.h) and check to see if the key entered matches // If we have a match, the switch to be used is the value of the index "move" for (Uint8 move = 0; move < SWITCH_COUNT; move++) { if ((key == g_key_defs[move][0]) || (key == g_key_defs[move][1])) { input_enable(move, NOMOUSE); } } // check for ALT-ENTER here if ((key == SDLK_LALT) || (key == SDLK_RALT)) { g_alt_pressed = true; } else if ((key == SDLK_RETURN) && (g_alt_pressed)) { vid_toggle_fullscreen(); } // end ALT-ENTER check } // if a key is released, we go here void process_keyup(SDLKey key) { // go through each key def (defined in enum in daphne.h) and check to see if the key entered matches // If we have a match, the switch to be used is the value of the index "move" for (Uint8 move = 0; move < SWITCH_COUNT; move++) { if ((key == g_key_defs[move][0]) || (key == g_key_defs[move][1])) { input_disable(move, NOMOUSE); } } // if they are releasing an ALT key if ((key == SDLK_LALT) || (key == SDLK_RALT)) { g_alt_pressed = false; } } // processes movements of the joystick void process_joystick_motion(SDL_Event *event) { static int x_axis_in_use = 0; // true if joystick is left or right static int y_axis_in_use = 0; // true if joystick is up or down // if they are moving along the verticle axis if (event->jaxis.axis == 1) { // if they're moving up if (event->jaxis.value < -JOY_AXIS_MID) { input_enable(SWITCH_UP, NOMOUSE); y_axis_in_use = 1; } // if they're moving down else if (event->jaxis.value > JOY_AXIS_MID) { input_enable(SWITCH_DOWN, NOMOUSE); y_axis_in_use = 1; } // if they just barely stopped moving up or down else if (y_axis_in_use == 1) { input_disable(SWITCH_UP, NOMOUSE); input_disable(SWITCH_DOWN, NOMOUSE); y_axis_in_use = 0; } } // end verticle axis // horizontal axis else { // if they're moving right if (event->jaxis.value > JOY_AXIS_MID) { input_enable(SWITCH_RIGHT, NOMOUSE); x_axis_in_use = 1; } // if they're moving left else if (event->jaxis.value < -JOY_AXIS_MID) { input_enable(SWITCH_LEFT, NOMOUSE); x_axis_in_use = 1; } // if they just barely stopped moving right or left else if (x_axis_in_use == 1) { input_disable(SWITCH_RIGHT, NOMOUSE); input_disable(SWITCH_LEFT, NOMOUSE); x_axis_in_use = 0; } } // end horizontal axis } // processes movement of the joystick hat void process_joystick_hat_motion(SDL_Event *event) { static Uint8 prev_hat_position = SDL_HAT_CENTERED; if ( ( event->jhat.value & SDL_HAT_UP ) && !( prev_hat_position & SDL_HAT_UP ) ) { // hat moved to the up position input_enable(SWITCH_UP, NOMOUSE); } else if ( !( event->jhat.value & SDL_HAT_UP ) && ( prev_hat_position & SDL_HAT_UP ) ) { // up hat released input_disable(SWITCH_UP, NOMOUSE); } if ( ( event->jhat.value & SDL_HAT_RIGHT ) && !( prev_hat_position & SDL_HAT_RIGHT ) ) { // hat moved to the right position input_enable(SWITCH_RIGHT, NOMOUSE); } else if ( !( event->jhat.value & SDL_HAT_RIGHT ) && ( prev_hat_position & SDL_HAT_RIGHT ) ) { // right hat released input_disable(SWITCH_RIGHT, NOMOUSE); } if ( ( event->jhat.value & SDL_HAT_DOWN ) && !( prev_hat_position & SDL_HAT_DOWN ) ) { // hat moved to the down position input_enable(SWITCH_DOWN, NOMOUSE); } else if ( !( event->jhat.value & SDL_HAT_DOWN ) && ( prev_hat_position & SDL_HAT_DOWN ) ) { // down hat released input_disable(SWITCH_DOWN, NOMOUSE); } if ( ( event->jhat.value & SDL_HAT_LEFT ) && !( prev_hat_position & SDL_HAT_LEFT ) ) { // hat moved to the left position input_enable(SWITCH_LEFT, NOMOUSE); } else if ( !( event->jhat.value & SDL_HAT_LEFT ) && ( prev_hat_position & SDL_HAT_LEFT ) ) { // left hat released input_disable(SWITCH_LEFT, NOMOUSE); } prev_hat_position = event->jhat.value; } // functions to help us avoid 'extern' statements bool get_consoledown() { return (g_consoledown); } void set_consoledown (bool value) { g_consoledown = value; } // draws console if it's down and if there's been enough of a delay void check_console_refresh() { static unsigned int console_refresh = 0; const unsigned int refresh_every = 125; // refreshes console every (this many) ms if (g_consoledown) { if (elapsed_ms_time(console_refresh) > refresh_every) { DrawConsole(); vid_blit(get_screen_blitter(), 0, 0); vid_flip(); console_refresh = refresh_ms_time(); } } } // if user has pressed a key/moved the joystick/pressed a button void input_enable(Uint8 move, int mouseID) { // first test universal input, then pass unknown input on to the game driver switch (move) { default: g_game->input_enable(move, mouseID); break; case SWITCH_RESET: g_game->reset(); break; case SWITCH_SCREENSHOT: g_ldp->request_screenshot(); break; case SWITCH_PAUSE: if (g_game->get_pause_key_flag()) // rdg g_game->toggle_game_pause(); break; case SWITCH_QUIT: set_quitflag(); break; case SWITCH_COIN1: case SWITCH_COIN2: // coin inputs are buffered to ensure that they are not dropped while the cpu is busy (such as during a seek) // therefore if the input is coin1 or coin2 AND we are using a real cpu (and not a program such as seektest) //if (get_cpu_hz(0) > 0) { add_coin_to_queue(true, move); } break; case SWITCH_CONSOLE: // we must not bring down the console if blitting is not allowed if (g_ldp->is_blitting_allowed()) { #ifdef CPU_DEBUG toggle_console(); #endif } break; } } // if user has released a key/released a button/moved joystick back to center position void input_disable(Uint8 move, int mouseID) { // don't send reset or screenshots key-ups to the individual games because they will return warnings that will alarm users if ((move != SWITCH_RESET) && (move != SWITCH_SCREENSHOT) && (move != SWITCH_QUIT) && (move != SWITCH_PAUSE)) { // coin inputs are buffered to ensure that they are not dropped while the cpu is busy (such as during a seek) // therefore if the input is coin1 or coin2 AND we are using a real cpu (and not a program such as seektest) //if (((move == SWITCH_COIN1) || (move == SWITCH_COIN2)) && (get_cpu_hz(0) > 0)) if ((move == SWITCH_COIN1) || (move == SWITCH_COIN2)) { add_coin_to_queue(false, move); } else { g_game->input_disable(move, mouseID); } } // else do nothing } inline void add_coin_to_queue(bool enabled, Uint8 val) { Uint64 total_cycles = 0;//get_total_cycles_executed(0); struct coin_input coin; coin.coin_enabled = enabled; coin.coin_val = val; // make sure that we are >= to the total cycles executed otherwise coin insertions will be really quick if (g_last_coin_cycle_used < total_cycles) { g_last_coin_cycle_used = total_cycles; } g_last_coin_cycle_used += g_sticky_coin_cycles; // advance to the next safe slot coin.cycles_when_to_enable = g_last_coin_cycle_used; // and assign this safe slot to this current coin g_coin_queue.push(coin); // add the coin to the queue ... } // added by JFA for -idleexit void reset_idle(void) { static bool bSoundOn = false; // At this time, the only way the sound will be muted is if -startsilent was passed via command line. // So the first key press should always unmute the sound. if (!bSoundOn) { bSoundOn = true; set_sound_mute(false); } idle_timer = refresh_ms_time(); } // end edit // primarily to disable joystick use if user wishes not to use one void set_use_joystick(bool val) { g_use_joystick = val; } bool set_mouse_mode(int thisMode) { bool result = false; if (g_game->get_mouse_enabled()) { if (g_mouse_mode == MANY_MOUSE) ManyMouse_Quit(); if (thisMode == MANY_MOUSE || thisMode == SDL_MOUSE) { g_mouse_mode = thisMode; result = true; memset(mouse_buttons_map, 0, 6); // Erase array if (thisMode == SDL_MOUSE) { mouse_buttons_map[0] = SWITCH_BUTTON1; // 0 (Left Button) mouse_buttons_map[1] = SWITCH_BUTTON3; // 1 (Middle Button) mouse_buttons_map[2] = SWITCH_BUTTON2; // 2 (Right Button) mouse_buttons_map[3] = SWITCH_BUTTON1; // 3 (Wheel Up) mouse_buttons_map[4] = SWITCH_BUTTON2; // 4 (Wheel Down) mouse_buttons_map[5] = SWITCH_MOUSE_DISCONNECT; // Dummy value so array matches in both branches. } else { mouse_buttons_map[0] = SWITCH_BUTTON3; // 0 (Left Button) mouse_buttons_map[1] = SWITCH_BUTTON1; // 1 (Middle Button) mouse_buttons_map[2] = SWITCH_BUTTON2; // 2 (Right Button) mouse_buttons_map[3] = SWITCH_MOUSE_SCROLL_UP; // 3 (Wheel Up) mouse_buttons_map[4] = SWITCH_MOUSE_SCROLL_DOWN; // 4 (Wheel Down) mouse_buttons_map[5] = SWITCH_MOUSE_DISCONNECT; // 4 (Wheel Down) ManyMouse_Init_Mice(); } // end if } // end if } // end if return result; }