emu_window_sdl2.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright 2016 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <SDL.h>
  5. #include "common/logging/log.h"
  6. #include "common/scm_rev.h"
  7. #include "core/core.h"
  8. #include "input_common/keyboard.h"
  9. #include "input_common/main.h"
  10. #include "input_common/motion_emu.h"
  11. #include "input_common/sdl/sdl.h"
  12. #include "yuzu_cmd/emu_window/emu_window_sdl2.h"
  13. EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
  14. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0) {
  15. LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting...");
  16. exit(1);
  17. }
  18. InputCommon::Init();
  19. SDL_SetMainReady();
  20. }
  21. EmuWindow_SDL2::~EmuWindow_SDL2() {
  22. InputCommon::Shutdown();
  23. SDL_Quit();
  24. }
  25. void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
  26. TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
  27. InputCommon::GetMotionEmu()->Tilt(x, y);
  28. }
  29. void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
  30. if (button == SDL_BUTTON_LEFT) {
  31. if (state == SDL_PRESSED) {
  32. TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0));
  33. } else {
  34. TouchReleased();
  35. }
  36. } else if (button == SDL_BUTTON_RIGHT) {
  37. if (state == SDL_PRESSED) {
  38. InputCommon::GetMotionEmu()->BeginTilt(x, y);
  39. } else {
  40. InputCommon::GetMotionEmu()->EndTilt();
  41. }
  42. }
  43. }
  44. std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const {
  45. int w, h;
  46. SDL_GetWindowSize(render_window, &w, &h);
  47. touch_x *= w;
  48. touch_y *= h;
  49. return {static_cast<unsigned>(std::max(std::round(touch_x), 0.0f)),
  50. static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))};
  51. }
  52. void EmuWindow_SDL2::OnFingerDown(float x, float y) {
  53. // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind
  54. // This isn't critical because the best we can do when we have that is to average them, like the
  55. // 3DS does
  56. const auto [px, py] = TouchToPixelPos(x, y);
  57. TouchPressed(px, py);
  58. }
  59. void EmuWindow_SDL2::OnFingerMotion(float x, float y) {
  60. const auto [px, py] = TouchToPixelPos(x, y);
  61. TouchMoved(px, py);
  62. }
  63. void EmuWindow_SDL2::OnFingerUp() {
  64. TouchReleased();
  65. }
  66. void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
  67. if (state == SDL_PRESSED) {
  68. InputCommon::GetKeyboard()->PressKey(key);
  69. } else if (state == SDL_RELEASED) {
  70. InputCommon::GetKeyboard()->ReleaseKey(key);
  71. }
  72. }
  73. bool EmuWindow_SDL2::IsOpen() const {
  74. return is_open;
  75. }
  76. void EmuWindow_SDL2::OnResize() {
  77. int width, height;
  78. SDL_GetWindowSize(render_window, &width, &height);
  79. UpdateCurrentFramebufferLayout(width, height);
  80. }
  81. void EmuWindow_SDL2::Fullscreen() {
  82. if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) {
  83. return;
  84. }
  85. LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError());
  86. // Try a different fullscreening method
  87. LOG_INFO(Frontend, "Attempting to use borderless fullscreen...");
  88. if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) {
  89. return;
  90. }
  91. LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError());
  92. // Fallback algorithm: Maximise window.
  93. // Works on all systems (unless something is seriously wrong), so no fallback for this one.
  94. LOG_INFO(Frontend, "Falling back on a maximised window...");
  95. SDL_MaximizeWindow(render_window);
  96. }
  97. void EmuWindow_SDL2::PollEvents() {
  98. SDL_Event event;
  99. // SDL_PollEvent returns 0 when there are no more events in the event queue
  100. while (SDL_PollEvent(&event)) {
  101. switch (event.type) {
  102. case SDL_WINDOWEVENT:
  103. switch (event.window.event) {
  104. case SDL_WINDOWEVENT_SIZE_CHANGED:
  105. case SDL_WINDOWEVENT_RESIZED:
  106. case SDL_WINDOWEVENT_MAXIMIZED:
  107. case SDL_WINDOWEVENT_RESTORED:
  108. OnResize();
  109. break;
  110. case SDL_WINDOWEVENT_MINIMIZED:
  111. case SDL_WINDOWEVENT_EXPOSED:
  112. is_shown = event.window.event == SDL_WINDOWEVENT_EXPOSED;
  113. OnResize();
  114. break;
  115. case SDL_WINDOWEVENT_CLOSE:
  116. is_open = false;
  117. break;
  118. }
  119. break;
  120. case SDL_KEYDOWN:
  121. case SDL_KEYUP:
  122. OnKeyEvent(static_cast<int>(event.key.keysym.scancode), event.key.state);
  123. break;
  124. case SDL_MOUSEMOTION:
  125. // ignore if it came from touch
  126. if (event.button.which != SDL_TOUCH_MOUSEID)
  127. OnMouseMotion(event.motion.x, event.motion.y);
  128. break;
  129. case SDL_MOUSEBUTTONDOWN:
  130. case SDL_MOUSEBUTTONUP:
  131. // ignore if it came from touch
  132. if (event.button.which != SDL_TOUCH_MOUSEID) {
  133. OnMouseButton(event.button.button, event.button.state, event.button.x,
  134. event.button.y);
  135. }
  136. break;
  137. case SDL_FINGERDOWN:
  138. OnFingerDown(event.tfinger.x, event.tfinger.y);
  139. break;
  140. case SDL_FINGERMOTION:
  141. OnFingerMotion(event.tfinger.x, event.tfinger.y);
  142. break;
  143. case SDL_FINGERUP:
  144. OnFingerUp();
  145. break;
  146. case SDL_QUIT:
  147. is_open = false;
  148. break;
  149. default:
  150. break;
  151. }
  152. }
  153. const u32 current_time = SDL_GetTicks();
  154. if (current_time > last_time + 2000) {
  155. const auto results = Core::System::GetInstance().GetAndResetPerfStats();
  156. const auto title = fmt::format(
  157. "yuzu {} | {}-{} | FPS: {:.0f} ({:.0%})", Common::g_build_fullname,
  158. Common::g_scm_branch, Common::g_scm_desc, results.game_fps, results.emulation_speed);
  159. SDL_SetWindowTitle(render_window, title.c_str());
  160. last_time = current_time;
  161. }
  162. }
  163. void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair<unsigned, unsigned> minimal_size) {
  164. SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second);
  165. }