src/video/mir/SDL_mirevents.c
author Brandon Schaefer
Tue, 07 Jun 2016 09:01:23 -0700
changeset 10180 7356b2938fba
parent 10089 25fda20d0173
child 10299 5a45e29a6ea7
permissions -rw-r--r--
MIR: Support relative mouse mode
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /*
    23   Contributed by Brandon Schaefer, <brandon.schaefer@canonical.com>
    24 */
    25 
    26 #include "../../SDL_internal.h"
    27 
    28 #if SDL_VIDEO_DRIVER_MIR
    29 
    30 #include "../../events/SDL_events_c.h"
    31 #include "../../events/SDL_keyboard_c.h"
    32 #include "../../events/SDL_touch_c.h"
    33 #include "../../events/scancodes_xfree86.h"
    34 
    35 #include "SDL_mirevents.h"
    36 #include "SDL_mirwindow.h"
    37 
    38 #include <xkbcommon/xkbcommon.h>
    39 
    40 #include "SDL_mirdyn.h"
    41 
    42 static void
    43 HandleKeyText(int32_t key_code)
    44 {
    45     char text[8];
    46     int size = 0;
    47 
    48     size = MIR_xkb_keysym_to_utf8(key_code, text, sizeof text);
    49 
    50     if (size > 0) {
    51         text[size] = '\0';
    52         SDL_SendKeyboardText(text);
    53     }
    54 }
    55 
    56 static void
    57 CheckKeyboardFocus(SDL_Window* sdl_window)
    58 {
    59     SDL_Window* keyboard_window = SDL_GetKeyboardFocus();
    60 
    61     if (sdl_window && keyboard_window != sdl_window)
    62         SDL_SetKeyboardFocus(sdl_window);
    63 }
    64 
    65 
    66 /* FIXME
    67    Mir still needs to implement its IM API, for now we assume
    68    a single key press produces a character.
    69 */
    70 static void
    71 HandleKeyEvent(MirKeyboardEvent const* key_event, SDL_Window* window)
    72 {
    73     xkb_keysym_t key_code;
    74     Uint8 key_state;
    75     int event_scancode;
    76     uint32_t sdl_scancode = SDL_SCANCODE_UNKNOWN;
    77 
    78     MirKeyboardAction action = MIR_mir_keyboard_event_action(key_event);
    79 
    80     key_state      = SDL_PRESSED;
    81     key_code       = MIR_mir_keyboard_event_key_code(key_event);
    82     event_scancode = MIR_mir_keyboard_event_scan_code(key_event);
    83 
    84     if (action == mir_keyboard_action_up)
    85         key_state = SDL_RELEASED;
    86 
    87     CheckKeyboardFocus(window);
    88 
    89     if (event_scancode < SDL_arraysize(xfree86_scancode_table2))
    90         sdl_scancode = xfree86_scancode_table2[event_scancode];
    91 
    92     if (sdl_scancode != SDL_SCANCODE_UNKNOWN)
    93         SDL_SendKeyboardKey(key_state, sdl_scancode);
    94 
    95     if (key_state == SDL_PRESSED)
    96         HandleKeyText(key_code);
    97 }
    98 
    99 static void
   100 HandleMouseButton(SDL_Window* sdl_window, Uint8 state, MirPointerEvent const* pointer)
   101 {
   102     uint32_t sdl_button           = SDL_BUTTON_LEFT;
   103     MirPointerButton button_state = mir_pointer_button_primary;
   104 
   105     static uint32_t old_button_states = 0;
   106     uint32_t new_button_states = MIR_mir_pointer_event_buttons(pointer);
   107 
   108     // XOR on our old button states vs our new states to get the newley pressed/released button
   109     button_state = new_button_states ^ old_button_states;
   110 
   111     switch (button_state) {
   112         case mir_pointer_button_primary:
   113             sdl_button = SDL_BUTTON_LEFT;
   114             break;
   115         case mir_pointer_button_secondary:
   116             sdl_button = SDL_BUTTON_RIGHT;
   117             break;
   118         case mir_pointer_button_tertiary:
   119             sdl_button = SDL_BUTTON_MIDDLE;
   120             break;
   121         case mir_pointer_button_forward:
   122             sdl_button = SDL_BUTTON_X1;
   123             break;
   124         case mir_pointer_button_back:
   125             sdl_button = SDL_BUTTON_X2;
   126             break;
   127         default:
   128             break;
   129     }
   130 
   131     old_button_states = new_button_states;
   132 
   133     SDL_SendMouseButton(sdl_window, 0, state, sdl_button);
   134 }
   135 
   136 static void
   137 HandleMouseMotion(SDL_Window* sdl_window, int x, int y)
   138 {
   139     SDL_Mouse* mouse = SDL_GetMouse();
   140     SDL_SendMouseMotion(sdl_window, 0, mouse->relative_mode, x, y);
   141 }
   142 
   143 static void
   144 HandleTouchPress(int device_id, int source_id, SDL_bool down, float x, float y, float pressure)
   145 {
   146     SDL_SendTouch(device_id, source_id, down, x, y, pressure);
   147 }
   148 
   149 static void
   150 HandleTouchMotion(int device_id, int source_id, float x, float y, float pressure)
   151 {
   152     SDL_SendTouchMotion(device_id, source_id, x, y, pressure);
   153 }
   154 
   155 static void
   156 HandleMouseScroll(SDL_Window* sdl_window, int hscroll, int vscroll)
   157 {
   158     SDL_SendMouseWheel(sdl_window, 0, hscroll, vscroll, SDL_MOUSEWHEEL_NORMAL);
   159 }
   160 
   161 static void
   162 AddTouchDevice(int device_id)
   163 {
   164     if (SDL_AddTouch(device_id, "") < 0)
   165         SDL_SetError("Error: can't add touch %s, %d", __FILE__, __LINE__);
   166 }
   167 
   168 static void
   169 HandleTouchEvent(MirTouchEvent const* touch, int device_id, SDL_Window* sdl_window)
   170 {
   171     int i, point_count;
   172     point_count = MIR_mir_touch_event_point_count(touch);
   173 
   174     AddTouchDevice(device_id);
   175 
   176     for (i = 0; i < point_count; i++) {
   177         int id = MIR_mir_touch_event_id(touch, i);
   178 
   179         int width  = sdl_window->w;
   180         int height = sdl_window->h;
   181 
   182         float x = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_x);
   183         float y = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_y);
   184 
   185         float n_x = x / width;
   186         float n_y = y / height;
   187 
   188         float pressure = MIR_mir_touch_event_axis_value(touch, i, mir_touch_axis_pressure);
   189 
   190         switch (MIR_mir_touch_event_action(touch, i)) {
   191             case mir_touch_action_up:
   192                 HandleTouchPress(device_id, id, SDL_FALSE, n_x, n_y, pressure);
   193                 break;
   194             case mir_touch_action_down:
   195                 HandleTouchPress(device_id, id, SDL_TRUE, n_x, n_y, pressure);
   196                 break;
   197             case mir_touch_action_change:
   198                 HandleTouchMotion(device_id, id, n_x, n_y, pressure);
   199                 break;
   200         }
   201     }
   202 }
   203 
   204 static void
   205 HandleMouseEvent(MirPointerEvent const* pointer, SDL_Window* sdl_window)
   206 {
   207     SDL_SetMouseFocus(sdl_window);
   208 
   209     switch (MIR_mir_pointer_event_action(pointer)) {
   210         case mir_pointer_action_button_down:
   211             HandleMouseButton(sdl_window, SDL_PRESSED, pointer);
   212             break;
   213         case mir_pointer_action_button_up:
   214             HandleMouseButton(sdl_window, SDL_RELEASED, pointer);
   215             break;
   216         case mir_pointer_action_motion: {
   217             int x, y;
   218             int hscroll, vscroll;
   219             SDL_Mouse* mouse = SDL_GetMouse();
   220             x = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_x);
   221             y = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_y);
   222 
   223             if (mouse && (mouse->x != x || mouse->y != y)) {
   224                 if (mouse->relative_mode) {
   225                     int relative_x = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_relative_x);
   226                     int relative_y = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_relative_y);
   227                     HandleMouseMotion(sdl_window, relative_x, relative_y);
   228                 }
   229                 else {
   230                     HandleMouseMotion(sdl_window, x, y);
   231                 }
   232             }
   233 
   234             hscroll = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_hscroll);
   235             vscroll = MIR_mir_pointer_event_axis_value(pointer, mir_pointer_axis_vscroll);
   236             if (vscroll != 0 || hscroll != 0)
   237                 HandleMouseScroll(sdl_window, hscroll, vscroll);
   238         }
   239             break;
   240         case mir_pointer_action_leave:
   241             SDL_SetMouseFocus(NULL);
   242             break;
   243         case mir_pointer_action_enter:
   244         default:
   245             break;
   246     }
   247 }
   248 
   249 static void
   250 MIR_HandleInput(MirInputEvent const* input_event, SDL_Window* window)
   251 {
   252     switch (MIR_mir_input_event_get_type(input_event)) {
   253         case (mir_input_event_type_key):
   254             HandleKeyEvent(MIR_mir_input_event_get_keyboard_event(input_event), window);
   255             break;
   256         case (mir_input_event_type_pointer):
   257             HandleMouseEvent(MIR_mir_input_event_get_pointer_event(input_event), window);
   258             break;
   259         case (mir_input_event_type_touch):
   260             HandleTouchEvent(MIR_mir_input_event_get_touch_event(input_event),
   261                              MIR_mir_input_event_get_device_id(input_event),
   262                              window);
   263             break;
   264         default:
   265             break;
   266     }
   267 }
   268 
   269 static void
   270 MIR_HandleResize(MirResizeEvent const* resize_event, SDL_Window* window)
   271 {
   272     int new_w = MIR_mir_resize_event_get_width (resize_event);
   273     int new_h = MIR_mir_resize_event_get_height(resize_event);
   274 
   275     int old_w = window->w;
   276     int old_h = window->h;
   277 
   278     if (new_w != old_w || new_h != old_h)
   279         SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, new_w, new_h);
   280 }
   281 
   282 void
   283 MIR_HandleEvent(MirSurface* surface, MirEvent const* ev, void* context)
   284 {
   285     MirEventType event_type = MIR_mir_event_get_type(ev);
   286     SDL_Window* window      = (SDL_Window*)context;
   287 
   288     if (window) {
   289         switch (event_type) {
   290             case (mir_event_type_input):
   291                 MIR_HandleInput(MIR_mir_event_get_input_event(ev), window);
   292                 break;
   293             case (mir_event_type_resize):
   294                 MIR_HandleResize(MIR_mir_event_get_resize_event(ev), window);
   295                 break;
   296             default:
   297                 break;
   298         }
   299     }
   300 }
   301 
   302 #endif /* SDL_VIDEO_DRIVER_MIR */
   303 
   304 /* vi: set ts=4 sw=4 expandtab: */