Форум программистов, компьютерный форум, киберфорум
8Observer8
Войти
Регистрация
Восстановить пароль

SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве

Запись от 8Observer8 размещена 02.02.2026 в 00:05. Обновил(-а) 8Observer8 07.02.2026 в 20:21
Показов 3161 Комментарии 0

Содержание блога

Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик касания экрана мобильного устройства, чтобы один и тот же проект работал в браузере ПК и в браузере мобильного устройства. Исходники того, что получилось: mouse-and-touch-handlers-sdl3.zip

Если у вас не установлены Emscripten SDK и CMake, то установите их по следующей инструкции и выполните "hello world" инструкцию там же: Установка Emscripten SDK (emsdk) и CMake

Установка библиотеки SDL3 для Wasm



  • Скачайте SDL3 для Wasm: SDL3-devel-3.4.0-wasm.zip Библиотека была собрана из исходников с помощью emsdk3 4.0.15
  • Создайте пустую папку с именем "libs", например, на диске C
  • Извлеките архив с библиотекой в папку "libs"
  • Установка библиотеки SDL3 для Wasm закончена. Теперь можно использовать этот путь в своих проектах в файле CMakeListst.txt, чтобы указывать точное местоположение конфигурационных файлов библиотеки SDL3:
    Code
    1
    
    set(SDL3_DIR "C:/libs/SDL3-devel-3.4.0-wasm/lib/cmake/SDL3")
  • Примечание 1. Команда "set" создаёт переменную SDL3_DIR и устанавливает ей значение "C:/libs/SDL3-devel-3.4.0-wasm/lib/cmake/SDL3"
  • Примечание 2. Имя переменной должно строго соответствовать: НазваниеБиблиотеки_DIR

Настройка проекта



  • Создайте пустую папку с именем "mouse-and-touch-handlers-sdl3". Это будет папка для проекта
  • Откройте созданную папку в каком-нибудь редакторе кода, например, в Notepad++ и Sublime Text4 (ST4): https://www.sublimetext.com/download Если у вас путь к ST4 находится в Path, то отройте консоль (CMD) в созданной папке "mouse-and-touch-handlers-sdl3" и введите команду:
    Bash
    1
    
    subl .
  • Примечание. Точка после subl означает - открыть текущую папку в Sublime Text 4

Пошаговое создание файла CMakeLists.txt



  • В корне проекта создайте файл CMakeLists.txt
  • Наберите строку указания минимальной версии CMake:
    Code
    1
    
    cmake_minimum_required(VERSION 3.21)
  • Добавьте строку, которая задаёт название проекта в системе CMake:
    Code
    1
    
    project(mouse-and-touch-handlers-sdl3)
  • Добавьте строку, которая задаёт название для генерируемых исполняемых файлов:
    Code
    1
    
    add_executable(app)
  • Примечание. В Windows был бы сгенерирован файл app.exe, а в вебе будет app.js / app.wasm
  • Добавьте строку, которая задаёт используемый стандарт языка Си:
    C
    1
    
    set(CMAKE_C_STANDARD 11)
  • Примечание 1. Для C++ эквивалентом будет строка "set(CMAKE_CXX_STANDARD 20)"
  • Добавьте строку, которая указывает точное местоположение конфигурационных файлов библиотеки SDL3:
    Code
    1
    
    set(SDL3_DIR "C:/libs/SDL3-devel-3.4.0-wasm/lib/cmake/SDL3")
  • Добавьте строку, которая проверяет наличие библиотеки SDL3 в системе
    Code
    1
    
    find_package(SDL3 REQUIRED)
  • Примечание. Команда find_package() проверяет наличие библиотеки SDL3 в системе по установленному ранее пути (SDL3_DIR)
  • Добавьте строку, которая привязывает библиотеку SDL3 к нашему приложению
    Code
    1
    
    target_link_libraries(app PRIVATE SDL3::SDL3)
  • Добавьте код для подключения файла исходного кода main.c:
    Code
    1
    2
    3
    4
    
    target_sources(app
        PRIVATE
        src/main.c
    )

В итоге должен получиться файл:

CMakeLists.txt

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cmake_minimum_required(VERSION 3.21)
project(mouse-and-touch-handlers-sdl3)
 
# Задаем название будущего приложения (в Windows это был бы app.exe, а в вебе будет app.js / app.wasm)
add_executable(app)
 
# Устанавливаем стандарт C
set(CMAKE_C_STANDARD 11)
 
# Указываем точное местоположение конфигурационных файлов библиотеки SDL3
# Имя переменной должно строго соответствовать: НазваниеБиблиотеки_DIR
set(SDL3_DIR "C:/libs/SDL3-devel-3.4.0-wasm/lib/cmake/SDL3")
 
# Проверяем наличие библиотеки SDL3 в системе
# Если она не будет найдены, CMake прервет настройку с ошибкой
# REQUIRED - переводится, как «обязательно» или «требуется»
find_package(SDL3 REQUIRED)
 
# Добавляем исходный код к проекту
target_sources(app
    PRIVATE
    src/main.c
)

Пошаговое создание файла main.c



  • Создайте папку "src", а в ней файл "main.c"
  • Откройте в файл src/main.c в редакторе кода
  • Примечание. Код лучше не копировать и вставлять, а набирать вручную - так лучше запоминается
  • Добавьте строку для переключения на режим "Использовать SDL3-callback вместо main()"
    C
    1
    
    #define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
  • Добавьте строки подключения необходимых заголовочных файлов SDL3:
    C
    1
    2
    
    #include <SDL3/SDL.h>
    #include <SDL3/SDL_main.h>
  • Создайте две глобальные переменные: window - окно и renderer - рисовальщик:
    C
    1
    2
    
    static SDL_Window *window = NULL;
    static SDL_Renderer *renderer = NULL;
  • Примечание. Ключевое слово static делает переменную видимой только в файле main.c

Функция SDL_AppInit() - инициализация



  • Напишите функцию SDL_AppInit(), которая будет вызываться библиотекой SDL3 автоматически один раз перед запуском основного цикла приложения:
    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
    {
        if (!SDL_Init(SDL_INIT_VIDEO))
        {
            SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
            return SDL_APP_FAILURE;
        }
     
        if (!SDL_CreateWindowAndRenderer("Example", 400, 400, 0, &window, &renderer))
        {
            SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
            return SDL_APP_FAILURE;
        }
     
        SDL_SetRenderVSync(renderer, 1);
     
        return SDL_APP_CONTINUE;
    }
  • Примечание 1. В этой функции вызывается функция SDL_Init() с аргументом SDL_INIT_VIDEO, для инициализации библиотеки SDL3. В случае, если по каким-то причинам инициализация не прошла, то выводится текст ошибки и приложение закрывается
  • Примечание 2. Функция SDL_CreateWindowAndRenderer() создаёт холст размера 400 на 400 пикселей и возвращает созданные: window и renderer
  • Примечание 3. Функция SDL_SetRenderVSync() включает вертикальную синхронизацию. Главный цикл приложения будет запущен с той же частотой с которой работает монитор компьютера. Это значительно снижает нагрузку на процессор. На старом ноутбуке эта разница будет примерно такая: 30% CPU с отключенной VSync и 1-3% с включенной VSync

    Функция SDL_AppEvent() - обработка событий



  • Напишите код функции SDL_AppEvent(), которая отвечает за события, а в данном случае за обработку события закрытия окна:

    C
    1
    2
    3
    4
    5
    6
    7
    8
    
    SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
    {
        if (event->type == SDL_EVENT_QUIT)
        {
            return SDL_APP_SUCCESS; // End the program, reporting success to the OS
        }
        return SDL_APP_CONTINUE;
    }
  • Примечание. Эта функция отвечает за события в приложении. Например, нажатия кнопок клавиатуры, движение мыши, клик мышью, касание экрана на мобильном устройстве и т.д. В данном случае, пользователь кликает по крестику. Срабатывает функция SDL_AppEvent(). Условие if проверяет какой тип события. Если это тим SDL_EVENT_QUIT, то срабатывает тело условия if и происходит выход из программы с кодом SDL_APP_SUCCESS, то есть сообщаем операционной системе, что выход успешный. Если было какое-то другое событие, то выполнение главного цикла продолжается (return SDL_APP_CONTINUE)

    Функция SDL_AppIterate() - главный цикл приложения



  • Напишите код главного цикла приложения, то есть функцию SDL_AppIterate():
    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    SDL_AppResult SDL_AppIterate(void *appstate)
    {
        // Clear the screen
        SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
        SDL_RenderClear(renderer);
     
        // Draw here...
     
        // Update the screen
        SDL_RenderPresent(renderer);
        return SDL_APP_CONTINUE;
    }
  • Примечание 1. Функция SDL_AppIterate() вызывается библиотекой SDL3 автоматически с частотой равной частоте монитора при включённом VSync. Таким образом, если у вас монитор с частотой 60 Гц, то функция SDL_AppIterate будет вызываться 60 раз в секунд с интервалом примерно 0.016 секунды между вызовами
  • Примечание 2. Функция SDL_SetRenderDrawColor задаём цвет в формате R, G, B, A (Red - красный, Green - зелёный, Blue - синий, Alpha альфа канал), где каждое значение находится в диапазоне [0, 255]. Последний параметр - это альфа канал - прозрачность: 0 - прозрачный фон, 255 - непрозрачный фон. Цвет (100, 100, 100, 255) - серый, непрозрачный
  • Примечание 3. Функция SDL_RenderClear() стирает всё с холста и заливает холст заданным цветом, то есть в данном случае серый
  • Примечание 4. Функция SDL_RenderPresent() - выводит кадр на экран

    Функция SDL_AppQuit() - освобождение ресурсов



  • Напишите код функции под названием SDL_AppQuit(), которая автоматически вызывается библиотекой SDL3 перед завершением приложения, когда пользователь закроет окно:
    C
    1
    2
    3
    4
    
    void SDL_AppQuit(void *appstate, SDL_AppResult result)
    {
        // SDL will clean up the window/renderer for us
    }
  • Примечание. Эта функция нужная для освобождения ресурсов

Конфигурирование проекта, компиляция кода и запуск на локальном сервере



  • В корне проекта создайте два батника со следующими названиями и содержимым:

    config-web.bat

    Bash
    1
    
    emcmake cmake -S . -B dist -DCMAKE_BUILD_TYPE=Debug
    build-web.bat

    Bash
    1
    2
    3
    4
    5
    6
    7
    8
    
    cd dist
    cmake --build .
     
    cd ..
    mkdir public\js
    set current_dir=%~dp0
    copy "%current_dir%dist\app.wasm" "%current_dir%public\js"
    copy "%current_dir%dist\app.js" "%current_dir%public\js"
  • Примечание. Батник "config-web.bat" нужно запустить один раз, а дальше во время разработки и отладки запускать батник "build-web.bat" для сборки проекта. После сборки в папке "dist" появятся два файла: "app.js" и "app.wasm", появится папка "public/js" и оба файла ("app.js" и "app.wasm") буду автоматически скопированы в папку "public/js"
  • В корне проекта выполните две команды в консоли, которые запустят батники:
    Bash
    1
    2
    
    config-web
    build-web
  • Можете проверить, что появилась папка "public/js", в которой находятся два файла: "app.js" и "app.wasm"
  • Создайте файл "index.html" в папке "public" со следующим содержимым:

    index.html

    PHP/HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    <!DOCTYPE html>
     
    <html>
     
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
    </head>
     
    <body>
        <canvas id="canvas"></canvas>
     
        <script async src="./js/app.js"></script>
    </body>
  • Примечание. Здесь создаётся элемент <canvas> c id="canvas", который будет использовать SDL3 для рисования. Подключается файл "./js/app.js". Элемент <meta name="viewport"... нужен, чтобы в нормальном масштабе отображалось на разных устройствах, например, в браузерах на смартфонах
  • Запустите локальный сервер командой:
    Bash
    1
    
    http-server -c-1
  • Перейдите в браузере ПК по адресу:
    Code
    1
    
    localhost:8080
  • Примечание. По Wi-Fi на Android тоже работает

Обработчик клика мыши



  • Добавьте заголовочный файл для использования функции printf():
    C
    1
    
    #include <stdio.h>
  • Добавьте обработчик клика мышью и выведите текст в консоль:
    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
    {
        if (event->type == SDL_EVENT_QUIT)
        {
            return SDL_APP_SUCCESS; // End the program, reporting success to the OS
        }
        else if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
        {
            printf("Клик мышью\n");
        }
     
        return SDL_APP_CONTINUE;
    }
  • В результате получился пример:

    main.c

    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    
    #define SDL_MAIN_USE_CALLBACKS 1 // Use the callbacks instead of main()
     
    #include <SDL3/SDL.h>
    #include <SDL3/SDL_main.h>
    #include <stdio.h>
     
    static SDL_Window *window = NULL;
    static SDL_Renderer *renderer = NULL;
     
    SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
    {
        if (!SDL_Init(SDL_INIT_VIDEO))
        {
            SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
            return SDL_APP_FAILURE;
        }
     
        if (!SDL_CreateWindowAndRenderer("Example", 400, 400, 0, &window, &renderer))
        {
            SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
            return SDL_APP_FAILURE;
        }
     
        SDL_SetRenderVSync(renderer, 1);
     
        return SDL_APP_CONTINUE;
    }
     
    SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
    {
        if (event->type == SDL_EVENT_QUIT)
        {
            return SDL_APP_SUCCESS; // End the program, reporting success to the OS
        }
     
        return SDL_APP_CONTINUE;
    }
     
    SDL_AppResult SDL_AppIterate(void *appstate)
    {
        // Clear the screen
        SDL_SetRenderDrawColor(renderer, 100, 100, 100, 255);
        SDL_RenderClear(renderer);
     
        // Draw here...
     
        // Update the screen
        SDL_RenderPresent(renderer);
        return SDL_APP_CONTINUE;
    }
     
    void SDL_AppQuit(void *appstate, SDL_AppResult result)
    {
        // SDL will clean up the window/renderer for us
    }
  • Введите команду для сборки проекта "build-web"
  • Откройте новую страницу в браузере
  • Откройте отладочную консоль браузера (Ctrl+Shift+J на Chrome/Edge или Ctrl+Shfit+K)
  • Перейдите по адресу "localhost:8080"

[H3]Обработчик касания экрана на смартфоне[/H4]

  • Добавьте обработчик касания экрана (тип события SDL_EVENT_FINGER_DOWN) в функцию SDL_AppEvent:
    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
    {
        if (event->type == SDL_EVENT_QUIT)
        {
            return SDL_APP_SUCCESS; // End the program, reporting success to the OS
        }
        else if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
        {
            printf("Клик мышью\n");
        }
        else if(event->type == SDL_EVENT_FINGER_DOWN)
        {
            printf("Касание экрана\n");
        }
     
        return SDL_APP_CONTINUE;
    }
  • Примечание. Если вы перейдёте в отладочную консоль браузера ПК, то вторая кнопка сверху "Toggle device toolbar" переключает на эмуляцию мобильного устройства. Там вы увидите, что срабатывают оба события: SDL_EVENT_MOUSE_BUTTON_DOWN и SDL_EVENT_FINGER_DOWN. Если вам нужно событие клика на Desktop и отдельно одиночного касания экрана на Android, то можно использовать тип события SDL_EVENT_MOUSE_BUTTON_DOWN. Если нужно отдельно касания обрабатывать и отключать события мыши на Android, то можно использовать следующую опцию, которую нужно разместить до строки создания окна:
    C
    1
    2
    
        // Отключаем генерацию событий мыши из касаний пальцем
        SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");

Загрузка приложения на бесплатный хостинг Vercel



  • Установите Node.js: https://nodejs.org/en/download
  • Установите Vercel:
    Bash
    1
    
    npm i -g vercel
  • Добавьте в корень проекта файл "vercel.json":

    vercel.json

    JSON
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    {
      "headers": [
        {
          "source": "/(.*)",
          "headers": [
            { "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" },
            { "key": "Cross-Origin-Opener-Policy", "value": "same-origin" }
          ]
        }
      ]
    }
  • Соберите проект в Release, а для этого замените Debug на Release в файле config-web.bat
  • Сконфигурируйте проект командой:
    Bash
    1
    
    config-web
  • Собирите проект командой:
    Bash
    1
    
    build-web
  • Введите команды:
    Bash
    1
    2
    
    vercel login
    vercel
  • Будет выведена ссылка на приложение в браузере: https://mouse-and-touch-handlers-sdl3.vercel.app
  • Примечание. Если вы что-то изменили в приложении и пересобрали его, то достаточно ввести одну команду для перезаливки:
    Bash
    1
    
    vercel --prod

Вес приложения в релизе на SDL3:

Название: 61799a872638385d41742d3efeeaa986e8afabb0.png
Просмотров: 2035

Размер: 2.7 Кб

Структура проекта:

Название: 9b4dc960d2a3e1563f06260a5f7ae942c13e0834.png
Просмотров: 2038

Размер: 3.8 Кб
Вложения
Тип файла: zip SDL3-devel-3.4.0-wasm.zip (1.22 Мб, 97 просмотров)
Тип файла: zip mouse-and-touch-handlers-sdl3.zip (280.6 Кб, 48 просмотров)
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Новые блоги и статьи
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru