void Pi::HandleEvents() { PROFILE_SCOPED() SDL_Event event; // XXX for most keypresses SDL will generate KEYUP/KEYDOWN and TEXTINPUT // events. keybindings run off KEYUP/KEYDOWN. the console is opened/closed // via keybinding. the console TextInput widget uses TEXTINPUT events. thus // after switching the console, the stray TEXTINPUT event causes the // console key (backtick) to appear in the text entry field. we hack around // this by setting this flag if the console was switched. if its set, we // swallow the TEXTINPUT event this hack must remain until we have a // unified input system bool skipTextInput = false; Pi::mouseMotion[0] = Pi::mouseMotion[1] = 0; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { if (Pi::game) Pi::EndGame(); Pi::Quit(); } if (skipTextInput && event.type == SDL_TEXTINPUT) { skipTextInput = false; continue; } if (ui->DispatchSDLEvent(event)) continue; bool consoleActive = Pi::IsConsoleActive(); if (!consoleActive) KeyBindings::DispatchSDLEvent(&event); else KeyBindings::toggleLuaConsole.CheckSDLEventAndDispatch(&event); if (consoleActive != Pi::IsConsoleActive()) { skipTextInput = true; continue; } if (Pi::IsConsoleActive()) continue; Gui::HandleSDLEvent(&event); switch (event.type) { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) { if (Pi::game) { // only accessible once game started if (currentView != 0) { if (currentView != Pi::game->GetSettingsView()) { Pi::game->SetTimeAccel(Game::TIMEACCEL_PAUSED); SetView(Pi::game->GetSettingsView()); } else { Pi::game->RequestTimeAccel(Game::TIMEACCEL_1X); SetView(Pi::player->IsDead() ? static_cast<View*>(Pi::game->GetDeathView()) : static_cast<View*>(Pi::game->GetWorldView())); } } } break; } // special keys. LCTRL+turd if ((KeyState(SDLK_LCTRL) || (KeyState(SDLK_RCTRL)))) { switch (event.key.keysym.sym) { case SDLK_q: // Quit if (Pi::game) Pi::EndGame(); Pi::Quit(); break; case SDLK_PRINTSCREEN: // print case SDLK_KP_MULTIPLY: // screen { char buf[256]; const time_t t = time(0); struct tm *_tm = localtime(&t); strftime(buf, sizeof(buf), "screenshot-%Y%m%d-%H%M%S.png", _tm); Graphics::ScreendumpState sd; Pi::renderer->Screendump(sd); write_screenshot(sd, buf); break; } #if WITH_DEVKEYS case SDLK_i: // Toggle Debug info Pi::showDebugInfo = !Pi::showDebugInfo; break; #ifdef PIONEER_PROFILER case SDLK_p: // alert it that we want to profile if (KeyState(SDLK_LSHIFT) || KeyState(SDLK_RSHIFT)) Pi::doProfileOne = true; else { Pi::doProfileSlow = !Pi::doProfileSlow; Output("slow frame profiling %s\n", Pi::doProfileSlow ? "enabled" : "disabled"); } break; #endif case SDLK_F12: { if(Pi::game) { vector3d dir = -Pi::player->GetOrient().VectorZ(); /* add test object */ if (KeyState(SDLK_RSHIFT)) { Missile *missile = new Missile(ShipType::MISSILE_GUIDED, Pi::player); missile->SetOrient(Pi::player->GetOrient()); missile->SetFrame(Pi::player->GetFrame()); missile->SetPosition(Pi::player->GetPosition()+50.0*dir); missile->SetVelocity(Pi::player->GetVelocity()); game->GetSpace()->AddBody(missile); missile->AIKamikaze(Pi::player->GetCombatTarget()); } else if (KeyState(SDLK_LSHIFT)) { SpaceStation *s = static_cast<SpaceStation*>(Pi::player->GetNavTarget()); if (s) { Ship *ship = new Ship(ShipType::POLICE); int port = s->GetFreeDockingPort(ship); if (port != -1) { Output("Putting ship into station\n"); // Make police ship intent on killing the player ship->AIKill(Pi::player); ship->SetFrame(Pi::player->GetFrame()); ship->SetDockedWith(s, port); game->GetSpace()->AddBody(ship); } else { delete ship; Output("No docking ports free dude\n"); } } else { Output("Select a space station...\n"); } } else { Ship *ship = new Ship(ShipType::POLICE); if( KeyState(SDLK_LCTRL) ) ship->AIFlyTo(Pi::player); // a less lethal option else ship->AIKill(Pi::player); // a really lethal option! lua_State *l = Lua::manager->GetLuaState(); pi_lua_import(l, "Equipment"); LuaTable equip(l, -1); LuaObject<Ship>::CallMethod<>(ship, "AddEquip", equip.Sub("laser").Sub("pulsecannon_dual_1mw")); LuaObject<Ship>::CallMethod<>(ship, "AddEquip", equip.Sub("misc").Sub("laser_cooling_booster")); LuaObject<Ship>::CallMethod<>(ship, "AddEquip", equip.Sub("misc").Sub("atmospheric_shielding")); lua_pop(l, 5); ship->SetFrame(Pi::player->GetFrame()); ship->SetPosition(Pi::player->GetPosition()+100.0*dir); ship->SetVelocity(Pi::player->GetVelocity()); ship->UpdateEquipStats(); game->GetSpace()->AddBody(ship); } } break; } #endif /* DEVKEYS */ #if WITH_OBJECTVIEWER case SDLK_F10: Pi::SetView(Pi::game->GetObjectViewerView()); break; #endif case SDLK_F11: // XXX only works on X11 //SDL_WM_ToggleFullScreen(Pi::scrSurface); #if WITH_DEVKEYS renderer->ReloadShaders(); #endif break; case SDLK_F9: // Quicksave { if(Pi::game) { if (Pi::game->IsHyperspace()) Pi::game->log->Add(Lang::CANT_SAVE_IN_HYPERSPACE); else { const std::string name = "_quicksave"; const std::string path = FileSystem::JoinPath(GetSaveDir(), name); try { Game::SaveGame(name, Pi::game); Pi::game->log->Add(Lang::GAME_SAVED_TO + path); } catch (CouldNotOpenFileException) { Pi::game->log->Add(stringf(Lang::COULD_NOT_OPEN_FILENAME, formatarg("path", path))); } catch (CouldNotWriteToFileException) { Pi::game->log->Add(Lang::GAME_SAVE_CANNOT_WRITE); } } } break; } default: break; // This does nothing but it stops the compiler warnings } } Pi::keyState[event.key.keysym.sym] = true; Pi::keyModState = event.key.keysym.mod; Pi::onKeyPress.emit(&event.key.keysym); break; case SDL_KEYUP: Pi::keyState[event.key.keysym.sym] = false; Pi::keyModState = event.key.keysym.mod; Pi::onKeyRelease.emit(&event.key.keysym); break; case SDL_MOUSEBUTTONDOWN: if (event.button.button < COUNTOF(Pi::mouseButton)) { Pi::mouseButton[event.button.button] = 1; Pi::onMouseButtonDown.emit(event.button.button, event.button.x, event.button.y); } break; case SDL_MOUSEBUTTONUP: if (event.button.button < COUNTOF(Pi::mouseButton)) { Pi::mouseButton[event.button.button] = 0; Pi::onMouseButtonUp.emit(event.button.button, event.button.x, event.button.y); } break; case SDL_MOUSEWHEEL: Pi::onMouseWheel.emit(event.wheel.y > 0); // true = up break; case SDL_MOUSEMOTION: Pi::mouseMotion[0] += event.motion.xrel; Pi::mouseMotion[1] += event.motion.yrel; // SDL_GetRelativeMouseState(&Pi::mouseMotion[0], &Pi::mouseMotion[1]); break; case SDL_JOYAXISMOTION: if (!joysticks[event.jaxis.which].joystick) break; if (event.jaxis.value == -32768) joysticks[event.jaxis.which].axes[event.jaxis.axis] = 1.f; else joysticks[event.jaxis.which].axes[event.jaxis.axis] = -event.jaxis.value / 32767.f; break; case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: if (!joysticks[event.jaxis.which].joystick) break; joysticks[event.jbutton.which].buttons[event.jbutton.button] = event.jbutton.state != 0; break; case SDL_JOYHATMOTION: if (!joysticks[event.jaxis.which].joystick) break; joysticks[event.jhat.which].hats[event.jhat.hat] = event.jhat.value; break; } } }
void Pi::HandleKeyDown(SDL_Keysym *key) { if (key->sym == SDLK_ESCAPE) { if (Pi::game) { // only accessible once game started HandleEscKey(); } return; } const bool CTRL = input.KeyState(SDLK_LCTRL) || input.KeyState(SDLK_RCTRL); // special keys. if (CTRL) { switch (key->sym) { case SDLK_q: // Quit Pi::RequestQuit(); break; case SDLK_PRINTSCREEN: // print case SDLK_KP_MULTIPLY: // screen { char buf[256]; const time_t t = time(0); struct tm *_tm = localtime(&t); strftime(buf, sizeof(buf), "screenshot-%Y%m%d-%H%M%S.png", _tm); Graphics::ScreendumpState sd; Pi::renderer->Screendump(sd); write_screenshot(sd, buf); break; } case SDLK_SCROLLLOCK: // toggle video recording Pi::isRecordingVideo = !Pi::isRecordingVideo; if (Pi::isRecordingVideo) { char videoName[256]; const time_t t = time(0); struct tm *_tm = localtime(&t); strftime(videoName, sizeof(videoName), "pioneer-%Y%m%d-%H%M%S", _tm); const std::string dir = "videos"; FileSystem::userFiles.MakeDirectory(dir); const std::string fname = FileSystem::JoinPathBelow(FileSystem::userFiles.GetRoot() + "/" + dir, videoName); Output("Video Recording started to %s.\n", fname.c_str()); // start ffmpeg telling it to expect raw rgba 720p-60hz frames // -i - tells it to read frames from stdin // if given no frame rate (-r 60), it will just use vfr char cmd[256] = { 0 }; snprintf(cmd, sizeof(cmd), "ffmpeg -f rawvideo -pix_fmt rgba -s %dx%d -i - -threads 0 -preset fast -y -pix_fmt yuv420p -crf 21 -vf vflip %s.mp4", config->Int("ScrWidth"), config->Int("ScrHeight"), fname.c_str()); // open pipe to ffmpeg's stdin in binary write mode #if defined(_MSC_VER) || defined(__MINGW32__) Pi::ffmpegFile = _popen(cmd, "wb"); #else Pi::ffmpegFile = _popen(cmd, "w"); #endif } else { Output("Video Recording ended.\n"); if (Pi::ffmpegFile != nullptr) { _pclose(Pi::ffmpegFile); Pi::ffmpegFile = nullptr; } } break; #if WITH_DEVKEYS case SDLK_i: // Toggle Debug info Pi::showDebugInfo = !Pi::showDebugInfo; break; #ifdef PIONEER_PROFILER case SDLK_p: // alert it that we want to profile if (input.KeyState(SDLK_LSHIFT) || input.KeyState(SDLK_RSHIFT)) Pi::doProfileOne = true; else { Pi::doProfileSlow = !Pi::doProfileSlow; Output("slow frame profiling %s\n", Pi::doProfileSlow ? "enabled" : "disabled"); } break; #endif case SDLK_F12: { if (Pi::game) { vector3d dir = -Pi::player->GetOrient().VectorZ(); /* add test object */ if (input.KeyState(SDLK_RSHIFT)) { Missile *missile = new Missile(ShipType::MISSILE_GUIDED, Pi::player); missile->SetOrient(Pi::player->GetOrient()); missile->SetFrame(Pi::player->GetFrame()); missile->SetPosition(Pi::player->GetPosition() + 50.0 * dir); missile->SetVelocity(Pi::player->GetVelocity()); game->GetSpace()->AddBody(missile); missile->AIKamikaze(Pi::player->GetCombatTarget()); } else if (input.KeyState(SDLK_LSHIFT)) { SpaceStation *s = static_cast<SpaceStation *>(Pi::player->GetNavTarget()); if (s) { Ship *ship = new Ship(ShipType::POLICE); int port = s->GetFreeDockingPort(ship); if (port != -1) { Output("Putting ship into station\n"); // Make police ship intent on killing the player ship->AIKill(Pi::player); ship->SetFrame(Pi::player->GetFrame()); ship->SetDockedWith(s, port); game->GetSpace()->AddBody(ship); } else { delete ship; Output("No docking ports free dude\n"); } } else { Output("Select a space station...\n"); } } else { Ship *ship = new Ship(ShipType::POLICE); if (!input.KeyState(SDLK_LALT)) { //Left ALT = no AI if (!input.KeyState(SDLK_LCTRL)) ship->AIFlyTo(Pi::player); // a less lethal option else ship->AIKill(Pi::player); // a really lethal option! } lua_State *l = Lua::manager->GetLuaState(); pi_lua_import(l, "Equipment"); LuaTable equip(l, -1); LuaObject<Ship>::CallMethod<>(ship, "AddEquip", equip.Sub("laser").Sub("pulsecannon_dual_1mw")); LuaObject<Ship>::CallMethod<>(ship, "AddEquip", equip.Sub("misc").Sub("laser_cooling_booster")); LuaObject<Ship>::CallMethod<>(ship, "AddEquip", equip.Sub("misc").Sub("atmospheric_shielding")); lua_pop(l, 5); ship->SetFrame(Pi::player->GetFrame()); ship->SetPosition(Pi::player->GetPosition() + 100.0 * dir); ship->SetVelocity(Pi::player->GetVelocity()); ship->UpdateEquipStats(); game->GetSpace()->AddBody(ship); } } break; } #endif /* DEVKEYS */ #if WITH_OBJECTVIEWER case SDLK_F10: Pi::SetView(Pi::game->GetObjectViewerView()); break; #endif case SDLK_F11: // XXX only works on X11 //SDL_WM_ToggleFullScreen(Pi::scrSurface); #if WITH_DEVKEYS renderer->ReloadShaders(); #endif break; case SDLK_F9: // Quicksave { if (Pi::game) { if (Pi::game->IsHyperspace()) Pi::game->log->Add(Lang::CANT_SAVE_IN_HYPERSPACE); else { const std::string name = "_quicksave"; const std::string path = FileSystem::JoinPath(GetSaveDir(), name); try { Game::SaveGame(name, Pi::game); Pi::game->log->Add(Lang::GAME_SAVED_TO + path); } catch (CouldNotOpenFileException) { Pi::game->log->Add(stringf(Lang::COULD_NOT_OPEN_FILENAME, formatarg("path", path))); } catch (CouldNotWriteToFileException) { Pi::game->log->Add(Lang::GAME_SAVE_CANNOT_WRITE); } } } break; } default: break; // This does nothing but it stops the compiler warnings } } }