123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- #include "EventLoop.h"
- #include "Event.h"
- #include "Object.h"
- #include "WindowManager.h"
- #include "AbstractScreen.h"
- #ifdef SERENITY
- #include "PS2MouseDevice.h"
- #include "Scheduler.h"
- #endif
- static EventLoop* s_mainEventLoop;
- void EventLoop::initialize()
- {
- s_mainEventLoop = nullptr;
- }
- EventLoop::EventLoop()
- {
- if (!s_mainEventLoop)
- s_mainEventLoop = this;
- }
- EventLoop::~EventLoop()
- {
- }
- EventLoop& EventLoop::main()
- {
- ASSERT(s_mainEventLoop);
- return *s_mainEventLoop;
- }
- int EventLoop::exec()
- {
- #ifdef SERENITY
- m_server_process = current;
- #endif
- m_running = true;
- for (;;) {
- if (m_queuedEvents.is_empty())
- waitForEvent();
- Vector<QueuedEvent> events;
- {
- InterruptDisabler disabler;
- events = move(m_queuedEvents);
- }
- for (auto& queuedEvent : events) {
- auto* receiver = queuedEvent.receiver;
- auto& event = *queuedEvent.event;
- //printf("EventLoop: Object{%p} event %u (%s)\n", receiver, (unsigned)event.type(), event.name());
- if (!receiver) {
- switch (event.type()) {
- case Event::Quit:
- ASSERT_NOT_REACHED();
- return 0;
- default:
- printf("event type %u with no receiver :(\n", event.type());
- ASSERT_NOT_REACHED();
- return 1;
- }
- } else {
- receiver->event(event);
- }
- }
- }
- }
- void EventLoop::postEvent(Object* receiver, OwnPtr<Event>&& event)
- {
- //printf("EventLoop::postEvent: {%u} << receiver=%p, event=%p\n", m_queuedEvents.size(), receiver, event.ptr());
- m_queuedEvents.append({ receiver, move(event) });
- }
- #ifdef SERENITY
- void EventLoop::waitForEvent()
- {
- auto& mouse = PS2MouseDevice::the();
- auto& screen = AbstractScreen::the();
- bool prev_left_button = screen.left_mouse_button_pressed();
- bool prev_right_button = screen.right_mouse_button_pressed();
- int dx = 0;
- int dy = 0;
- while (mouse.has_data_available_for_reading(*m_server_process)) {
- signed_byte data[3];
- ssize_t nread = mouse.read((byte*)data, 3);
- ASSERT(nread == 3);
- bool left_button = data[0] & 1;
- bool right_button = data[0] & 2;
- dx += data[1];
- dy += -data[2];
- if (left_button != prev_left_button || right_button != prev_right_button || !mouse.has_data_available_for_reading(*m_server_process)) {
- prev_left_button = left_button;
- prev_right_button = right_button;
- screen.on_receive_mouse_data(dx, dy, left_button, right_button);
- dx = 0;
- dy = 0;
- }
- }
- }
- #endif
- #ifdef USE_SDL
- static inline MouseButton toMouseButton(byte sdlButton)
- {
- if (sdlButton == 1)
- return MouseButton::Left;
- if (sdlButton == 2)
- return MouseButton::Middle;
- if (sdlButton == 3)
- return MouseButton::Right;
- ASSERT_NOT_REACHED();
- return MouseButton::None;
- }
- void EventLoop::handleKeyEvent(Event::Type type, const SDL_KeyboardEvent& sdlKey)
- {
- auto keyEvent = make<KeyEvent>(type, 0);
- int key = 0;
- switch (sdlKey.keysym.sym) {
- case SDLK_LEFT: key = KeyboardKey::LeftArrow; break;
- case SDLK_RIGHT: key = KeyboardKey::RightArrow; break;
- case SDLK_UP: key = KeyboardKey::UpArrow; break;
- case SDLK_DOWN: key = KeyboardKey::DownArrow; break;
- case SDLK_BACKSPACE: key = KeyboardKey::Backspace; break;
- case SDLK_RETURN: key = KeyboardKey::Return; break;
- }
- keyEvent->m_key = key;
- if (sdlKey.keysym.sym > SDLK_UNKNOWN && sdlKey.keysym.sym <= 'z') {
- char buf[] = { 0, 0 };
- char& ch = buf[0];
- ch = (char)sdlKey.keysym.sym;
- if (sdlKey.keysym.mod & KMOD_SHIFT) {
- if (ch >= 'a' && ch <= 'z') {
- ch &= ~0x20;
- } else {
- switch (ch) {
- case '1': ch = '!'; break;
- case '2': ch = '@'; break;
- case '3': ch = '#'; break;
- case '4': ch = '$'; break;
- case '5': ch = '%'; break;
- case '6': ch = '^'; break;
- case '7': ch = '&'; break;
- case '8': ch = '*'; break;
- case '9': ch = '('; break;
- case '0': ch = ')'; break;
- case '-': ch = '_'; break;
- case '=': ch = '+'; break;
- case '`': ch = '~'; break;
- case ',': ch = '<'; break;
- case '.': ch = '>'; break;
- case '/': ch = '?'; break;
- case '[': ch = '{'; break;
- case ']': ch = '}'; break;
- case '\\': ch = '|'; break;
- case '\'': ch = '"'; break;
- case ';': ch = ':'; break;
- }
- }
- }
- keyEvent->m_text = buf;
- }
- keyEvent->m_shift = sdlKey.keysym.mod & KMOD_SHIFT;
- keyEvent->m_ctrl = sdlKey.keysym.mod & KMOD_CTRL;
- keyEvent->m_alt = sdlKey.keysym.mod & KMOD_ALT;
- postEvent(&WindowManager::the(), move(keyEvent));
- }
- void EventLoop::waitForEvent()
- {
- SDL_Event sdlEvent;
- while (SDL_PollEvent(&sdlEvent) != 0) {
- switch (sdlEvent.type) {
- case SDL_QUIT:
- postEvent(nullptr, make<QuitEvent>());
- return;
- case SDL_WINDOWEVENT:
- if (sdlEvent.window.event == SDL_WINDOWEVENT_EXPOSED) {
- // Spam paint events whenever we get exposed.
- // This is obviously not ideal, but the SDL backend here is just a prototype anyway.
- postEvent(&WindowManager::the(), make<PaintEvent>());
- }
- return;
- case SDL_MOUSEMOTION:
- postEvent(&WindowManager::the(), make<MouseEvent>(Event::MouseMove, sdlEvent.motion.x, sdlEvent.motion.y));
- return;
- case SDL_MOUSEBUTTONDOWN:
- postEvent(&WindowManager::the(), make<MouseEvent>(Event::MouseDown, sdlEvent.button.x, sdlEvent.button.y, toMouseButton(sdlEvent.button.button)));
- return;
- case SDL_MOUSEBUTTONUP:
- postEvent(&WindowManager::the(), make<MouseEvent>(Event::MouseUp, sdlEvent.button.x, sdlEvent.button.y, toMouseButton(sdlEvent.button.button)));
- return;
- case SDL_KEYDOWN:
- handleKeyEvent(Event::KeyDown, sdlEvent.key);
- return;
- case SDL_KEYUP:
- handleKeyEvent(Event::KeyUp, sdlEvent.key);
- return;
- }
- }
- }
- #endif
|