Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  *
  9.  * SDL mouse driver
  10.  *
  11.  */
  12.  
  13. #include <string.h>
  14. #include <SDL.h>
  15.  
  16. #include "maths.h"
  17. #include "timer.h"
  18. #include "event.h"
  19. #include "window.h"
  20. #include "mouse.h"
  21. #include "playsave.h"
  22. #include "dxxerror.h"
  23. #include "args.h"
  24. #include "gr.h"
  25.  
  26. namespace dcx {
  27.  
  28. namespace {
  29.  
  30. struct flushable_mouseinfo
  31. {
  32.         int    delta_x, delta_y, delta_z;
  33.         int z;
  34. };
  35.  
  36. struct mouseinfo : flushable_mouseinfo
  37. {
  38.         int    x,y;
  39.         int    cursor_enabled;
  40.         fix64  cursor_time;
  41.         std::array<fix64, MOUSE_MAX_BUTTONS> time_lastpressed;
  42. };
  43.  
  44. }
  45.  
  46. static mouseinfo Mouse;
  47.  
  48. d_event_mousebutton::d_event_mousebutton(const event_type etype, const unsigned b) :
  49.         d_event{etype}, button(b)
  50. {
  51. }
  52.  
  53. void mouse_init(void)
  54. {
  55.         Mouse = {};
  56. }
  57.  
  58. void mouse_close(void)
  59. {
  60.         SDL_ShowCursor(SDL_ENABLE);
  61. }
  62.  
  63. static window_event_result maybe_send_z_move(const unsigned button)
  64. {
  65.         short dz;
  66.         if (button == MBTN_Z_UP)
  67.         {
  68.                 Mouse.delta_z += Z_SENSITIVITY;
  69.                 Mouse.z += Z_SENSITIVITY;
  70.                 dz = Z_SENSITIVITY;
  71.         }
  72.         else if (button == MBTN_Z_DOWN)
  73.         {
  74.                 Mouse.delta_z -= Z_SENSITIVITY;
  75.                 Mouse.z -= Z_SENSITIVITY;
  76.                 dz = -1*Z_SENSITIVITY;
  77.         }
  78.         else
  79.                 return window_event_result::ignored;
  80.         const d_event_mouse_moved event{EVENT_MOUSE_MOVED, 0, 0, dz};
  81.         return event_send(event);
  82. }
  83.  
  84. static window_event_result send_singleclick(const bool pressed, const unsigned button)
  85. {
  86.         const d_event_mousebutton event{pressed ? EVENT_MOUSE_BUTTON_DOWN : EVENT_MOUSE_BUTTON_UP, button};
  87.         con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_BUTTON_%s, button %d, coords %d,%d,%d",
  88.                            pressed ? "DOWN" : "UP", event.button, Mouse.x, Mouse.y, Mouse.z);
  89.         return event_send(event);
  90. }
  91.  
  92. static window_event_result maybe_send_doubleclick(const fix64 now, const unsigned button)
  93. {
  94.         auto &when = Mouse.time_lastpressed[button];
  95.         const auto then = when;
  96.         when = now;
  97.         if (now > then + F1_0/5)
  98.                 return window_event_result::ignored;
  99.         const d_event_mousebutton event{EVENT_MOUSE_DOUBLE_CLICKED, button};
  100.         con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_DOUBLE_CLICKED, button %d, coords %d,%d", button, Mouse.x, Mouse.y);
  101.         return event_send(event);
  102. }
  103.  
  104. window_event_result mouse_button_handler(const SDL_MouseButtonEvent *const mbe)
  105. {
  106.         window_event_result highest_result(window_event_result::ignored);
  107.  
  108.         if (unlikely(CGameArg.CtlNoMouse))
  109.                 return window_event_result::ignored;
  110.         // to bad, SDL buttons use a different mapping as descent expects,
  111.         // this is at least true and tested for the first three buttons
  112.         static const std::array<int, 17> button_remap{{
  113.                 MBTN_LEFT,
  114.                 MBTN_MIDDLE,
  115.                 MBTN_RIGHT,
  116.                 MBTN_Z_UP,
  117.                 MBTN_Z_DOWN,
  118.                 MBTN_PITCH_BACKWARD,
  119.                 MBTN_PITCH_FORWARD,
  120.                 MBTN_BANK_LEFT,
  121.                 MBTN_BANK_RIGHT,
  122.                 MBTN_HEAD_LEFT,
  123.                 MBTN_HEAD_RIGHT,
  124.                 MBTN_11,
  125.                 MBTN_12,
  126.                 MBTN_13,
  127.                 MBTN_14,
  128.                 MBTN_15,
  129.                 MBTN_16
  130.         }};
  131.         const unsigned button_idx = mbe->button - 1; // -1 since SDL seems to start counting at 1
  132.         if (unlikely(button_idx >= button_remap.size()))
  133.                 return window_event_result::ignored;
  134.  
  135.         const auto now = timer_query();
  136.         const auto button = button_remap[button_idx];
  137.         const auto mbe_state = mbe->state;
  138.         Mouse.cursor_time = now;
  139.  
  140.         const auto pressed = mbe_state != SDL_RELEASED;
  141.         if (pressed) {
  142.                 highest_result = maybe_send_z_move(button);
  143.         }
  144.         highest_result = std::max(send_singleclick(pressed, button), highest_result);
  145.         //Double-click support
  146.         if (pressed)
  147.         {
  148.                 highest_result = std::max(maybe_send_doubleclick(now, button), highest_result);
  149.         }
  150.  
  151.         return highest_result;
  152. }
  153.  
  154. window_event_result mouse_motion_handler(const SDL_MouseMotionEvent *const mme)
  155. {
  156.         Mouse.cursor_time = timer_query();
  157.         Mouse.x += mme->xrel;
  158.         Mouse.y += mme->yrel;
  159.        
  160.         // z handled in mouse_button_handler
  161.         const d_event_mouse_moved event{EVENT_MOUSE_MOVED, mme->xrel, mme->yrel, 0};
  162.        
  163.         //con_printf(CON_DEBUG, "Sending event EVENT_MOUSE_MOVED, relative motion %d,%d,%d",
  164.         //                 event.dx, event.dy, event.dz);
  165.         return event_send(event);
  166. }
  167.  
  168. void mouse_flush()      // clears all mice events...
  169. {
  170. //      event_poll();
  171.         static_cast<flushable_mouseinfo &>(Mouse) = {};
  172.         SDL_GetMouseState(&Mouse.x, &Mouse.y); // necessary because polling only gives us the delta.
  173. }
  174.  
  175. //========================================================================
  176. void mouse_get_pos( int *x, int *y, int *z )
  177. {
  178.         //event_poll();         // Have to assume this is called in event_process, because event_poll can cause a window to close (depending on what the user does)
  179.         *x=Mouse.x;
  180.         *y=Mouse.y;
  181.         *z=Mouse.z;
  182. }
  183.  
  184. window_event_result mouse_in_window(window *wind)
  185. {
  186.         auto &canv = window_get_canvas(*wind);
  187.         return  (static_cast<unsigned>(Mouse.x) - canv.cv_bitmap.bm_x <= canv.cv_bitmap.bm_w) &&
  188.                         (static_cast<unsigned>(Mouse.y) - canv.cv_bitmap.bm_y <= canv.cv_bitmap.bm_h) ? window_event_result::handled : window_event_result::ignored;
  189. }
  190.  
  191. void mouse_get_delta( int *dx, int *dy, int *dz )
  192. {
  193.         *dz = Mouse.delta_z;
  194.         Mouse.delta_x = 0;
  195.         Mouse.delta_y = 0;
  196.         Mouse.delta_z = 0;
  197.         SDL_GetRelativeMouseState(dx, dy);
  198. }
  199.  
  200. template <bool noactivate>
  201. static void mouse_change_cursor()
  202. {
  203.         Mouse.cursor_enabled = (!noactivate && !CGameArg.CtlNoMouse && !CGameArg.CtlNoCursor);
  204.         if (!Mouse.cursor_enabled)
  205.                 SDL_ShowCursor(SDL_DISABLE);
  206. }
  207.  
  208. void mouse_enable_cursor()
  209. {
  210.         mouse_change_cursor<false>();
  211. }
  212.  
  213. void mouse_disable_cursor()
  214. {
  215.         mouse_change_cursor<true>();
  216. }
  217.  
  218. // If we want to display/hide cursor, do so if not already and also hide it automatically after some time.
  219. void mouse_cursor_autohide()
  220. {
  221.         static fix64 hidden_time = 0;
  222.  
  223.         const auto is_showing = SDL_ShowCursor(SDL_QUERY);
  224.         int result;
  225.         if (Mouse.cursor_enabled)
  226.         {
  227.                 const auto now = timer_query();
  228.                 const auto cursor_time = Mouse.cursor_time;
  229.                 const auto recent_cursor_time = cursor_time + (F1_0*2) >= now;
  230.                 if (is_showing)
  231.                 {
  232.                         if (recent_cursor_time)
  233.                                 return;
  234.                         hidden_time = now;
  235.                         result = SDL_DISABLE;
  236.                 }
  237.                 else
  238.                 {
  239.                         if (!(recent_cursor_time && hidden_time + (F1_0/2) < now))
  240.                                 return;
  241.                         result = SDL_ENABLE;
  242.                 }
  243.         }
  244.         else
  245.         {
  246.                 if (!is_showing)
  247.                         return;
  248.                 result = SDL_DISABLE;
  249.         }
  250.         SDL_ShowCursor(result);
  251. }
  252.  
  253. }
  254.