int SDL_SetRelativeMouseMode(int index, SDL_bool enabled) { SDL_Mouse *mouse = SDL_GetMouse(index); if (!mouse) { return -1; } /* Flush pending mouse motion */ mouse->flush_motion = SDL_TRUE; SDL_PumpEvents(); mouse->flush_motion = SDL_FALSE; SDL_FilterEvents(FlushMouseMotion, mouse); /* Set the relative mode */ mouse->relative_mode = enabled; /* Update cursor visibility */ SDL_SetCursor(NULL); if (!enabled) { /* Restore the expected mouse position */ SDL_WarpMouseInWindow(mouse->focus, mouse->x, mouse->y); } return 0; }
/* * SDL.filterEvents(func) * * The func must have the following signature: * function filter(event) -> return false to disable * * Arguments: * func the function */ static int l_event_filterEvents(lua_State *L) { Filter f; luaL_checktype(L, 1, LUA_TFUNCTION); f.L = L; f.type = EventTypeFilter; /* Push the temporarly function */ lua_pushvalue(L, 1); f.ref = luaL_ref(L, LUA_REGISTRYINDEX); SDL_FilterEvents((SDL_EventFilter)eventFilter, &f); luaL_unref(L, LUA_REGISTRYINDEX, f.ref); return 0; }
void FilterEvents(void *data) { SDL_FilterEvents(eventFilter, data); }
int SDL_SendWindowEvent(SDL_Window * window, Uint8 windowevent, int data1, int data2) { int posted; if (!window) { return 0; } switch (windowevent) { case SDL_WINDOWEVENT_SHOWN: if (window->flags & SDL_WINDOW_SHOWN) { return 0; } window->flags &= ~SDL_WINDOW_HIDDEN; window->flags |= SDL_WINDOW_SHOWN; SDL_OnWindowShown(window); break; case SDL_WINDOWEVENT_HIDDEN: if (!(window->flags & SDL_WINDOW_SHOWN)) { return 0; } window->flags &= ~SDL_WINDOW_SHOWN; window->flags |= SDL_WINDOW_HIDDEN; SDL_OnWindowHidden(window); break; case SDL_WINDOWEVENT_MOVED: if (SDL_WINDOWPOS_ISUNDEFINED(data1) || SDL_WINDOWPOS_ISUNDEFINED(data2)) { return 0; } if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { window->windowed.x = data1; window->windowed.y = data2; } if (data1 == window->x && data2 == window->y) { return 0; } window->x = data1; window->y = data2; break; case SDL_WINDOWEVENT_RESIZED: if (!(window->flags & SDL_WINDOW_FULLSCREEN)) { window->windowed.w = data1; window->windowed.h = data2; } if (data1 == window->w && data2 == window->h) { return 0; } window->w = data1; window->h = data2; SDL_OnWindowResized(window); break; case SDL_WINDOWEVENT_MINIMIZED: if (window->flags & SDL_WINDOW_MINIMIZED) { return 0; } window->flags &= ~SDL_WINDOW_MAXIMIZED; window->flags |= SDL_WINDOW_MINIMIZED; SDL_OnWindowMinimized(window); break; case SDL_WINDOWEVENT_MAXIMIZED: if (window->flags & SDL_WINDOW_MAXIMIZED) { return 0; } window->flags &= ~SDL_WINDOW_MINIMIZED; window->flags |= SDL_WINDOW_MAXIMIZED; break; case SDL_WINDOWEVENT_RESTORED: if (!(window->flags & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED))) { return 0; } window->flags &= ~(SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED); SDL_OnWindowRestored(window); break; case SDL_WINDOWEVENT_ENTER: if (window->flags & SDL_WINDOW_MOUSE_FOCUS) { return 0; } window->flags |= SDL_WINDOW_MOUSE_FOCUS; SDL_OnWindowEnter(window); break; case SDL_WINDOWEVENT_LEAVE: if (!(window->flags & SDL_WINDOW_MOUSE_FOCUS)) { return 0; } window->flags &= ~SDL_WINDOW_MOUSE_FOCUS; SDL_OnWindowLeave(window); break; case SDL_WINDOWEVENT_FOCUS_GAINED: if (window->flags & SDL_WINDOW_INPUT_FOCUS) { return 0; } window->flags |= SDL_WINDOW_INPUT_FOCUS; SDL_OnWindowFocusGained(window); break; case SDL_WINDOWEVENT_FOCUS_LOST: if (!(window->flags & SDL_WINDOW_INPUT_FOCUS)) { return 0; } window->flags &= ~SDL_WINDOW_INPUT_FOCUS; SDL_OnWindowFocusLost(window); break; } /* Post the event, if desired */ posted = 0; if (SDL_GetEventState(SDL_WINDOWEVENT) == SDL_ENABLE) { SDL_Event event; event.type = SDL_WINDOWEVENT; event.window.event = windowevent; event.window.data1 = data1; event.window.data2 = data2; event.window.windowID = window->id; /* Fixes queue overflow with resize events that aren't processed */ if (windowevent == SDL_WINDOWEVENT_RESIZED) { SDL_FilterEvents(RemovePendingResizedEvents, &event); } if (windowevent == SDL_WINDOWEVENT_SIZE_CHANGED) { SDL_FilterEvents(RemovePendingSizeChangedEvents, &event); } if (windowevent == SDL_WINDOWEVENT_MOVED) { SDL_FilterEvents(RemovePendingMoveEvents, &event); } if (windowevent == SDL_WINDOWEVENT_EXPOSED) { SDL_FilterEvents(RemovePendingExposedEvents, &event); } posted = (SDL_PushEvent(&event) > 0); } if (windowevent == SDL_WINDOWEVENT_CLOSE) { if ( !window->prev && !window->next ) { /* This is the last window in the list so send the SDL_QUIT event */ SDL_SendQuit(); } } return (posted); }
void window::update() { input_state.advance_frame(); SDL_PumpEvents(); SDL_FilterEvents ( [] (void* userdata, SDL_Event* event) -> int { // Return 0 to remove an event from the queue, anything else to // keep the event in the queue. auto&& window = static_cast<class window*>(userdata); auto&& window_id = SDL_GetWindowID(window->handle.get()); switch (event->type) { case SDL_KEYDOWN: case SDL_KEYUP: { if (event->key.windowID != window_id) { return 1; } auto&& keycode = input::sdl_keycode_to_polygonist_keycode(event->key.keysym.sym); if (event->key.state == SDL_PRESSED) { window->input_state.key_press(keycode); } else if (event->key.state == SDL_RELEASED) { window->input_state.key_release(keycode); } break; } case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { if (event->button.windowID != window_id) { return 1; } auto&& button = input::sdl_button_to_polygonist_mouse_button(event->button.button); auto&& button_index = static_cast<size_t>(button); if (event->button.state == SDL_PRESSED) { window->input_state.mouse_press(button, event->button.clicks); } else if (event->button.state == SDL_RELEASED) { window->input_state.mouse_release(button); } break; } case SDL_MOUSEWHEEL: { if (event->wheel.windowID != window_id) { return 1; } // TODO: Use preciseX and preciseY after SDL 2.1 comes // out. https://bugzilla.libsdl.org/show_bug.cgi?id=2293 // TODO: do we need to DPI scale these values? if (event->wheel.direction == SDL_MOUSEWHEEL_FLIPPED) { window->input_state.mouse_wheel(-event->wheel.x, -event->wheel.y); } else { window->input_state.mouse_wheel(event->wheel.x, event->wheel.y); } break; } case SDL_TEXTINPUT: { if (event->text.windowID != window_id) { return 1; } window->input_state.text_input(event->text.text); break; } case SDL_TEXTEDITING: { if (event->edit.windowID != window_id) { return 1; } window->input_state.text_composition(event->edit.text, event->edit.start, event->edit.length); break; } case SDL_WINDOWEVENT: if (event->window.windowID != window_id) { return 1; } switch (event->window.event) { case SDL_WINDOWEVENT_MOVED: { auto&& x = static_cast<unsigned int>(event->window.data1); auto&& y = static_cast<unsigned int>(event->window.data2); window->move_event.fire(x, y); break; } case SDL_WINDOWEVENT_SIZE_CHANGED: { auto&& width = static_cast<unsigned int>(event->window.data1); auto&& height = static_cast<unsigned int>(event->window.data2); window->size = { width, height }; window->aspect_ratio = static_cast<float>(width) / static_cast<float>(height); window->cache_backbuffer_size(); window->resize_event.fire(width, height); break; } case SDL_WINDOWEVENT_CLOSE: window->close(); break; case SDL_WINDOWEVENT_ENTER: mouse_focus_window = window; break; case SDL_WINDOWEVENT_LEAVE: // mouse_focus_window = nullptr; break; case SDL_WINDOWEVENT_FOCUS_GAINED: keyboard_focus_window = window; break; case SDL_WINDOWEVENT_FOCUS_LOST: keyboard_focus_window = nullptr; break; } break; case SDL_SYSWMEVENT: return get_application_menu()->handle_event(event->syswm.msg); case SDL_QUIT: window->close(); // Don't remove quit events from the queue. All windows // need to handle them. return 1; } return 0; }, this ); // TODO: On Windows we can use WM_DPICHANGED to detect this. auto&& dpi = get_dpi(); if (this->dpi.get() != dpi) { this->dpi = dpi; dpi_change_event.fire(dpi.get_x(), dpi.get_y()); } mouse_focus_window = has_mouse_focus() ? this : mouse_focus_window; keyboard_focus_window = has_keyboard_focus() ? this : keyboard_focus_window; // Handles any pending deletions that must be done in the shared // graphics context and couldn't be done in the texture destructor. graphics::texture::free_textures_pending_deletion(); // We may not want to do this every frame. If it turns out that we're // freeing stuff too early, move this into some strategic places around // the code. We could do this on a timer or a memory threshold as well. asset::free_unused_assets(); }