SciEvent EventManager::getScummVMEvent() { SciEvent input = { SCI_EVENT_NONE, 0, 0, 0, Common::Point(0, 0) }; SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, 0, Common::Point(0, 0) }; Common::EventManager *em = g_system->getEventManager(); Common::Event ev; bool found = em->pollEvent(ev); // Don't generate events for mouse movement while (found && ev.type == Common::EVENT_MOUSEMOVE) found = em->pollEvent(ev); // Save the mouse position // // We call getMousePos of the event manager here, since we also want to // store the mouse position in case of keyboard events, which do not feature // any mouse position information itself. // This should be safe, since the mouse position in the event manager should // only be updated when a mouse related event has been taken from the queue // via pollEvent. // We also adjust the position based on the scaling of the screen. Common::Point mousePos = em->getMousePos(); g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); noEvent.mousePos = input.mousePos = mousePos; if (!found || ev.type == Common::EVENT_MOUSEMOVE) { int modifiers = em->getModifierState(); noEvent.modifiers = ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) | ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) | ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0); return noEvent; } if (ev.type == Common::EVENT_QUIT) { input.type = SCI_EVENT_QUIT; return input; } // Handle mouse events for (int i = 0; i < ARRAYSIZE(mouseEventMappings); i++) { if (mouseEventMappings[i].commonType == ev.type) { input.type = mouseEventMappings[i].sciType; input.data = mouseEventMappings[i].data; return input; } } // If we reached here, make sure that it's a keydown event if (ev.type != Common::EVENT_KEYDOWN) return noEvent; // Check for Control-D (debug console) if (ev.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && ev.kbd.keycode == Common::KEYCODE_d) { // Open debug console Console *con = g_sci->getSciDebugger(); con->attach(); return noEvent; } // Process keyboard events int modifiers = em->getModifierState(); bool numlockOn = (ev.kbd.flags & Common::KBD_NUM); input.data = ev.kbd.keycode; input.character = ev.kbd.ascii; input.type = SCI_EVENT_KEYBOARD; input.modifiers = ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) | ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) | ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0); // Caps lock and Scroll lock have been removed, cause we already handle upper // case keys ad Scroll lock doesn't seem to be used anywhere //((ev.kbd.flags & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) | //((ev.kbd.flags & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) | if ((input.character) && (input.character <= 0xFF)) { // Directly accept most common keys without conversion if ((input.character >= 0x80) && (input.character <= 0xFF)) { // If there is no extended font, we will just clear the // current event. // Sierra SCI actually accepted those characters, but // didn't display them inside text edit controls because // the characters were missing inside the font(s). // We filter them out for non-multilingual games because // of that. if (!_fontIsExtended) return noEvent; // Convert 8859-1 characters to DOS (cp850/437) for // multilingual SCI01 games input.character = codepagemap_88591toDOS[input.character & 0x7f]; } if (input.data == Common::KEYCODE_TAB) { input.character = input.data = SCI_KEY_TAB; if (modifiers & Common::KBD_SHIFT) input.character = SCI_KEY_SHIFT_TAB; } if (input.data == Common::KEYCODE_DELETE) input.data = input.character = SCI_KEY_DELETE; } else if ((input.data >= Common::KEYCODE_F1) && input.data <= Common::KEYCODE_F10) { // SCI_K_F1 == 59 << 8 // SCI_K_SHIFT_F1 == 84 << 8 input.character = input.data = SCI_KEY_F1 + ((input.data - Common::KEYCODE_F1)<<8); if (modifiers & Common::KBD_SHIFT) input.character = input.data + 0x1900; } else { // Special keys that need conversion for (int i = 0; i < ARRAYSIZE(keyMappings); i++) { if (keyMappings[i].scummVMKey == ev.kbd.keycode) { input.character = input.data = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff; break; } } } // When Ctrl AND Alt are pressed together with a regular key, Linux will give us control-key, Windows will give // us the actual key. My opinion is that windows is right, because under DOS the keys worked the same, anyway // we support the other case as well if ((modifiers & Common::KBD_ALT) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' // Scancodify if appropriate if (modifiers & Common::KBD_ALT) input.character = altify(input.character); if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (modifiers & Common::KBD_CTRL) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' // If no actual key was pressed (e.g. if only a modifier key was pressed), // ignore the event if (!input.character) return noEvent; return input; }
TestExitStatus EventTests::mouseEvents() { Testsuite::clearScreen(); Common::String info = "Testing Mouse events.\n " "Any movement/click generated by L/R/M mouse buttons or the mouse wheel should be detected.\n" "Press X to exit"; if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) { Testsuite::logPrintf("Info! Skipping test : keyboard events\n"); return kTestSkipped; } Common::EventManager *eventMan = g_system->getEventManager(); Common::Point pt(0, 30); Common::Rect rectInfo = Testsuite::writeOnScreen("Generate mouse events make L/R/M button clicks, move wheel", pt); pt.y += 15; Testsuite::writeOnScreen("Press X to exit", pt); pt.y = 70; Common::Rect rectLB = Testsuite::writeOnScreen("Left-button click : Not tested", pt); pt.y += 15; Common::Rect rectRB = Testsuite::writeOnScreen("Right-button click : Not tested", pt); pt.y += 15; Common::Rect rectMB = Testsuite::writeOnScreen("Middle-button click : Not tested", pt); pt.y += 15; Common::Rect rectWheel = Testsuite::writeOnScreen("Wheel Movements : Not tested", pt); // Init Mouse Palette GFXtests::initMousePalette(); Common::Rect finishZone = drawFinishZone(); bool quitLoop = false; TestExitStatus passed = kTestPassed; // handle all mouse events Common::Event event; while (!quitLoop) { // Show mouse CursorMan.showMouse(true); g_system->updateScreen(); while (eventMan->pollEvent(event)) { // Quit if explicitly requested if (Engine::shouldQuit()) { return passed; } switch (event.type) { case Common::EVENT_MOUSEMOVE: // Movements havee already been tested in GFX break; case Common::EVENT_LBUTTONDOWN: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse left-button pressed", Common::Point(rectInfo.left, rectInfo.top)); break; case Common::EVENT_RBUTTONDOWN: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse right-button pressed", Common::Point(rectInfo.left, rectInfo.top)); break; case Common::EVENT_WHEELDOWN: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse wheel moved down", Common::Point(rectInfo.left, rectInfo.top)); Testsuite::writeOnScreen("Wheel Movements : Done!", Common::Point(rectWheel.left, rectWheel.top)); break; case Common::EVENT_MBUTTONDOWN: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse middle-button pressed ", Common::Point(rectInfo.left, rectInfo.top)); break; case Common::EVENT_LBUTTONUP: Testsuite::clearScreen(rectInfo); if (finishZone.contains(eventMan->getMousePos())) { quitLoop = true; } Testsuite::writeOnScreen("Mouse left-button released", Common::Point(rectInfo.left, rectInfo.top)); Testsuite::writeOnScreen("Left-button clicks : Done!", Common::Point(rectLB.left, rectLB.top)); break; case Common::EVENT_RBUTTONUP: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse right-button released", Common::Point(rectInfo.left, rectInfo.top)); Testsuite::writeOnScreen("Right-button clicks : Done!", Common::Point(rectRB.left, rectRB.top)); break; case Common::EVENT_WHEELUP: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse wheel moved up", Common::Point(rectInfo.left, rectInfo.top)); Testsuite::writeOnScreen("Wheel Movements : Done!", Common::Point(rectWheel.left, rectWheel.top)); break; case Common::EVENT_MBUTTONUP: Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Mouse middle-button released ", Common::Point(rectInfo.left, rectInfo.top)); Testsuite::writeOnScreen("Middle-button clicks : Done!", Common::Point(rectMB.left, rectMB.top)); break; case Common::EVENT_KEYDOWN: if (event.kbd.keycode == Common::KEYCODE_x) { Testsuite::clearScreen(rectInfo); Testsuite::writeOnScreen("Exit requested", Common::Point(rectInfo.left, rectInfo.top)); quitLoop = true; } break; default: break; } } } CursorMan.showMouse(false); // Verify results now! if (Testsuite::handleInteractiveInput("Were mouse clicks (L/R/M buttons) and wheel movements identfied ?", "Yes", "No", kOptionRight)) { Testsuite::logDetailedPrintf("Mouse clicks (L/R/M buttons) and wheel movements failed"); passed = kTestFailed; } return passed; }
SciEvent EventManager::getScummVMEvent() { #ifdef ENABLE_SCI32 SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; #else SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point() }; SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point() }; #endif Common::EventManager *em = g_system->getEventManager(); Common::Event ev; bool found = em->pollEvent(ev); // Don't generate events for mouse movement while (found && ev.type == Common::EVENT_MOUSEMOVE) found = em->pollEvent(ev); // Save the mouse position // // We call getMousePos of the event manager here, since we also want to // store the mouse position in case of keyboard events, which do not feature // any mouse position information itself. // This should be safe, since the mouse position in the event manager should // only be updated when a mouse related event has been taken from the queue // via pollEvent. // We also adjust the position based on the scaling of the screen. Common::Point mousePos = em->getMousePos(); #if ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); Common::Point mousePosSci = mousePos; mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight)); noEvent.mousePosSci = input.mousePosSci = mousePosSci; } else { #endif g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); #if ENABLE_SCI32 } #endif noEvent.mousePos = input.mousePos = mousePos; if (!found || ev.type == Common::EVENT_MOUSEMOVE) { int modifiers = em->getModifierState(); noEvent.modifiers = ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) | ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) | ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0); return noEvent; } if (ev.type == Common::EVENT_QUIT) { input.type = SCI_EVENT_QUIT; return input; } int scummVMKeyFlags; switch (ev.type) { case Common::EVENT_KEYDOWN: case Common::EVENT_KEYUP: // Use keyboard modifiers directly in case this is a keyboard event scummVMKeyFlags = ev.kbd.flags; break; default: // Otherwise get them from EventManager scummVMKeyFlags = em->getModifierState(); break; } input.modifiers = ((scummVMKeyFlags & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) | ((scummVMKeyFlags & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) | ((scummVMKeyFlags & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0); // Caps lock and Scroll lock have been removed, cause we already handle upper // case keys and Scroll lock doesn't seem to be used anywhere //((ourModifiers & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) | //((ourModifiers & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) | // Handle mouse events for (int i = 0; i < ARRAYSIZE(mouseEventMappings); i++) { if (mouseEventMappings[i].commonType == ev.type) { input.type = mouseEventMappings[i].sciType; // Sierra passed keyboard modifiers for mouse events, too. // Sierra also set certain modifiers within their mouse interrupt handler // This whole thing was probably meant for people using a mouse, that only featured 1 button // So the user was able to press Ctrl and click the mouse button to create a right click. switch (ev.type) { case Common::EVENT_RBUTTONDOWN: // right button case Common::EVENT_RBUTTONUP: input.modifiers |= (SCI_KEYMOD_RSHIFT | SCI_KEYMOD_LSHIFT); // this value was hardcoded in the mouse interrupt handler break; case Common::EVENT_MBUTTONDOWN: // middle button case Common::EVENT_MBUTTONUP: input.modifiers |= SCI_KEYMOD_CTRL; // this value was hardcoded in the mouse interrupt handler break; default: break; } return input; } } // If we reached here, make sure that it's a keydown event if (ev.type != Common::EVENT_KEYDOWN) return noEvent; // Check for Control-Shift-D (debug console) if (ev.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && ev.kbd.keycode == Common::KEYCODE_d) { // Open debug console Console *con = g_sci->getSciDebugger(); con->attach(); return noEvent; } // Process keyboard events bool numlockOn = (ev.kbd.flags & Common::KBD_NUM); Common::KeyCode scummVMKeycode = ev.kbd.keycode; input.character = ev.kbd.ascii; input.type = SCI_EVENT_KEYBOARD; if (scummVMKeycode >= Common::KEYCODE_KP0 && scummVMKeycode <= Common::KEYCODE_KP9) { if (!(scummVMKeyFlags & Common::KBD_NUM)) { // HACK: Num-Lock not enabled // We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys // on the numpad work properly. input.character = 0; } } if ((input.character) && (input.character <= 0xFF)) { // Directly accept most common keys without conversion if ((input.character >= 0x80) && (input.character <= 0xFF)) { // If there is no extended font, we will just clear the // current event. // Sierra SCI actually accepted those characters, but // didn't display them inside text edit controls because // the characters were missing inside the font(s). // We filter them out for non-multilingual games because // of that. if (!_fontIsExtended) return noEvent; // Convert 8859-1 characters to DOS (cp850/437) for // multilingual SCI01 games input.character = codePageMap88591ToDOS[input.character & 0x7f]; } if (scummVMKeycode == Common::KEYCODE_TAB) { input.character = SCI_KEY_TAB; if (scummVMKeyFlags & Common::KBD_SHIFT) input.character = SCI_KEY_SHIFT_TAB; } if (scummVMKeycode == Common::KEYCODE_DELETE) input.character = SCI_KEY_DELETE; } else if ((scummVMKeycode >= Common::KEYCODE_F1) && scummVMKeycode <= Common::KEYCODE_F10) { // SCI_K_F1 == 59 << 8 // SCI_K_SHIFT_F1 == 84 << 8 if (!(scummVMKeyFlags & Common::KBD_SHIFT)) input.character = SCI_KEY_F1 + ((scummVMKeycode - Common::KEYCODE_F1)<<8); else input.character = SCI_KEY_SHIFT_F1 + ((scummVMKeycode - Common::KEYCODE_F1)<<8); } else { // Special keys that need conversion for (int i = 0; i < ARRAYSIZE(keyMappings); i++) { if (keyMappings[i].scummVMKey == scummVMKeycode) { input.character = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff; break; } } } // When Ctrl AND Alt are pressed together with a regular key, Linux will give us control-key, Windows will give // us the actual key. My opinion is that windows is right, because under DOS the keys worked the same, anyway // we support the other case as well if ((scummVMKeyFlags & Common::KBD_ALT) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' // Scancodify if appropriate if (scummVMKeyFlags & Common::KBD_ALT) input.character = altify(input.character); if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (scummVMKeyFlags & Common::KBD_CTRL) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2 && (scummVMKeyFlags & Common::KBD_CTRL) && input.character == 'c') { input.character = SCI_KEY_ETX; } #endif // If no actual key was pressed (e.g. if only a modifier key was pressed), // ignore the event if (!input.character) return noEvent; return input; }