mirror of
https://github.com/cocos/cocos-engine.git
synced 2026-09-07 08:09:13 +08:00
* Distribute touch events independently * remove touch event cast * Fix the error of clang-tidy Co-authored-by: qiuguohua <862332094@qq.com>
399 lines
15 KiB
C++
399 lines
15 KiB
C++
/****************************************************************************
|
|
Copyright (c) 2022 Xiamen Yaji Software Co., Ltd.
|
|
|
|
http://www.cocos.com
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated engine source code (the "Software"), a limited,
|
|
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
|
to use Cocos Creator solely to develop games on your target platforms. You shall
|
|
not use Cocos Creator software for developing other software or tools that's
|
|
used for developing games. You are not granted to publish, distribute,
|
|
sublicense, and/or sell copies of Cocos Creator.
|
|
|
|
The software or tools in this License Agreement are licensed, not sold.
|
|
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
****************************************************************************/
|
|
|
|
#include "platform/SDLHelper.h"
|
|
#include "SDL2/SDL.h"
|
|
#include "SDL2/SDL_main.h"
|
|
#include "SDL2/SDL_syswm.h"
|
|
#include "base/Log.h"
|
|
#include "platform/IEventDispatch.h"
|
|
#include "platform/interfaces/modules/ISystemWindow.h"
|
|
|
|
namespace {
|
|
std::unordered_map<int, cc::KeyCode> gKeyMap = {
|
|
{SDLK_APPLICATION, cc::KeyCode::CONTEXT_MENU},
|
|
{SDLK_SCROLLLOCK, cc::KeyCode::SCROLLLOCK},
|
|
{SDLK_PAUSE, cc::KeyCode::PAUSE},
|
|
{SDLK_PRINTSCREEN, cc::KeyCode::PRINT_SCREEN},
|
|
{SDLK_INSERT, cc::KeyCode::INSERT},
|
|
{SDLK_ESCAPE, cc::KeyCode::ESCAPE},
|
|
{SDLK_MINUS, cc::KeyCode::MINUS},
|
|
{SDLK_LSHIFT, cc::KeyCode::SHIFT_LEFT},
|
|
{SDLK_RSHIFT, cc::KeyCode::SHIFT_RIGHT},
|
|
{SDLK_EQUALS, cc::KeyCode::EQUAL},
|
|
{SDLK_BACKSLASH, cc::KeyCode::BACKSLASH},
|
|
{SDLK_BACKQUOTE, cc::KeyCode::BACKQUOTE},
|
|
{SDLK_BACKSPACE, cc::KeyCode::BACKSPACE},
|
|
{SDLK_RETURN, cc::KeyCode::ENTER},
|
|
{SDLK_RETURN2, cc::KeyCode::ENTER},
|
|
{SDLK_LEFTBRACKET, cc::KeyCode::BRACKET_LEFT},
|
|
{SDLK_RIGHTBRACKET, cc::KeyCode::BRACKET_RIGHT},
|
|
{SDLK_SEMICOLON, cc::KeyCode::SEMICOLON},
|
|
{SDLK_QUOTE, cc::KeyCode::QUOTE},
|
|
{SDLK_TAB, cc::KeyCode::TAB},
|
|
{SDLK_LCTRL, cc::KeyCode::CONTROL_LEFT},
|
|
{SDLK_RCTRL, cc::KeyCode::CONTROL_RIGHT},
|
|
{SDLK_LALT, cc::KeyCode::ALT_LEFT},
|
|
{SDLK_RALT, cc::KeyCode::ALT_RIGHT},
|
|
{SDLK_LEFT, cc::KeyCode::ARROW_LEFT},
|
|
{SDLK_RIGHT, cc::KeyCode::ARROW_RIGHT},
|
|
{SDLK_UP, cc::KeyCode::ARROW_UP},
|
|
{SDLK_DOWN, cc::KeyCode::ARROW_DOWN},
|
|
{SDLK_KP_ENTER, cc::KeyCode::NUMPAD_ENTER},
|
|
{SDLK_KP_PLUS, cc::KeyCode::NUMPAD_PLUS},
|
|
{SDLK_KP_MULTIPLY, cc::KeyCode::NUMPAD_MULTIPLY},
|
|
{SDLK_KP_DIVIDE, cc::KeyCode::NUMPAD_DIVIDE},
|
|
{SDLK_KP_MINUS, cc::KeyCode::NUMPAD_MINUS},
|
|
{SDLK_KP_PERIOD, cc::KeyCode::NUMPAD_DECIMAL},
|
|
{SDLK_KP_BACKSPACE, cc::KeyCode::BACKSPACE},
|
|
{SDLK_NUMLOCKCLEAR, cc::KeyCode::NUM_LOCK},
|
|
{SDLK_HOME, cc::KeyCode::HOME},
|
|
{SDLK_PAGEUP, cc::KeyCode::PAGE_UP},
|
|
{SDLK_PAGEDOWN, cc::KeyCode::PAGE_DOWN},
|
|
{SDLK_END, cc::KeyCode::END},
|
|
{SDLK_COMMA, cc::KeyCode::COMMA},
|
|
{SDLK_PERIOD, cc::KeyCode::PERIOD},
|
|
{SDLK_SLASH, cc::KeyCode::SLASH},
|
|
{SDLK_SPACE, cc::KeyCode::SPACE},
|
|
{SDLK_DELETE, cc::KeyCode::DELETE_KEY},
|
|
{SDLK_CAPSLOCK, cc::KeyCode::CAPS_LOCK},
|
|
{SDLK_KP_0, cc::KeyCode::NUMPAD_0},
|
|
{SDLK_KP_1, cc::KeyCode::NUMPAD_1},
|
|
{SDLK_KP_2, cc::KeyCode::NUMPAD_2},
|
|
{SDLK_KP_3, cc::KeyCode::NUMPAD_3},
|
|
{SDLK_KP_4, cc::KeyCode::NUMPAD_4},
|
|
{SDLK_KP_5, cc::KeyCode::NUMPAD_5},
|
|
{SDLK_KP_6, cc::KeyCode::NUMPAD_6},
|
|
{SDLK_KP_7, cc::KeyCode::NUMPAD_7},
|
|
{SDLK_KP_8, cc::KeyCode::NUMPAD_8},
|
|
{SDLK_KP_9, cc::KeyCode::NUMPAD_9}};
|
|
|
|
int sdlKeycodeToCocosCode(int sdlCode, int mode) {
|
|
auto it = gKeyMap.find(sdlCode);
|
|
if (it != gKeyMap.end()) {
|
|
return static_cast<int>(it->second);
|
|
}
|
|
|
|
if (sdlCode >= SDLK_F1 && sdlCode <= SDLK_F12) {
|
|
// F1 ~ F12
|
|
return 112 + (sdlCode - SDLK_F1);
|
|
} else {
|
|
int code = sdlCode & (~(1 << 30));
|
|
if (code >= SDLK_a && code <= SDLK_z) {
|
|
return 'A' + (code - SDLK_a);
|
|
} else {
|
|
return code;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unordered_map<cc::ISystemWindow::WindowFlags, SDL_WindowFlags> gWindowFlagMap = {
|
|
{cc::ISystemWindow::CC_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN},
|
|
{cc::ISystemWindow::CC_WINDOW_OPENGL, SDL_WINDOW_OPENGL},
|
|
{cc::ISystemWindow::CC_WINDOW_SHOWN, SDL_WINDOW_SHOWN},
|
|
{cc::ISystemWindow::CC_WINDOW_HIDDEN, SDL_WINDOW_HIDDEN},
|
|
{cc::ISystemWindow::CC_WINDOW_BORDERLESS, SDL_WINDOW_BORDERLESS},
|
|
{cc::ISystemWindow::CC_WINDOW_RESIZABLE, SDL_WINDOW_RESIZABLE},
|
|
{cc::ISystemWindow::CC_WINDOW_MINIMIZED, SDL_WINDOW_MINIMIZED},
|
|
{cc::ISystemWindow::CC_WINDOW_MAXIMIZED, SDL_WINDOW_MAXIMIZED},
|
|
{cc::ISystemWindow::CC_WINDOW_INPUT_GRABBED, SDL_WINDOW_INPUT_GRABBED},
|
|
{cc::ISystemWindow::CC_WINDOW_INPUT_FOCUS, SDL_WINDOW_INPUT_FOCUS},
|
|
{cc::ISystemWindow::CC_WINDOW_MOUSE_FOCUS, SDL_WINDOW_MOUSE_FOCUS},
|
|
{cc::ISystemWindow::CC_WINDOW_FULLSCREEN_DESKTOP, SDL_WINDOW_FULLSCREEN_DESKTOP},
|
|
{cc::ISystemWindow::CC_WINDOW_FOREIGN, SDL_WINDOW_FOREIGN},
|
|
{cc::ISystemWindow::CC_WINDOW_ALLOW_HIGHDPI, SDL_WINDOW_ALLOW_HIGHDPI},
|
|
{cc::ISystemWindow::CC_WINDOW_MOUSE_CAPTURE, SDL_WINDOW_MOUSE_CAPTURE},
|
|
{cc::ISystemWindow::CC_WINDOW_ALWAYS_ON_TOP, SDL_WINDOW_ALWAYS_ON_TOP},
|
|
{cc::ISystemWindow::CC_WINDOW_SKIP_TASKBAR, SDL_WINDOW_SKIP_TASKBAR},
|
|
{cc::ISystemWindow::CC_WINDOW_UTILITY, SDL_WINDOW_UTILITY},
|
|
{cc::ISystemWindow::CC_WINDOW_TOOLTIP, SDL_WINDOW_TOOLTIP},
|
|
{cc::ISystemWindow::CC_WINDOW_POPUP_MENU, SDL_WINDOW_POPUP_MENU},
|
|
{cc::ISystemWindow::CC_WINDOW_VULKAN, SDL_WINDOW_VULKAN}};
|
|
|
|
int windowFlagsToSDLWindowFlag(int flags) {
|
|
int sdlFlags = 0;
|
|
for (auto it : gWindowFlagMap) {
|
|
if ((it.first & flags) == it.first) {
|
|
sdlFlags |= it.second;
|
|
}
|
|
}
|
|
return sdlFlags;
|
|
}
|
|
} // namespace
|
|
|
|
namespace cc {
|
|
SDLHelper::SDLHelper(IEventDispatch *delegate)
|
|
: _delegate(delegate) {
|
|
}
|
|
|
|
SDLHelper::~SDLHelper() {
|
|
if (_handle) {
|
|
SDL_DestroyWindow(_handle);
|
|
_handle = nullptr;
|
|
}
|
|
if (_isWindowCreated) {
|
|
SDL_Quit();
|
|
}
|
|
}
|
|
|
|
int SDLHelper::init() {
|
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
|
// Display error message
|
|
CC_LOG_ERROR("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
void SDLHelper::dispatchWindowEvent(const SDL_WindowEvent &wevent) {
|
|
WindowEvent ev;
|
|
switch (wevent.event) {
|
|
case SDL_WINDOWEVENT_SHOWN: {
|
|
ev.type = WindowEvent::Type::SHOW;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_RESTORED: {
|
|
ev.type = WindowEvent::Type::RESTORED;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_SIZE_CHANGED: {
|
|
ev.type = WindowEvent::Type::SIZE_CHANGED;
|
|
ev.width = wevent.data1;
|
|
ev.height = wevent.data2;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_RESIZED: {
|
|
ev.type = WindowEvent::Type::RESIZED;
|
|
ev.width = wevent.data1;
|
|
ev.height = wevent.data2;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_HIDDEN: {
|
|
ev.type = WindowEvent::Type::HIDDEN;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_MINIMIZED: {
|
|
ev.type = WindowEvent::Type::MINIMIZED;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_ENTER: {
|
|
SDL_CaptureMouse(SDL_TRUE);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT_CLOSE: {
|
|
ev.type = WindowEvent::Type::CLOSE;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SDLHelper::dispatchSDLEvent(const SDL_Event &sdlEvent, bool *quit) {
|
|
cc::TouchEvent touch;
|
|
cc::MouseEvent mouse;
|
|
cc::KeyboardEvent keyboard;
|
|
switch (sdlEvent.type) {
|
|
case SDL_QUIT: {
|
|
if (quit) {
|
|
*quit = true;
|
|
}
|
|
WindowEvent ev;
|
|
ev.type = WindowEvent::Type::QUIT;
|
|
_delegate->dispatchEvent(ev);
|
|
break;
|
|
}
|
|
case SDL_WINDOWEVENT: {
|
|
dispatchWindowEvent(sdlEvent.window);
|
|
break;
|
|
}
|
|
case SDL_MOUSEBUTTONDOWN: {
|
|
int width = 0;
|
|
int height = 0;
|
|
SDL_GetWindowSize(_handle, &width, &height);
|
|
const SDL_MouseButtonEvent &event = sdlEvent.button;
|
|
if (0 > event.x || event.x > width || 0 > event.y || event.y > height) {
|
|
break;
|
|
}
|
|
mouse.type = MouseEvent::Type::DOWN;
|
|
mouse.x = static_cast<float>(event.x);
|
|
mouse.y = static_cast<float>(event.y);
|
|
mouse.button = event.button - 1;
|
|
_delegate->dispatchEvent(mouse);
|
|
break;
|
|
}
|
|
case SDL_MOUSEBUTTONUP: {
|
|
const SDL_MouseButtonEvent &event = sdlEvent.button;
|
|
mouse.type = MouseEvent::Type::UP;
|
|
mouse.x = static_cast<float>(event.x);
|
|
mouse.y = static_cast<float>(event.y);
|
|
mouse.button = event.button - 1;
|
|
_delegate->dispatchEvent(mouse);
|
|
break;
|
|
}
|
|
case SDL_MOUSEMOTION: {
|
|
const SDL_MouseMotionEvent &event = sdlEvent.motion;
|
|
mouse.type = MouseEvent::Type::MOVE;
|
|
mouse.x = static_cast<float>(event.x);
|
|
mouse.y = static_cast<float>(event.y);
|
|
mouse.button = 0;
|
|
_delegate->dispatchEvent(mouse);
|
|
break;
|
|
}
|
|
case SDL_MOUSEWHEEL: {
|
|
const SDL_MouseWheelEvent &event = sdlEvent.wheel;
|
|
mouse.type = MouseEvent::Type::WHEEL;
|
|
mouse.x = static_cast<float>(event.x);
|
|
mouse.y = static_cast<float>(event.y);
|
|
mouse.button = 0; //TODO: direction
|
|
_delegate->dispatchEvent(mouse);
|
|
break;
|
|
}
|
|
case SDL_FINGERUP: {
|
|
const SDL_TouchFingerEvent &event = sdlEvent.tfinger;
|
|
touch.type = TouchEvent::Type::ENDED;
|
|
touch.touches = {TouchInfo(event.x, event.y, (int)event.fingerId)};
|
|
_delegate->dispatchTouchEvent(touch);
|
|
break;
|
|
}
|
|
case SDL_FINGERDOWN: {
|
|
const SDL_TouchFingerEvent &event = sdlEvent.tfinger;
|
|
touch.type = TouchEvent::Type::BEGAN;
|
|
touch.touches = {TouchInfo(event.x, event.y, (int)event.fingerId)};
|
|
_delegate->dispatchTouchEvent(touch);
|
|
break;
|
|
}
|
|
case SDL_FINGERMOTION: {
|
|
const SDL_TouchFingerEvent &event = sdlEvent.tfinger;
|
|
touch.type = TouchEvent::Type::MOVED;
|
|
touch.touches = {TouchInfo(event.x, event.y, (int)event.fingerId)};
|
|
_delegate->dispatchTouchEvent(touch);
|
|
break;
|
|
}
|
|
case SDL_KEYDOWN: {
|
|
const SDL_KeyboardEvent &event = sdlEvent.key;
|
|
auto mode = event.keysym.mod;
|
|
keyboard.action = KeyboardEvent::Action::PRESS;
|
|
keyboard.key = sdlKeycodeToCocosCode(event.keysym.sym, mode);
|
|
keyboard.altKeyActive = mode & KMOD_ALT;
|
|
keyboard.ctrlKeyActive = mode & KMOD_CTRL;
|
|
keyboard.shiftKeyActive = mode & KMOD_SHIFT;
|
|
//CC_LOG_DEBUG("==> key %d -> code %d", event.keysym.sym, keyboard.key);
|
|
_delegate->dispatchEvent(keyboard);
|
|
break;
|
|
}
|
|
case SDL_KEYUP: {
|
|
const SDL_KeyboardEvent &event = sdlEvent.key;
|
|
auto mode = event.keysym.mod;
|
|
keyboard.action = KeyboardEvent::Action::RELEASE;
|
|
keyboard.key = sdlKeycodeToCocosCode(event.keysym.sym, mode);
|
|
keyboard.altKeyActive = mode & KMOD_ALT;
|
|
keyboard.ctrlKeyActive = mode & KMOD_CTRL;
|
|
keyboard.shiftKeyActive = mode & KMOD_SHIFT;
|
|
_delegate->dispatchEvent(keyboard);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SDLHelper::pollEvent(bool *quit) {
|
|
SDL_Event sdlEvent;
|
|
int cnt = 0;
|
|
while ((cnt = SDL_PollEvent(&sdlEvent)) != 0) {
|
|
dispatchSDLEvent(sdlEvent, quit);
|
|
}
|
|
}
|
|
|
|
bool SDLHelper::createWindow(const char *title,
|
|
int w, int h, int flags) {
|
|
if (_isWindowCreated) {
|
|
return true;
|
|
}
|
|
SDL_Rect screenRect;
|
|
if (SDL_GetDisplayUsableBounds(0, &screenRect) != 0) {
|
|
return false;
|
|
}
|
|
int x = screenRect.x;
|
|
int y = screenRect.y + screenRect.h - h;
|
|
return createWindow(title, x, y, w, h, flags);
|
|
}
|
|
|
|
bool SDLHelper::createWindow(const char *title,
|
|
int x, int y, int w,
|
|
int h, int flags) {
|
|
if (_isWindowCreated) {
|
|
return true;
|
|
}
|
|
// Create window
|
|
int sdlFlags = windowFlagsToSDLWindowFlag(flags);
|
|
_handle = SDL_CreateWindow(title, x, y, w, h, sdlFlags);
|
|
if (_handle == nullptr) {
|
|
// Display error message
|
|
CC_LOG_ERROR("Window could not be created! SDL_Error: %s\n", SDL_GetError());
|
|
return false;
|
|
}
|
|
_isWindowCreated = true;
|
|
return true;
|
|
}
|
|
|
|
void SDLHelper::setCursorEnabled(bool value) {
|
|
SDL_SetRelativeMouseMode(value ? SDL_FALSE : SDL_TRUE);
|
|
}
|
|
|
|
void SDLHelper::swapWindow() {
|
|
SDL_GL_SwapWindow(_handle);
|
|
}
|
|
|
|
#if (CC_PLATFORM == CC_PLATFORM_LINUX)
|
|
uintptr_t SDLHelper::getDisplay() const {
|
|
SDL_SysWMinfo wmInfo;
|
|
SDL_VERSION(&wmInfo.version);
|
|
SDL_GetWindowWMInfo(_handle, &wmInfo);
|
|
return reinterpret_cast<uintptr_t>(wmInfo.info.x11.display);
|
|
}
|
|
#endif
|
|
|
|
uintptr_t SDLHelper::getWindowHandler() const {
|
|
SDL_SysWMinfo wmInfo;
|
|
SDL_VERSION(&wmInfo.version);
|
|
SDL_GetWindowWMInfo(_handle, &wmInfo);
|
|
|
|
#if CC_PLATFORM == CC_PLATFORM_WINDOWS
|
|
return reinterpret_cast<uintptr_t>(wmInfo.info.win.window);
|
|
#elif (CC_PLATFORM == CC_PLATFORM_LINUX)
|
|
return reinterpret_cast<uintptr_t>(wmInfo.info.x11.window);
|
|
#endif
|
|
CCASSERT(false, "Only valid in windows, linux");
|
|
return 0;
|
|
}
|
|
|
|
} // namespace cc
|