From 462476f1500252d0fcd640a15af431f17bc12847 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Fri, 30 May 2025 19:28:10 +0800 Subject: [PATCH 01/92] Harmony port: Workflows --- .../setup-harmony-toolchain/action.yml | 33 +++++++++++++++++++ .github/workflows/create-test-plan.py | 11 +++++++ 2 files changed, 44 insertions(+) create mode 100644 .github/actions/setup-harmony-toolchain/action.yml diff --git a/.github/actions/setup-harmony-toolchain/action.yml b/.github/actions/setup-harmony-toolchain/action.yml new file mode 100644 index 0000000000..b13a29888c --- /dev/null +++ b/.github/actions/setup-harmony-toolchain/action.yml @@ -0,0 +1,33 @@ +name: 'Setup Harmony toolchain' +inputs: + version: + description: 'Harmony version' + default: '5.0.0-Release' +runs: + using: 'composite' + steps: + - uses: actions/cache/restore@v4 + id: restore-cache + with: + path: /opt/native + key: harmony-${{ inputs.version }} + + - name: Download Harmony toolchain + if: ${{ !steps.restore-cache.outputs.cache-hit }} + shell: bash + run: | + wget https://repo.huaweicloud.com/openharmony/os/${{ inputs.version }}/ohos-sdk-windows_linux-public.tar.gz + tar -zxvf ohos-sdk-windows_linux-public.tar.gz + mkdir -p /opt + + unzip linux/native*.zip -d /opt + - uses: actions/cache/save@v4 + if: ${{ !steps.restore-cache.outputs.cache-hit }} + with: + path: /opt/native + key: harmony-${{ inputs.version }} + - name: 'Set output vars' + id: final + shell: bash + run: | + echo "HARMONY_NATIVE_SDK=/opt/native" >> $GITHUB_OUTPUT diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index b711c02ede..2e85ed9f9c 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -55,6 +55,7 @@ class SdlPlatform(Enum): FreeBSD = "freebsd" NetBSD = "netbsd" NGage = "ngage" + Harmony = "harmony" class Msys2Platform(Enum): @@ -141,6 +142,7 @@ JOB_SPECS = { "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), + "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), } @@ -757,6 +759,15 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta job.setup_gage_sdk_path = "C:/ngagesdk" job.cmake_toolchain_file = "C:/ngagesdk/cmake/ngage-toolchain.cmake" job.test_pkg_config = False + case SdlPlatform.Harmony: + job.cmake_arguments.extend(( + f"-DOHOS_ARCH={spec.harmony_arch}", + "-DCMAKE_TOOLCHAIN_FILE=/opt/native/build/cmake/ohos.toolchain.cmake", + )) + job.shared_lib = SharedLibType.SO_0 + job.static_lib = StaticLibType.A + job.run_tests = False + job.test_pkg_config = False case _: raise ValueError(f"Unsupported platform={spec.platform}") From a6ebc6a63abc1dfc3178ec556a77dc85fe5fcd22 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Fri, 30 May 2025 19:30:49 +0800 Subject: [PATCH 02/92] Harmony port: Workflows (disable other plats) --- .github/workflows/create-test-plan.py | 80 +++++++++++++-------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 2e85ed9f9c..7d7e6e5ee8 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -102,46 +102,46 @@ class JobSpec: JOB_SPECS = { - "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ), - "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ), - "msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ), - "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ), - "msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ), - "msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ), - "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ), - "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ), - "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ), - "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ), - "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ), - "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), - "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ), - "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ), - "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:3.0.20250408.124536", ), - "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ), - "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), - "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), - "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), - "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ), - "ios": JobSpec(name="iOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ), - "tvos": JobSpec(name="tvOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ), - "android-cmake": JobSpec(name="Android (CMake)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ), - "android-cmake-lean": JobSpec(name="Android (CMake, lean)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-lean-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, lean=True, ), - "android-mk": JobSpec(name="Android (Android.mk)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ), - "android-gradle": JobSpec(name="Android (Gradle)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ), - "emscripten": JobSpec(name="Emscripten", os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ), - "haiku": JobSpec(name="Haiku", os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ), - "loongarch64": JobSpec(name="LoongArch64", os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ), - "n3ds": JobSpec(name="Nintendo 3DS", os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ), - "ppc": JobSpec(name="PowerPC", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ), - "ppc64": JobSpec(name="PowerPC64", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC64, artifact="SDL-ppc64le", container="dockcross/linux-ppc64le:latest", ), - "ps2": JobSpec(name="Sony PlayStation 2", os=JobOs.UbuntuLatest, platform=SdlPlatform.Ps2, artifact="SDL-ps2", container="ps2dev/ps2dev:latest", ), - "psp": JobSpec(name="Sony PlayStation Portable", os=JobOs.UbuntuLatest, platform=SdlPlatform.Psp, artifact="SDL-psp", container="pspdev/pspdev:latest", ), - "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pib", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib, ), - "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ), - "riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ), - "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), - "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), - "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), + # "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ), + # "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ), + # "msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ), + # "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ), + # "msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ), + # "msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ), + # "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ), + # "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ), + # "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ), + # "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ), + # "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ), + # "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), + # "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ), + # "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ), + # "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:3.0.20250408.124536", ), + # "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ), + # "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), + # "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), + # "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), + # "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ), + # "ios": JobSpec(name="iOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ), + # "tvos": JobSpec(name="tvOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ), + # "android-cmake": JobSpec(name="Android (CMake)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ), + # "android-cmake-lean": JobSpec(name="Android (CMake, lean)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-lean-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, lean=True, ), + # "android-mk": JobSpec(name="Android (Android.mk)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ), + # "android-gradle": JobSpec(name="Android (Gradle)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ), + # "emscripten": JobSpec(name="Emscripten", os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ), + # "haiku": JobSpec(name="Haiku", os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ), + # "loongarch64": JobSpec(name="LoongArch64", os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ), + # "n3ds": JobSpec(name="Nintendo 3DS", os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ), + # "ppc": JobSpec(name="PowerPC", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ), + # "ppc64": JobSpec(name="PowerPC64", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC64, artifact="SDL-ppc64le", container="dockcross/linux-ppc64le:latest", ), + # "ps2": JobSpec(name="Sony PlayStation 2", os=JobOs.UbuntuLatest, platform=SdlPlatform.Ps2, artifact="SDL-ps2", container="ps2dev/ps2dev:latest", ), + # "psp": JobSpec(name="Sony PlayStation Portable", os=JobOs.UbuntuLatest, platform=SdlPlatform.Psp, artifact="SDL-psp", container="pspdev/pspdev:latest", ), + # "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pib", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib, ), + # "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ), + # "riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ), + # "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), + # "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), + # "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), } From 15cbc266ecfb90a276ff1a5bf917cb44e496c070 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Fri, 30 May 2025 19:32:06 +0800 Subject: [PATCH 03/92] Harmony port: Workflows (fix script error) --- .github/workflows/create-test-plan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 7d7e6e5ee8..7a1f00c0bf 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -99,6 +99,7 @@ class JobSpec: clang_cl: bool = False gdk: bool = False vita_gles: Optional[VitaGLES] = None + harmony_arch: Optional[str] = None JOB_SPECS = { From 95ccfa69e5e8e5d1367ff097ff5dea5ba6ab44e5 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Fri, 30 May 2025 19:33:53 +0800 Subject: [PATCH 04/92] Harmony port: Workflows (fix script error) --- .github/workflows/create-test-plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 7a1f00c0bf..3b71e8d883 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -130,7 +130,7 @@ JOB_SPECS = { # "android-mk": JobSpec(name="Android (Android.mk)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ), # "android-gradle": JobSpec(name="Android (Gradle)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ), # "emscripten": JobSpec(name="Emscripten", os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ), - # "haiku": JobSpec(name="Haiku", os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ), + "haiku": JobSpec(name="Haiku", os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ), # "loongarch64": JobSpec(name="LoongArch64", os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ), # "n3ds": JobSpec(name="Nintendo 3DS", os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ), # "ppc": JobSpec(name="PowerPC", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ), From 8f0b9c1151a93fb9f2bc138d3e2267382388712d Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Fri, 30 May 2025 19:54:09 +0800 Subject: [PATCH 05/92] Harmony port: Workflows (fix script error) --- .github/workflows/generic.yml | 3 +++ CMakeLists.txt | 21 +++++++++++++++++++++ cmake/macros.cmake | 2 +- include/SDL3/SDL_platform_defines.h | 5 +++++ src/audio/SDL_audiotypecvt.c | 4 ++++ src/thread/pthread/SDL_systhread.c | 2 +- 6 files changed, 35 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index 083859b341..1cd6b62411 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -51,6 +51,9 @@ jobs: uses: ./.github/actions/setup-msvc-libusb with: arch: ${{ matrix.platform.setup-libusb-arch }} + - name: 'Set up Harmony toolchain' + if: ${{ matrix.platform.platform == 'harmony' }} + uses: ./.github/actions/setup-harmony-toolchain - uses: mymindstorm/setup-emsdk@v14 if: ${{ matrix.platform.platform == 'emscripten' }} with: diff --git a/CMakeLists.txt b/CMakeLists.txt index fd62e985f0..2c1abba5a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1502,7 +1502,28 @@ if(ANDROID) endif() endif() endif() +elseif(OHOS) + # disable warnings from the toolchain + sdl_compile_options(PRIVATE "-Wno-unused-command-line-argument") + set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN "") + set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") + + sdl_link_dependency(OHOS_LIBS LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) + + set(SDL_LOADSO_DLOPEN 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c") + set(HAVE_SDL_LOADSO TRUE) + + set(SDL_TIME_UNIX 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c") + set(HAVE_SDL_TIME TRUE) + + set(SDL_TIMER_UNIX 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c") + set(HAVE_SDL_TIMERS TRUE) + + CheckPTHREAD() elseif(EMSCRIPTEN) # Hide noisy warnings that intend to aid mostly during initial stages of porting a new # project. Uncomment at will for verbose cross-compiling -I/../ path info. diff --git a/cmake/macros.cmake b/cmake/macros.cmake index 3ee413c52f..f5adebc3e8 100644 --- a/cmake/macros.cmake +++ b/cmake/macros.cmake @@ -373,7 +373,7 @@ function(SDL_PrintSummary) message(STATUS "") endif() - if(UNIX AND NOT (ANDROID OR APPLE OR EMSCRIPTEN OR HAIKU OR RISCOS)) + if(UNIX AND NOT (ANDROID OR APPLE OR EMSCRIPTEN OR HAIKU OR RISCOS OR OHOS)) if(NOT (HAVE_X11 OR HAVE_WAYLAND)) if(NOT SDL_UNIX_CONSOLE_BUILD) message(FATAL_ERROR diff --git a/include/SDL3/SDL_platform_defines.h b/include/SDL3/SDL_platform_defines.h index f7f14be005..a8ebbfd7d0 100644 --- a/include/SDL3/SDL_platform_defines.h +++ b/include/SDL3/SDL_platform_defines.h @@ -112,6 +112,11 @@ #undef SDL_PLATFORM_LINUX #endif +#if defined(OHOS) || defined(__OHOS__) +#define SDL_PLATFORM_OHOS 1 +#undef SDL_PLATFORM_LINUX +#endif + #if defined(__unix__) || defined(__unix) || defined(unix) /** diff --git a/src/audio/SDL_audiotypecvt.c b/src/audio/SDL_audiotypecvt.c index a27575f239..abb72e961e 100644 --- a/src/audio/SDL_audiotypecvt.c +++ b/src/audio/SDL_audiotypecvt.c @@ -536,9 +536,11 @@ static void SDL_TARGETING("ssse3") SDL_Convert_Swap32_SSSE3(Uint32* dst, const U // be guarded by the STDC FENV_ACCESS pragma; otherwise, it's undefined // behavior. However, the compiler support for this pragma is bad. #if defined(__clang__) +#ifndef SDL_PLATFORM_OHOS #if __clang_major__ >= 12 #pragma STDC FENV_ACCESS ON #endif +#endif #elif defined(_MSC_VER) #pragma fenv_access (on) #elif defined(__GNUC__) @@ -813,9 +815,11 @@ static void SDL_Convert_Swap32_NEON(Uint32* dst, const Uint32* src, int num_samp } #if defined(__clang__) +#ifndef SDL_PLATFORM_OHOS #if __clang_major__ >= 12 #pragma STDC FENV_ACCESS DEFAULT #endif +#endif #elif defined(_MSC_VER) #pragma fenv_access (off) #elif defined(__GNUC__) diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c index ae4a94c2e2..05ad396956 100644 --- a/src/thread/pthread/SDL_systhread.c +++ b/src/thread/pthread/SDL_systhread.c @@ -169,7 +169,7 @@ void SDL_SYS_SetupThread(const char *name) pthread_sigmask(SIG_BLOCK, &mask, 0); #endif -#ifdef PTHREAD_CANCEL_ASYNCHRONOUS +#if defined(PTHREAD_CANCEL_ASYNCHRONOUS) && !defined(SDL_PLATFORM_OHOS) // Allow ourselves to be asynchronously cancelled { int oldstate; From 1c48676f4f2d3a6bbeac780db91fec673e6b5c92 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Fri, 30 May 2025 20:21:35 +0800 Subject: [PATCH 06/92] Harmony port: window fetching --- CMakeLists.txt | 1 + include/build_config/SDL_build_config.h.cmake | 2 + src/SDL_log.c | 28 ++++- src/core/ohos/SDL_ohos.c | 106 ++++++++++++++++++ src/core/ohos/SDL_ohos.h | 12 ++ 5 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/core/ohos/SDL_ohos.c create mode 100644 src/core/ohos/SDL_ohos.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c1abba5a5..b89e777c8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1510,6 +1510,7 @@ elseif(OHOS) set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") sdl_link_dependency(OHOS_LIBS LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ohos/*.c") set(SDL_LOADSO_DLOPEN 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c") diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 3cd00ed956..f58d43ea1c 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -265,6 +265,7 @@ #cmakedefine SDL_AUDIO_DRIVER_JACK 1 #cmakedefine SDL_AUDIO_DRIVER_JACK_DYNAMIC @SDL_AUDIO_DRIVER_JACK_DYNAMIC@ #cmakedefine SDL_AUDIO_DRIVER_NETBSD 1 +#cmakedefine SDL_VIDEO_DRIVER_OHOS 1 #cmakedefine SDL_AUDIO_DRIVER_OSS 1 #cmakedefine SDL_AUDIO_DRIVER_PIPEWIRE 1 #cmakedefine SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC @SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC@ @@ -391,6 +392,7 @@ #cmakedefine SDL_VIDEO_DRIVER_N3DS 1 #cmakedefine SDL_VIDEO_DRIVER_NGAGE 1 #cmakedefine SDL_VIDEO_DRIVER_OFFSCREEN 1 +#cmakedefine SDL_VIDEO_DRIVER_OHOS 1 #cmakedefine SDL_VIDEO_DRIVER_PS2 1 #cmakedefine SDL_VIDEO_DRIVER_PSP 1 #cmakedefine SDL_VIDEO_DRIVER_RISCOS 1 diff --git a/src/SDL_log.c b/src/SDL_log.c index da55dcf1c1..2e159fba7b 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -36,6 +36,10 @@ #include #endif +#ifdef SDL_PLATFORM_OHOS +#include +#endif + #include "stdlib/SDL_vacopy.h" // The size of the stack buffer to use for rendering log messages. @@ -120,6 +124,19 @@ static int SDL_android_priority[] = { SDL_COMPILE_TIME_ASSERT(android_priority, SDL_arraysize(SDL_android_priority) == SDL_LOG_PRIORITY_COUNT); #endif // SDL_PLATFORM_ANDROID +#ifdef SDL_PLATFORM_OHOS +static int SDL_ohos_priority[] = { + LOG_DEBUG, + LOG_DEBUG, + LOG_DEBUG, + LOG_DEBUG, + LOG_INFO, + LOG_WARN, + LOG_ERROR, + LOG_FATAL +}; +#endif + static void SDLCALL SDL_LoggingChanged(void *userdata, const char *name, const char *oldValue, const char *hint) { SDL_ResetLogPriorities(); @@ -556,7 +573,7 @@ void SDL_LogMessage(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_ST va_end(ap); } -#ifdef SDL_PLATFORM_ANDROID +#if defined(SDL_PLATFORM_ANDROID) || defined(SDL_PLATFORM_OHOS) static const char *GetCategoryPrefix(int category) { if (category < SDL_LOG_CATEGORY_RESERVED2) { @@ -567,7 +584,7 @@ static const char *GetCategoryPrefix(int category) } return "CUSTOM"; } -#endif // SDL_PLATFORM_ANDROID +#endif void SDL_LogMessageV(int category, SDL_LogPriority priority, SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) { @@ -751,6 +768,13 @@ static void SDLCALL SDL_LogOutput(void *userdata, int category, SDL_LogPriority SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category)); __android_log_write(SDL_android_priority[priority], tag, message); } + #elif defined(SDL_PLATFORM_OHOS) + { + char tag[32]; + + SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category)); + OH_LOG_Print(LOG_APP, SDL_ohos_priority[priority], 0, tag, "%{public}s", message); + } #elif defined(SDL_PLATFORM_APPLE) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT)) /* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now. */ diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c new file mode 100644 index 0000000000..3f3f4ffedd --- /dev/null +++ b/src/core/ohos/SDL_ohos.c @@ -0,0 +1,106 @@ +#include "SDL_internal.h" + +#ifdef SDL_PLATFORM_OHOS + +#include "napi/native_api.h" +#include "SDL_ohos.h" +#include + +OHNativeWindow *nativeWindow; +SDL_Mutex *g_ohosPageMutex = NULL; +static OH_NativeXComponent_Callback callback; +static OH_NativeXComponent_MouseEvent_Callback mouseCallback; + +static napi_value minus(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value args[2] = { NULL }; + + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + napi_valuetype valuetype1; + napi_typeof(env, args[1], &valuetype1); + + double value0; + napi_get_value_double(env, args[0], &value0); + + double value1; + napi_get_value_double(env, args[1], &value1); + + napi_value sum; + napi_create_double(env, value0 - value1, &sum); + + return sum; +} + +static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) +{ + nativeWindow = (OHNativeWindow *)window; + + SDL_Log("Native Window: %p", nativeWindow); +} +static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) {} +static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) {} +static void onKeyEvent(OH_NativeXComponent *component, void *window) {} +static void onNativeTouch(OH_NativeXComponent *component, void *window) {} +static void onNativeMouse(OH_NativeXComponent *component, void *window) {} +static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) {} +void OnHoverEvent(OH_NativeXComponent *component, bool isHover) {} +void OnFocusEvent(OH_NativeXComponent *component, void *window) {} +void OnBlurEvent(OH_NativeXComponent *component, void *window) {} + +static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "minus", NULL, minus, NULL, NULL, NULL, napi_default, NULL } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + + napi_value exportInstance = NULL; + if (napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance) != napi_ok) { + return exports; + } + OH_NativeXComponent *nativeXComponent; + if (napi_unwrap(env, exportInstance, (void **)(&nativeXComponent)) != napi_ok) { + return exports; + } + + callback.OnSurfaceCreated = OnSurfaceCreatedCB; + callback.OnSurfaceChanged = OnSurfaceChangedCB; + callback.OnSurfaceDestroyed = OnSurfaceDestroyedCB; + callback.DispatchTouchEvent = onNativeTouch; + OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback); + + mouseCallback.DispatchMouseEvent = OnDispatchTouchEventCB; + mouseCallback.DispatchMouseEvent = onNativeMouse; + mouseCallback.DispatchHoverEvent = OnHoverEvent; + OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback); + + OH_NativeXComponent_RegisterKeyEventCallback(nativeXComponent, onKeyEvent); + OH_NativeXComponent_RegisterFocusEventCallback(nativeXComponent, OnFocusEvent); + OH_NativeXComponent_RegisterBlurEventCallback(nativeXComponent, OnBlurEvent); + + g_ohosPageMutex = SDL_CreateMutex(); + + return exports; +} + +napi_module OHOS_NAPI_Module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = NULL, + .nm_register_func = SDL_OHOS_NAPI_Init, + .nm_modname = "SDL3", + .nm_priv = ((void *)0), + .reserved = { 0 }, +}; + +__attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&OHOS_NAPI_Module); +} + +#endif diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h new file mode 100644 index 0000000000..ddea0b43ca --- /dev/null +++ b/src/core/ohos/SDL_ohos.h @@ -0,0 +1,12 @@ +#ifndef SDL_OHOS_H +#define SDL_OHOS_H + +#include "SDL3/SDL_mutex.h" +#include "video/SDL_sysvideo.h" +#include + +extern SDL_Mutex *g_ohosPageMutex; +void SDL_OHOS_SetDisplayOrientation(int orientation); +extern OHNativeWindow *nativeWindow; + +#endif From addb748c64fd898b6d99a9005eeaa972cfe9d37a Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 08:59:06 +0800 Subject: [PATCH 07/92] Harmony port: disable lib version suffix --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index b89e777c8e..c5e0b3b52b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3554,6 +3554,8 @@ if(SDL_SHARED) RESOURCE "${SDL_FRAMEWORK_RESOURCES}" ) endif() + elseif(OHOS) + # disable libtool postfix elseif(UNIX AND NOT ANDROID) set_target_properties(SDL3-shared PROPERTIES VERSION "${SDL_SO_VERSION}" From 845ba7d5cee34feec3026abcb4035446e79f1b04 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 14:03:05 +0800 Subject: [PATCH 08/92] Harmony port: video vulkan library & disable version test --- .github/workflows/generic.yml | 2 +- CMakeLists.txt | 10 ++++ src/video/SDL_sysvideo.h | 1 + src/video/ohos/SDL_ohosvideo.c | 39 ++++++++++++++++ src/video/ohos/SDL_ohosvulkan.c | 82 +++++++++++++++++++++++++++++++++ src/video/ohos/SDL_ohosvulkan.h | 11 +++++ 6 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 src/video/ohos/SDL_ohosvideo.c create mode 100644 src/video/ohos/SDL_ohosvulkan.c create mode 100644 src/video/ohos/SDL_ohosvulkan.h diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index 1cd6b62411..e50ac9857d 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -236,7 +236,7 @@ jobs: ${{ matrix.platform.source-cmd }} cmake --build build --config ${{ matrix.platform.cmake-build-type }} --verbose -- ${{ matrix.platform.cmake-build-arguments }} - name: 'Verify SDL_REVISION' - if: ${{ !matrix.platform.no-cmake }} + if: ${{ !matrix.platform.no-cmake && matrix.platform.platform != 'harmony' }} run: | echo "This should show us the SDL_REVISION" echo "Shared library:" diff --git a/CMakeLists.txt b/CMakeLists.txt index c5e0b3b52b..f5b179d029 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1512,6 +1512,16 @@ elseif(OHOS) sdl_link_dependency(OHOS_LIBS LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ohos/*.c") + if(SDL_VIDEO) + set(SDL_VIDEO_DRIVER_OHOS 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/ohos/*.c") + set(HAVE_SDL_VIDEO TRUE) + set(SDL_VULKAN ON) + set(HAVE_VULKAN ON) + set(SDL_VIDEO_VULKAN ON) + set(HAVE_RENDER_VULKAN TRUE) + endif() + set(SDL_LOADSO_DLOPEN 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c") set(HAVE_SDL_LOADSO TRUE) diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 8396addb00..b53b869f6a 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -542,6 +542,7 @@ extern VideoBootStrap Emscripten_bootstrap; extern VideoBootStrap OFFSCREEN_bootstrap; extern VideoBootStrap QNX_bootstrap; extern VideoBootStrap OPENVR_bootstrap; +extern VideoBootStrap OHOS_bootstrap; extern bool SDL_UninitializedVideo(void); // Use SDL_OnVideoThread() sparingly, to avoid regressions in use cases that currently happen to work diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c new file mode 100644 index 0000000000..effafc4b1c --- /dev/null +++ b/src/video/ohos/SDL_ohosvideo.c @@ -0,0 +1,39 @@ +#include "SDL_internal.h" +#include "../SDL_sysvideo.h" + +#ifdef SDL_VIDEO_DRIVER_OHOS +#include "SDL_ohosvulkan.h" + +bool OHOS_VideoInit(SDL_VideoDevice *_this) +{ + return true; +} +void OHOS_VideoQuit(SDL_VideoDevice *_this) +{ +} +static SDL_VideoDevice *OHOS_CreateDevice(void) +{ + SDL_VideoDevice *device; + + device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + return NULL; + } + + device->VideoInit = OHOS_VideoInit; + device->VideoQuit = OHOS_VideoQuit; +#ifdef SDL_VIDEO_VULKAN + device->Vulkan_LoadLibrary = OHOS_Vulkan_LoadLibrary; + device->Vulkan_UnloadLibrary = OHOS_Vulkan_UnloadLibrary; +#endif + + + return device; +} +VideoBootStrap OHOS_bootstrap = { + "ohos", "OpenHarmony video driver", + OHOS_CreateDevice, + NULL, + false +}; +#endif diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c new file mode 100644 index 0000000000..f3869b1051 --- /dev/null +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -0,0 +1,82 @@ +#include "SDL_ohosvulkan.h" +#include "SDL_internal.h" +#include "../khronos/vulkan/vulkan.h" + +#ifdef SDL_VIDEO_DRIVER_OHOS + +static int loadedCount = 0; +bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path) +{ + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; + if (_this->vulkan_config.loader_handle) + { + return SDL_SetError("Vulkan already loaded"); + } + + /* Load the Vulkan loader library */ + if (!path) + { + path = SDL_getenv("SDL_VULKAN_LIBRARY"); + } + if (!path) + { + path = "libvulkan.so"; + } + _this->vulkan_config.loader_handle = SDL_LoadObject(path); + if (!_this->vulkan_config.loader_handle) + { + return false; + } + SDL_strlcpy(_this->vulkan_config.loader_path, path, + SDL_arraysize(_this->vulkan_config.loader_path)); + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( + _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) + { + goto fail; + } + _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; + _this->vulkan_config.vkEnumerateInstanceExtensionProperties = + (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( + VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); + if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) + { + goto fail; + } + loadedCount++; + return true; + +fail: + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + return false; +} + +void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this) +{ + if (loadedCount == 0) + { + return; + } + loadedCount--; + if (_this->vulkan_config.loader_handle && loadedCount == 0) { + SDL_UnloadObject(_this->vulkan_config.loader_handle); + _this->vulkan_config.loader_handle = NULL; + } +} + +/*bool OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, SDL_Window *window, unsigned *count, + const char **names) +{ + static const char *const extensionsForOHOS[] = { + VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_OHOS_XCOMPONENT_EXTENSION_NAME + }; + if (!_this->vulkan_config.loader_handle) { + SDL_SetError("Vulkan is not loaded"); + return false; + } + return SDL_Vulkan_GetInstanceExtensions_Helper( + count, names, SDL_arraysize(extensionsForOHOS), extensionsForOHOS); +}*/ + +#endif diff --git a/src/video/ohos/SDL_ohosvulkan.h b/src/video/ohos/SDL_ohosvulkan.h new file mode 100644 index 0000000000..8a3364e3ca --- /dev/null +++ b/src/video/ohos/SDL_ohosvulkan.h @@ -0,0 +1,11 @@ +#ifndef SDL_OHOSVULKAN_H +#define SDL_OHOSVULKAN_H + +#ifdef SDL_VIDEO_DRIVER_OHOS +#include "../SDL_sysvideo.h" + +bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path); +void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this); +#endif + +#endif From f25cbb135c90973921905664f24453b719758c6a Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 14:12:02 +0800 Subject: [PATCH 09/92] Harmony port: video vulkan library & disable version test --- src/video/khronos/vulkan/vulkan_ohos.h | 124 +++++++++++++++++++++++++ src/video/ohos/SDL_ohosvideo.c | 1 + src/video/ohos/SDL_ohosvulkan.c | 15 ++- src/video/ohos/SDL_ohosvulkan.h | 1 + 4 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 src/video/khronos/vulkan/vulkan_ohos.h diff --git a/src/video/khronos/vulkan/vulkan_ohos.h b/src/video/khronos/vulkan/vulkan_ohos.h new file mode 100644 index 0000000000..b3e18c19c0 --- /dev/null +++ b/src/video/khronos/vulkan/vulkan_ohos.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef VULKAN_OHOS_H +#define VULKAN_OHOS_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define VK_KHR_OHOS_XCOMPONENT 1 +struct ONativeWindow; + +#define VK_KHR_OHOS_XCOMPONENT_SPEC_VERSION 6 +#define VK_KHR_OHOS_XCOMPONENT_EXTENSION_NAME "VK_OHOS_surface" + +typedef VkFlags VkOHOSXComponentCreateFlagsKHR; + +typedef struct VkOHOSXComponentCreateInfoKHR { + VkStructureType sType; + const void* pNext; + VkOHOSXComponentCreateFlagsKHR flags; + struct OHNativeWindow* window; +} VkOHOSXComponentCreateInfoKHR; + +typedef VkResult (VKAPI_PTR *PFN_vkCreateOHOSXComponentKHR)(VkInstance instance, + const VkOHOSXComponentCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pXComponent); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkCreateOHOSXComponentKHR( + VkInstance instance, + const VkOHOSXComponentCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface); +#endif + +#define VK_OHOS_EXTERNAL_MEMORY_OHOS_HARDWARE_BUFFER 1 +struct OHardwareBuffer; + +#define VK_OHOS_EXTERNAL_MEMORY_OHOS_HARDWARE_BUFFER_SPEC_VERSION 3 +#define VK_OHOS_EXTERNAL_MEMORY_OHOS_HARDWARE_BUFFER_EXTENSION_NAME "VK_OHOS_EXTERNAL_MEMORY_OHOS_HARDWARE_BUFFER" + +typedef struct VkOHOSHardwareBufferUsageOHOS { + VkStructureType sType; + void* pNext; + uint64_t ohosHardwareBufferUsage; +} VkOHOSHardwareBufferUsageOHOS; + +typedef struct VkOHOSHardwareBufferPropertiesOHOS { + VkStructureType sType; + void* pNext; + VkDeviceSize allocationSize; + uint32_t memoryTypeBits; +} VkOHOSHardwareBufferPropertiesOHOS; + +typedef struct VkOHOSHardwareBufferFormatPropertiesOHOS { + VkStructureType sType; + void* pNext; + VkFormat format; + uint64_t externalFormat; + VkFormatFeatureFlags formatFeatures; + VkComponentMapping samplerYcbcrConversionComponents; + VkSamplerYcbcrModelConversion suggestedYcbcrModel; + VkSamplerYcbcrRange suggestedYcbcrRange; + VkChromaLocation suggestedXChromaOffset; + VkChromaLocation suggestedYChromaOffset; +} VkOHOSHardwareBufferFormatPropertiesOHOS; + +typedef struct VkImportOHOSHardwareBufferInfoOHOS { + VkStructureType sType; + const void* pNext; + struct OHardwareBuffer* buffer; +} VkImportOHOSHardwareBufferInfoOHOS; + +typedef struct VkMemoryGetOHOSHardwareBufferInfoOHOS { + VkStructureType sType; + const void* pNext; + VkDeviceMemory memory; +} VkMemoryGetOHOSHardwareBufferInfoOHOS; + +typedef struct VkExternalFormatOHOS { + VkStructureType sType; + void* pNext; + uint64_t externalFormat; +} VkExternalFormatOHOS; + + +typedef VkResult (VKAPI_PTR *PFN_vkGetOHOSHardwareBufferPropertiesOHOS)(VkDevice device, + const struct OHardwareBuffer* buffer, VkOHOSHardwareBufferPropertiesOHOS* pProperties); +typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryOHOSHardwareBufferOHOS)(VkDevice device, + const VkMemoryGetOHOSHardwareBufferInfoOHOS* pInfo, struct OHardwareBuffer** pBuffer); + +#ifndef VK_NO_PROTOTYPES +VKAPI_ATTR VkResult VKAPI_CALL vkGetOHOSHardwareBufferPropertiesOHOS( + VkDevice device, + const struct OHardwareBuffer* buffer, + VkOHOSHardwareBufferPropertiesOHOS* pProperties); + +VKAPI_ATTR VkResult VKAPI_CALL vkGetMemoryOHOSHardwareBufferOHOS( + VkDevice device, + const VkMemoryGetOHOSHardwareBufferInfoOHOS* pInfo, + struct OHardwareBuffer** pBuffer); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index effafc4b1c..6816b61ccc 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -25,6 +25,7 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) #ifdef SDL_VIDEO_VULKAN device->Vulkan_LoadLibrary = OHOS_Vulkan_LoadLibrary; device->Vulkan_UnloadLibrary = OHOS_Vulkan_UnloadLibrary; + device->Vulkan_GetInstanceExtensions = OHOS_Vulkan_GetInstanceExtensions; #endif diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c index f3869b1051..1b9dc78d55 100644 --- a/src/video/ohos/SDL_ohosvulkan.c +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -1,6 +1,6 @@ #include "SDL_ohosvulkan.h" #include "SDL_internal.h" -#include "../khronos/vulkan/vulkan.h" +#include "../khronos/vulkan/vulkan_ohos.h" #ifdef SDL_VIDEO_DRIVER_OHOS @@ -65,18 +65,15 @@ void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this) } } -/*bool OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, SDL_Window *window, unsigned *count, - const char **names) +char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count) { static const char *const extensionsForOHOS[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_OHOS_XCOMPONENT_EXTENSION_NAME }; - if (!_this->vulkan_config.loader_handle) { - SDL_SetError("Vulkan is not loaded"); - return false; + if (count) { + *count = SDL_arraysize(extensionsForOHOS); } - return SDL_Vulkan_GetInstanceExtensions_Helper( - count, names, SDL_arraysize(extensionsForOHOS), extensionsForOHOS); -}*/ + return extensionsForOHOS; +} #endif diff --git a/src/video/ohos/SDL_ohosvulkan.h b/src/video/ohos/SDL_ohosvulkan.h index 8a3364e3ca..6ea21a13d6 100644 --- a/src/video/ohos/SDL_ohosvulkan.h +++ b/src/video/ohos/SDL_ohosvulkan.h @@ -6,6 +6,7 @@ bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path); void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this); +char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count); #endif #endif From 4f5fcf6a16048ab8dac667eeb54b94001a4f8c08 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 14:24:53 +0800 Subject: [PATCH 10/92] Harmony port: video vulkan library & disable version test --- src/video/ohos/SDL_ohosvulkan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c index 1b9dc78d55..9b90d280da 100644 --- a/src/video/ohos/SDL_ohosvulkan.c +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -3,6 +3,7 @@ #include "../khronos/vulkan/vulkan_ohos.h" #ifdef SDL_VIDEO_DRIVER_OHOS +#include "../SDL_sysvideo.h" static int loadedCount = 0; bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path) From e339bde5058981cacd1927a551530fff5a6b63cb Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 15:13:29 +0800 Subject: [PATCH 11/92] Harmony port: video vulkan library --- src/core/ohos/SDL_ohos.h | 1 - src/video/ohos/SDL_ohosvideo.c | 2 ++ src/video/ohos/SDL_ohosvulkan.c | 60 +++++++++++++++++++++++++++++++-- src/video/ohos/SDL_ohosvulkan.h | 9 +++++ 4 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index ddea0b43ca..bcc2537d6b 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -6,7 +6,6 @@ #include extern SDL_Mutex *g_ohosPageMutex; -void SDL_OHOS_SetDisplayOrientation(int orientation); extern OHNativeWindow *nativeWindow; #endif diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index 6816b61ccc..e5e835c5a8 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -26,6 +26,8 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) device->Vulkan_LoadLibrary = OHOS_Vulkan_LoadLibrary; device->Vulkan_UnloadLibrary = OHOS_Vulkan_UnloadLibrary; device->Vulkan_GetInstanceExtensions = OHOS_Vulkan_GetInstanceExtensions; + device->Vulkan_CreateSurface = OHOS_Vulkan_CreateSurface; + device->Vulkan_DestroySurface = OHOS_Vulkan_DestroySurface; #endif diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c index 9b90d280da..6742189dbb 100644 --- a/src/video/ohos/SDL_ohosvulkan.c +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -1,9 +1,14 @@ #include "SDL_ohosvulkan.h" #include "SDL_internal.h" -#include "../khronos/vulkan/vulkan_ohos.h" +#include #ifdef SDL_VIDEO_DRIVER_OHOS +#define VK_USE_PLATFORM_OHOS 1 +#include "vulkan/vulkan.h" #include "../SDL_sysvideo.h" +#include "../../core/ohos/SDL_ohos.h" +#include "vulkan/vulkan_ohos.h" +#include static int loadedCount = 0; bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path) @@ -69,7 +74,7 @@ void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this) char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count) { static const char *const extensionsForOHOS[] = { - VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_OHOS_XCOMPONENT_EXTENSION_NAME + VK_KHR_SURFACE_EXTENSION_NAME, VK_OHOS_SURFACE_EXTENSION_NAME }; if (count) { *count = SDL_arraysize(extensionsForOHOS); @@ -77,4 +82,55 @@ char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uin return extensionsForOHOS; } +bool OHOS_Vulkan_CreateSurface(SDL_VideoDevice *_this, + SDL_Window *window, + VkInstance instance, + const struct VkAllocationCallbacks *allocator, + VkSurfaceKHR *surface) +{ + VkResult result; + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkCreateSurfaceOHOS vkCreateSurfaceOHOS = + (PFN_vkCreateSurfaceOHOS)vkGetInstanceProcAddr(instance, "vkCreateSurfaceOHOS"); + VkSurfaceCreateInfoOHOS createInfo; + + if (!_this->vulkan_config.loader_handle) { + SDL_SetError("Vulkan is not loaded"); + return false; + } + + if (!vkCreateSurfaceOHOS) { + SDL_SetError(VK_OHOS_SURFACE_EXTENSION_NAME + " extension is not enabled in the Vulkan instance."); + return false; + } + + SDL_zero(createInfo); + createInfo.sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS; + createInfo.pNext = NULL; + createInfo.flags = 0; + createInfo.window = nativeWindow; + result = vkCreateSurfaceOHOS(instance, &createInfo, NULL, surface); + if (result != VK_SUCCESS) { + SDL_SetError("vkCreateSurfaceOHOS failed: %d", result); + return false; + } + return true; +} + +void OHOS_Vulkan_DestroySurface(SDL_VideoDevice *_this, + VkInstance instance, + VkSurfaceKHR surface, + const struct VkAllocationCallbacks *allocator) +{ + if (_this->vulkan_config.loader_handle) { + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = + (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr; + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR = (PFN_vkDestroySurfaceKHR)vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"); + vkDestroySurfaceKHR(instance, surface, allocator); + } +} + #endif diff --git a/src/video/ohos/SDL_ohosvulkan.h b/src/video/ohos/SDL_ohosvulkan.h index 6ea21a13d6..5700c29866 100644 --- a/src/video/ohos/SDL_ohosvulkan.h +++ b/src/video/ohos/SDL_ohosvulkan.h @@ -7,6 +7,15 @@ bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path); void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this); char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count); +bool OHOS_Vulkan_CreateSurface(SDL_VideoDevice *_this, + SDL_Window *window, + VkInstance instance, + const struct VkAllocationCallbacks *allocator, + VkSurfaceKHR *surface); +void OHOS_Vulkan_DestroySurface(SDL_VideoDevice *_this, + VkInstance instance, + VkSurfaceKHR surface, + const struct VkAllocationCallbacks *allocator); #endif #endif From 1e75f1fa6cf68c3b56fa8b553d7df668113521ea Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 15:43:31 +0800 Subject: [PATCH 12/92] Harmony port: video vulkan library --- CMakeLists.txt | 9 +++++++++ src/core/ohos/SDL_ohos.c | 15 +++++++++++++++ src/core/ohos/SDL_ohos.h | 1 + src/video/ohos/SDL_ohosvideo.c | 1 - src/video/ohos/SDL_ohosvideo.h | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/video/ohos/SDL_ohosvideo.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f5b179d029..52021d8a55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1520,6 +1520,15 @@ elseif(OHOS) set(HAVE_VULKAN ON) set(SDL_VIDEO_VULKAN ON) set(HAVE_RENDER_VULKAN TRUE) + + if(SDL_OPENGLES) + set(SDL_VIDEO_OPENGL_EGL 1) + set(HAVE_OPENGLES TRUE) + set(SDL_VIDEO_OPENGL_ES2 1) + set(SDL_VIDEO_RENDER_OGL_ES2 1) + + sdl_link_dependency(opengles LIBS GLESv2) + endif() endif() set(SDL_LOADSO_DLOPEN 1) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 3f3f4ffedd..2fca870f5f 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -5,11 +5,13 @@ #include "napi/native_api.h" #include "SDL_ohos.h" #include +#include "../../video/ohos/SDL_ohosvideo.h" OHNativeWindow *nativeWindow; SDL_Mutex *g_ohosPageMutex = NULL; static OH_NativeXComponent_Callback callback; static OH_NativeXComponent_MouseEvent_Callback mouseCallback; +SDL_WindowData data; static napi_value minus(napi_env env, napi_callback_info info) { @@ -40,7 +42,20 @@ static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { nativeWindow = (OHNativeWindow *)window; + uint64_t width; + uint64_t height; + double offsetX; + double offsetY; + OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); + SDL_Log("Native Window: %p", nativeWindow); + + data.native_window = nativeWindow; + data.width = width; + data.height = height; + data.x = offsetX; + data.y = offsetY; } static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) {} static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) {} diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index bcc2537d6b..8440f07386 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -7,5 +7,6 @@ extern SDL_Mutex *g_ohosPageMutex; extern OHNativeWindow *nativeWindow; +extern SDL_WindowData data; #endif diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index e5e835c5a8..d4df17c2a2 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -30,7 +30,6 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) device->Vulkan_DestroySurface = OHOS_Vulkan_DestroySurface; #endif - return device; } VideoBootStrap OHOS_bootstrap = { diff --git a/src/video/ohos/SDL_ohosvideo.h b/src/video/ohos/SDL_ohosvideo.h new file mode 100644 index 0000000000..a402429b6e --- /dev/null +++ b/src/video/ohos/SDL_ohosvideo.h @@ -0,0 +1,19 @@ +#ifndef SDL_OHOSVIDEO_H +#define SDL_OHOSVIDEO_H + +#include "../SDL_egl_c.h" +#include "../../core/ohos/SDL_ohos.h" +struct SDL_WindowData { +#ifdef SDL_VIDEO_OPENGL_EGL + EGLSurface egl_xcomponent; + EGLContext egl_context; +#endif + bool backup_done; + OHNativeWindow *native_window; + uint64_t width; + uint64_t height; + double x; + double y; +}; + +#endif From cd0d25ca11702cab823025f3c16a36df6bc82548 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 16:16:45 +0800 Subject: [PATCH 13/92] Harmony port: video library --- src/core/ohos/SDL_ohos.c | 46 +++++++++++++++++++++++++++------ src/core/ohos/SDL_ohos.h | 9 ++++++- src/video/ohos/SDL_ohosvideo.c | 3 +++ src/video/ohos/SDL_ohoswindow.c | 4 +++ 4 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 src/video/ohos/SDL_ohoswindow.c diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 2fca870f5f..1f128c1e1c 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,6 @@ #include "SDL_internal.h" +#include +#include #ifdef SDL_PLATFORM_OHOS @@ -6,12 +8,14 @@ #include "SDL_ohos.h" #include #include "../../video/ohos/SDL_ohosvideo.h" +#include "SDL3/SDL_mutex.h" OHNativeWindow *nativeWindow; SDL_Mutex *g_ohosPageMutex = NULL; static OH_NativeXComponent_Callback callback; static OH_NativeXComponent_MouseEvent_Callback mouseCallback; -SDL_WindowData data; +SDL_WindowData windowData; +SDL_VideoData videoData; static napi_value minus(napi_env env, napi_callback_info info) { @@ -51,14 +55,40 @@ static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) SDL_Log("Native Window: %p", nativeWindow); - data.native_window = nativeWindow; - data.width = width; - data.height = height; - data.x = offsetX; - data.y = offsetY; + SDL_LockMutex(g_ohosPageMutex); + windowData.native_window = nativeWindow; + windowData.width = width; + windowData.height = height; + windowData.x = offsetX; + windowData.y = offsetY; + SDL_UnlockMutex(g_ohosPageMutex); +} +static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) +{ + nativeWindow = (OHNativeWindow *)window; + + uint64_t width; + uint64_t height; + double offsetX; + double offsetY; + OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); + OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); + + SDL_Log("Native Window: %p", nativeWindow); + + SDL_LockMutex(g_ohosPageMutex); + windowData.native_window = nativeWindow; + windowData.width = width; + windowData.height = height; + windowData.x = offsetX; + windowData.y = offsetY; + + SDL_UnlockMutex(g_ohosPageMutex); +} +static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) +{ + // SDL_VideoDevice* _this = SDL_GetVideoDevice(); } -static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) {} -static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) {} static void onKeyEvent(OH_NativeXComponent *component, void *window) {} static void onNativeTouch(OH_NativeXComponent *component, void *window) {} static void onNativeMouse(OH_NativeXComponent *component, void *window) {} diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 8440f07386..0df3a0bee0 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -7,6 +7,13 @@ extern SDL_Mutex *g_ohosPageMutex; extern OHNativeWindow *nativeWindow; -extern SDL_WindowData data; +extern SDL_WindowData windowData; +extern SDL_VideoData videoData; + +typedef struct SDL_VideoData { + SDL_Rect textRect; + int isPaused; + int isPausing; +} SDL_VideoData; #endif diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index d4df17c2a2..5372751666 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -3,6 +3,7 @@ #ifdef SDL_VIDEO_DRIVER_OHOS #include "SDL_ohosvulkan.h" +#include "../../core/ohos/SDL_ohos.h" bool OHOS_VideoInit(SDL_VideoDevice *_this) { @@ -20,6 +21,8 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) return NULL; } + device->internal = &videoData; + device->VideoInit = OHOS_VideoInit; device->VideoQuit = OHOS_VideoQuit; #ifdef SDL_VIDEO_VULKAN diff --git a/src/video/ohos/SDL_ohoswindow.c b/src/video/ohos/SDL_ohoswindow.c new file mode 100644 index 0000000000..10d54fba2f --- /dev/null +++ b/src/video/ohos/SDL_ohoswindow.c @@ -0,0 +1,4 @@ +#ifdef SDL_VIDEO_DRIVER_OHOS + + +#endif From 8b6c78c6881a5f3773ab54073178e0e70b22064f Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 16:53:23 +0800 Subject: [PATCH 14/92] Harmony port: window creation --- src/core/ohos/SDL_ohos.c | 12 +++++++++- src/video/ohos/SDL_ohosvideo.c | 3 +++ src/video/ohos/SDL_ohoswindow.c | 42 ++++++++++++++++++++++++++++++++- src/video/ohos/SDL_ohoswindow.h | 8 +++++++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 src/video/ohos/SDL_ohoswindow.h diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 1f128c1e1c..c1877645fc 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -87,7 +87,17 @@ static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) } static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { - // SDL_VideoDevice* _this = SDL_GetVideoDevice(); + SDL_VideoDevice* _this = SDL_GetVideoDevice(); +#ifdef SDL_VIDEO_OPENGL_EGL + if (windowData.egl_context) + { + SDL_EGL_DestroyContext(_this, windowData.egl_context); + } + if (windowData.egl_xcomponent) + { + SDL_EGL_DestroySurface(_this, windowData.egl_xcomponent); + } +#endif } static void onKeyEvent(OH_NativeXComponent *component, void *window) {} static void onNativeTouch(OH_NativeXComponent *component, void *window) {} diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index 5372751666..a823916d7a 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -3,6 +3,7 @@ #ifdef SDL_VIDEO_DRIVER_OHOS #include "SDL_ohosvulkan.h" +#include "SDL_ohoswindow.h" #include "../../core/ohos/SDL_ohos.h" bool OHOS_VideoInit(SDL_VideoDevice *_this) @@ -32,6 +33,8 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) device->Vulkan_CreateSurface = OHOS_Vulkan_CreateSurface; device->Vulkan_DestroySurface = OHOS_Vulkan_DestroySurface; #endif + device->CreateSDLWindow = OHOS_CreateWindow; + device->DestroyWindow = OHOS_DestroyWindow; return device; } diff --git a/src/video/ohos/SDL_ohoswindow.c b/src/video/ohos/SDL_ohoswindow.c index 10d54fba2f..33a44dc309 100644 --- a/src/video/ohos/SDL_ohoswindow.c +++ b/src/video/ohos/SDL_ohoswindow.c @@ -1,4 +1,44 @@ -#ifdef SDL_VIDEO_DRIVER_OHOS +#include "SDL_ohoswindow.h" +#include +#ifdef SDL_VIDEO_DRIVER_OHOS +#include "../../core/ohos/SDL_ohos.h" +#include "SDL_ohosvideo.h" +bool OHOS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) +{ + window->internal = &windowData; +#ifdef SDL_VIDEO_OPENGL_EGL + if (window->flags & SDL_WINDOW_OPENGL) { + SDL_LockMutex(g_ohosPageMutex); + if (window->internal->egl_xcomponent == EGL_NO_SURFACE) + { + window->internal->egl_xcomponent = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)window->internal->native_window); + } + SDL_UnlockMutex(g_ohosPageMutex); + } +#endif + window->x = (int)window->internal->x; + window->y = (int)window->internal->y; + + return true; +} + +void OHOS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ + #ifdef SDL_VIDEO_OPENGL_EGL + if (window->flags & SDL_WINDOW_OPENGL) { + SDL_LockMutex(g_ohosPageMutex); + if (window->internal->egl_context) + { + SDL_EGL_DestroyContext(_this, window->internal->egl_context); + } + if (window->internal->egl_xcomponent != EGL_NO_SURFACE) + { + SDL_EGL_DestroySurface(_this, window->internal->egl_xcomponent); + } + SDL_UnlockMutex(g_ohosPageMutex); + } +#endif +} #endif diff --git a/src/video/ohos/SDL_ohoswindow.h b/src/video/ohos/SDL_ohoswindow.h new file mode 100644 index 0000000000..b611951a79 --- /dev/null +++ b/src/video/ohos/SDL_ohoswindow.h @@ -0,0 +1,8 @@ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_OHOS +#include "../SDL_sysvideo.h" +bool OHOS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); +void OHOS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); + +#endif From 9e61fcb7f1b99ce6e772fd378ccd7a4eb20c2152 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 17:24:09 +0800 Subject: [PATCH 15/92] Harmony port: egl/gles lib --- src/video/ohos/SDL_ohosgl.c | 49 ++++++++++++++++++++++++++++++++++ src/video/ohos/SDL_ohosgl.h | 9 +++++++ src/video/ohos/SDL_ohosvideo.c | 18 +++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 src/video/ohos/SDL_ohosgl.c create mode 100644 src/video/ohos/SDL_ohosgl.h diff --git a/src/video/ohos/SDL_ohosgl.c b/src/video/ohos/SDL_ohosgl.c new file mode 100644 index 0000000000..bc4398e5a2 --- /dev/null +++ b/src/video/ohos/SDL_ohosgl.c @@ -0,0 +1,49 @@ +#include "SDL_internal.h" +#ifdef SDL_VIDEO_DRIVER_OHOS +#include "SDL_ohosvideo.h" +#include "../../core/ohos/SDL_ohos.h" + +bool OHOS_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) +{ + if (window && context) + { + return SDL_EGL_MakeCurrent(_this, window->internal->egl_xcomponent, context); + } + else + { + return SDL_EGL_MakeCurrent(_this, NULL, NULL); + } +} + +SDL_GLContext OHOS_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window) +{ + SDL_GLContext result; + + SDL_LockMutex(g_ohosPageMutex); + + result = SDL_EGL_CreateContext(_this, window->internal->egl_xcomponent); + + SDL_UnlockMutex(g_ohosPageMutex); + + return result; +} + +bool OHOS_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ + bool result; + + SDL_LockMutex(g_ohosPageMutex); + + result = SDL_EGL_SwapBuffers(_this, window->internal->egl_xcomponent); + + SDL_UnlockMutex(g_ohosPageMutex); + + return result; +} + +bool OHOS_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path) +{ + return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)0, 0); +} + +#endif diff --git a/src/video/ohos/SDL_ohosgl.h b/src/video/ohos/SDL_ohosgl.h new file mode 100644 index 0000000000..b168dbeb3d --- /dev/null +++ b/src/video/ohos/SDL_ohosgl.h @@ -0,0 +1,9 @@ +#ifdef SDL_VIDEO_DRIVER_OHOS +#include "SDL_ohosvideo.h" + +bool OHOS_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context); +SDL_GLContext OHOS_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); +bool OHOS_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window); +bool OHOS_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path); + +#endif diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index a823916d7a..222247c9f8 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -3,6 +3,7 @@ #ifdef SDL_VIDEO_DRIVER_OHOS #include "SDL_ohosvulkan.h" +#include "SDL_ohosgl.h" #include "SDL_ohoswindow.h" #include "../../core/ohos/SDL_ohos.h" @@ -13,6 +14,10 @@ bool OHOS_VideoInit(SDL_VideoDevice *_this) void OHOS_VideoQuit(SDL_VideoDevice *_this) { } +void OHOS_DeviceFree(SDL_VideoDevice *device) +{ + SDL_free(device); +} static SDL_VideoDevice *OHOS_CreateDevice(void) { SDL_VideoDevice *device; @@ -23,6 +28,7 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) } device->internal = &videoData; + device->free = OHOS_DeviceFree; device->VideoInit = OHOS_VideoInit; device->VideoQuit = OHOS_VideoQuit; @@ -36,6 +42,18 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) device->CreateSDLWindow = OHOS_CreateWindow; device->DestroyWindow = OHOS_DestroyWindow; +#ifdef SDL_VIDEO_OPENGL_EGL + device->GL_LoadLibrary = OHOS_GLES_LoadLibrary; + device->GL_MakeCurrent = OHOS_GLES_MakeCurrent; + device->GL_CreateContext = OHOS_GLES_CreateContext; + device->GL_SwapWindow = OHOS_GLES_SwapWindow; + device->GL_GetProcAddress = SDL_EGL_GetProcAddressInternal; + device->GL_UnloadLibrary = SDL_EGL_UnloadLibrary; + device->GL_SetSwapInterval = SDL_EGL_SetSwapInterval; + device->GL_GetSwapInterval = SDL_EGL_GetSwapInterval; + device->GL_DestroyContext = SDL_EGL_DestroyContext; +#endif + return device; } VideoBootStrap OHOS_bootstrap = { From dc28e96952d27a1a58e0ecf8d76eabcbfa9bd692 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 20:05:48 +0800 Subject: [PATCH 16/92] Harmony port: keyboard event --- src/core/ohos/SDL_ohos.c | 28 +- src/video/ohos/SDL_ohoskeyboard.c | 3153 +++++++++++++++++++++++++++++ src/video/ohos/SDL_ohoskeyboard.h | 4 + 3 files changed, 3184 insertions(+), 1 deletion(-) create mode 100644 src/video/ohos/SDL_ohoskeyboard.c create mode 100644 src/video/ohos/SDL_ohoskeyboard.h diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index c1877645fc..abbae88807 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -9,6 +9,7 @@ #include #include "../../video/ohos/SDL_ohosvideo.h" #include "SDL3/SDL_mutex.h" +#include "../../video/ohos/SDL_ohoskeyboard.h" OHNativeWindow *nativeWindow; SDL_Mutex *g_ohosPageMutex = NULL; @@ -99,7 +100,32 @@ static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) } #endif } -static void onKeyEvent(OH_NativeXComponent *component, void *window) {} +static void onKeyEvent(OH_NativeXComponent *component, void *window) +{ + OH_NativeXComponent_KeyEvent *keyEvent = NULL; + if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) + { + OH_NativeXComponent_KeyAction action; + OH_NativeXComponent_KeyCode code; + OH_NativeXComponent_EventSourceType sourceType; + + OH_NativeXComponent_GetKeyEventAction(keyEvent, &action); + OH_NativeXComponent_GetKeyEventCode(keyEvent, &code); + OH_NativeXComponent_GetKeyEventSourceType(keyEvent, &sourceType); + + if (sourceType == OH_NATIVEXCOMPONENT_SOURCE_TYPE_KEYBOARD) + { + if (OH_NATIVEXCOMPONENT_KEY_ACTION_DOWN == action) + { + OHOS_OnKeyDown(code); + } + else if (OH_NATIVEXCOMPONENT_KEY_ACTION_UP == action) + { + OHOS_OnKeyUp(code); + } + } + } +} static void onNativeTouch(OH_NativeXComponent *component, void *window) {} static void onNativeMouse(OH_NativeXComponent *component, void *window) {} static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) {} diff --git a/src/video/ohos/SDL_ohoskeyboard.c b/src/video/ohos/SDL_ohoskeyboard.c new file mode 100644 index 0000000000..8dcfc6862b --- /dev/null +++ b/src/video/ohos/SDL_ohoskeyboard.c @@ -0,0 +1,3153 @@ +#include "SDL3/SDL_log.h" +#include "SDL3/SDL_oldnames.h" +#include "SDL3/SDL_scancode.h" +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_OHOS + +#include "../../events/SDL_events_c.h" + +static SDL_Scancode OHOS_Keycodes[] = { + SDL_SCANCODE_UNKNOWN, // KEY_FN + SDL_SCANCODE_AC_HOME, + SDL_SCANCODE_AC_BACK, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_MEDIA_PAUSE, + SDL_SCANCODE_MEDIA_STOP, + SDL_SCANCODE_MEDIA_NEXT_TRACK, + SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, + SDL_SCANCODE_MEDIA_REWIND, + SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_FAST_FORWARD + SDL_SCANCODE_VOLUMEUP, + SDL_SCANCODE_VOLUMEDOWN, + SDL_SCANCODE_POWER, + SDL_SCANCODE_UNKNOWN, // KEY_CAMERA + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_MUTE, + SDL_SCANCODE_MUTE, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_UP + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_DOWN + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_0, + SDL_SCANCODE_1, + SDL_SCANCODE_2, + SDL_SCANCODE_3, + SDL_SCANCODE_4, + SDL_SCANCODE_5, + SDL_SCANCODE_6, + SDL_SCANCODE_7, + SDL_SCANCODE_8, + SDL_SCANCODE_9, + SDL_SCANCODE_UNKNOWN, // KEY_STAR + SDL_SCANCODE_UNKNOWN, // KEY_POUND + SDL_SCANCODE_UP, + SDL_SCANCODE_DOWN, // KEY_DPAD_DOWN + SDL_SCANCODE_LEFT, // KEY_DPAD_LEFT + SDL_SCANCODE_RIGHT, // KEY_DPAD_RIGHT + SDL_SCANCODE_SELECT, // KEY_DPAD_CENTER + SDL_SCANCODE_A, + SDL_SCANCODE_B, + SDL_SCANCODE_C, + SDL_SCANCODE_D, + SDL_SCANCODE_E, + SDL_SCANCODE_F, + SDL_SCANCODE_G, + SDL_SCANCODE_H, + SDL_SCANCODE_I, + SDL_SCANCODE_J, + SDL_SCANCODE_K, + SDL_SCANCODE_L, + SDL_SCANCODE_M, + SDL_SCANCODE_N, + SDL_SCANCODE_O, + SDL_SCANCODE_P, + SDL_SCANCODE_Q, + SDL_SCANCODE_R, + SDL_SCANCODE_S, + SDL_SCANCODE_T, + SDL_SCANCODE_U, + SDL_SCANCODE_V, + SDL_SCANCODE_W, + SDL_SCANCODE_X, + SDL_SCANCODE_Y, + SDL_SCANCODE_Z, + SDL_SCANCODE_COMMA, + SDL_SCANCODE_PERIOD, + SDL_SCANCODE_LALT, + SDL_SCANCODE_RALT, + SDL_SCANCODE_LSHIFT, + SDL_SCANCODE_RSHIFT, + SDL_SCANCODE_TAB, + SDL_SCANCODE_SPACE, + SDL_SCANCODE_UNKNOWN, // KEY_SYM + SDL_SCANCODE_UNKNOWN, // KEY_EXPLORER + SDL_SCANCODE_UNKNOWN, // KEY_ENVELOPE + SDL_SCANCODE_RETURN, + SDL_SCANCODE_BACKSPACE, + SDL_SCANCODE_GRAVE, + SDL_SCANCODE_MINUS, + SDL_SCANCODE_EQUALS, + SDL_SCANCODE_LEFTBRACKET, + SDL_SCANCODE_RIGHTBRACKET, + SDL_SCANCODE_BACKSLASH, + SDL_SCANCODE_SEMICOLON, + SDL_SCANCODE_APOSTROPHE, + SDL_SCANCODE_SLASH, + SDL_SCANCODE_UNKNOWN, // KEY_AT + SDL_SCANCODE_UNKNOWN, // KEY_PLUS + SDL_SCANCODE_MENU, + SDL_SCANCODE_PAGEUP, + SDL_SCANCODE_PAGEDOWN, + SDL_SCANCODE_ESCAPE, + SDL_SCANCODE_DELETE, + SDL_SCANCODE_LCTRL, + SDL_SCANCODE_RCTRL, + SDL_SCANCODE_CAPSLOCK, + SDL_SCANCODE_SCROLLLOCK, + SDL_SCANCODE_LGUI, // KEY_META_LEFT + SDL_SCANCODE_RGUI, // KEY_META_RIGHT + SDL_SCANCODE_UNKNOWN, // KEY_FUNCTION + SDL_SCANCODE_SYSREQ, + SDL_SCANCODE_PAUSE, // KEY_BREAK + SDL_SCANCODE_HOME, + SDL_SCANCODE_END, + SDL_SCANCODE_INSERT, + SDL_SCANCODE_AC_FORWARD, + SDL_SCANCODE_MEDIA_PLAY, + SDL_SCANCODE_MEDIA_PAUSE, + SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_CLOSE + SDL_SCANCODE_MEDIA_EJECT, + SDL_SCANCODE_MEDIA_RECORD, + SDL_SCANCODE_F1, + SDL_SCANCODE_F2, + SDL_SCANCODE_F3, + SDL_SCANCODE_F4, + SDL_SCANCODE_F5, + SDL_SCANCODE_F6, + SDL_SCANCODE_F7, + SDL_SCANCODE_F8, + SDL_SCANCODE_F9, + SDL_SCANCODE_F10, + SDL_SCANCODE_F11, + SDL_SCANCODE_F12, + SDL_SCANCODE_NUMLOCKCLEAR, + SDL_SCANCODE_KP_0, + SDL_SCANCODE_KP_1, + SDL_SCANCODE_KP_2, + SDL_SCANCODE_KP_3, + SDL_SCANCODE_KP_4, + SDL_SCANCODE_KP_5, + SDL_SCANCODE_KP_6, + SDL_SCANCODE_KP_7, + SDL_SCANCODE_KP_8, + SDL_SCANCODE_KP_9, + SDL_SCANCODE_KP_DIVIDE, + SDL_SCANCODE_KP_MULTIPLY, + SDL_SCANCODE_KP_MINUS, + SDL_SCANCODE_KP_PLUS, + SDL_SCANCODE_KP_PERIOD, + SDL_SCANCODE_KP_COMMA, + SDL_SCANCODE_KP_ENTER, + SDL_SCANCODE_KP_EQUALS, + SDL_SCANCODE_KP_LEFTPAREN, + SDL_SCANCODE_KP_RIGHTPAREN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_VIRTUAL_MULTITASK + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_SLEEP, + SDL_SCANCODE_LANG5, + SDL_SCANCODE_UNKNOWN, // KEY_102ND + SDL_SCANCODE_UNKNOWN, // KEY_RO + SDL_SCANCODE_UNKNOWN, // KEY_KATAKANA + SDL_SCANCODE_UNKNOWN, // KEY_HIRAGANA + SDL_SCANCODE_INTERNATIONAL4, + SDL_SCANCODE_LANG3, + SDL_SCANCODE_INTERNATIONAL5, + SDL_SCANCODE_UNKNOWN, // KEY_LINEFEED + SDL_SCANCODE_UNKNOWN, // KEY_MACRO + SDL_SCANCODE_UNKNOWN, // KEY_PLUSMINUS + SDL_SCANCODE_UNKNOWN, // KEY_SCALE + SDL_SCANCODE_UNKNOWN, // KEY_HANGUEL + SDL_SCANCODE_UNKNOWN, // KEY_HANJA + SDL_SCANCODE_INTERNATIONAL3, + SDL_SCANCODE_UNKNOWN, // KEY_STOP + SDL_SCANCODE_UNKNOWN, // KEY_AGAIN + SDL_SCANCODE_UNKNOWN, // KEY_PROPS + SDL_SCANCODE_UNDO, + SDL_SCANCODE_COPY, + SDL_SCANCODE_UNKNOWN, // KEY_OPEN + SDL_SCANCODE_PASTE, + SDL_SCANCODE_FIND, + SDL_SCANCODE_CUT, + SDL_SCANCODE_HELP, + SDL_SCANCODE_UNKNOWN, // KEY_CALC + SDL_SCANCODE_UNKNOWN, // KEY_FILE + SDL_SCANCODE_AC_BOOKMARKS, + SDL_SCANCODE_MEDIA_NEXT_TRACK, + SDL_SCANCODE_MEDIA_PLAY_PAUSE, + SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, + SDL_SCANCODE_MEDIA_STOP, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_CONFIG + SDL_SCANCODE_UNKNOWN, // KEY_REFRESH + SDL_SCANCODE_UNKNOWN, // KEY_EXIT + SDL_SCANCODE_UNKNOWN, // KEY_EDIT + SDL_SCANCODE_UP, + SDL_SCANCODE_DOWN, + SDL_SCANCODE_UNKNOWN, // KEY_NEW + SDL_SCANCODE_UNKNOWN, // KEY_REDO + SDL_SCANCODE_UNKNOWN, // KEY_CLOSE + SDL_SCANCODE_MEDIA_PLAY, + SDL_SCANCODE_UNKNOWN, // KEY_BASSBOOST + SDL_SCANCODE_PRINTSCREEN, + SDL_SCANCODE_UNKNOWN, // KEY_CHAT + SDL_SCANCODE_UNKNOWN, // KEY_FINANCE + SDL_SCANCODE_UNKNOWN, // KEY_CANCEL + SDL_SCANCODE_UNKNOWN, // KEY_KBDILLUM_TOGGLE + SDL_SCANCODE_DOWN, + SDL_SCANCODE_UP, + SDL_SCANCODE_UNKNOWN, // KEY_SEND + SDL_SCANCODE_UNKNOWN, // KEY_REPLY + SDL_SCANCODE_UNKNOWN, // KEY_FORWARDMAIL + SDL_SCANCODE_UNKNOWN, // KEY_SAVE + SDL_SCANCODE_UNKNOWN, // KEY_DOCUMENTS + SDL_SCANCODE_MEDIA_NEXT_TRACK, + SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_CYCLE + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_ZERO + SDL_SCANCODE_UNKNOWN, // KEY_DISPLAY_OFF + SDL_SCANCODE_UNKNOWN, // KEY_BTN_MISC + SDL_SCANCODE_UNKNOWN, // KEY_GOTO + SDL_SCANCODE_UNKNOWN, // KEY_INFO + SDL_SCANCODE_UNKNOWN, // KEY_PROGRAM + SDL_SCANCODE_UNKNOWN, // KEY_PVR + SDL_SCANCODE_UNKNOWN, // KEY_SUBTITLE + SDL_SCANCODE_UNKNOWN, // KEY_FULLSCREEN + SDL_SCANCODE_UNKNOWN, // KEY_KEYBOARD + SDL_SCANCODE_UNKNOWN, // KEY_ASPECT_RATIO + SDL_SCANCODE_UNKNOWN, // KEY_PC + SDL_SCANCODE_UNKNOWN, // KEY_TV + SDL_SCANCODE_UNKNOWN, // KEY_TV2 + SDL_SCANCODE_UNKNOWN, // KEY_VCR + SDL_SCANCODE_UNKNOWN, // KEY_VCR2 + SDL_SCANCODE_UNKNOWN, // KEY_SAT + SDL_SCANCODE_UNKNOWN, // KEY_CD + SDL_SCANCODE_UNKNOWN, // KEY_TAPE + SDL_SCANCODE_UNKNOWN, // KEY_TUNER + SDL_SCANCODE_UNKNOWN, // KEY_PLAYER + SDL_SCANCODE_UNKNOWN, // KEY_DVD + SDL_SCANCODE_UNKNOWN, // KEY_AUDIO + SDL_SCANCODE_UNKNOWN, // KEY_VIDEO + SDL_SCANCODE_UNKNOWN, // KEY_MEMO + SDL_SCANCODE_UNKNOWN, // KEY_CALENDER + SDL_SCANCODE_UNKNOWN, // KEY_RED + SDL_SCANCODE_UNKNOWN, // KEY_GREEN + SDL_SCANCODE_UNKNOWN, // KEY_YELLOW + SDL_SCANCODE_UNKNOWN, // KEY_BLUE + SDL_SCANCODE_CHANNEL_INCREMENT, + SDL_SCANCODE_CHANNEL_DECREMENT, + SDL_SCANCODE_UNKNOWN, // KEY_LAST + SDL_SCANCODE_UNKNOWN, // KEY_RESTART + SDL_SCANCODE_UNKNOWN, // KEY_SLOW + SDL_SCANCODE_UNKNOWN, // KEY_SHUFFLE + SDL_SCANCODE_UNKNOWN, // KEY_VIDEOPHONE + SDL_SCANCODE_UNKNOWN, // KEY_GAMES + SDL_SCANCODE_UNKNOWN, // KEY_ZOOMIN + SDL_SCANCODE_UNKNOWN, // KEY_ZOOMOUT + SDL_SCANCODE_UNKNOWN, // KEY_ZOOMRESET + SDL_SCANCODE_UNKNOWN, // KEY_WORDPROCESSOR + SDL_SCANCODE_UNKNOWN, // KEY_EDITOR + SDL_SCANCODE_UNKNOWN, // KEY_SPREADSHEET + SDL_SCANCODE_UNKNOWN, // KEY_GRAPHICSEDITOR + SDL_SCANCODE_UNKNOWN, // KEY_PRESENTATION + SDL_SCANCODE_UNKNOWN, // KEY_DATABASE + SDL_SCANCODE_UNKNOWN, // KEY_NEWS + SDL_SCANCODE_UNKNOWN, // KEY_VOICEMAIL + SDL_SCANCODE_UNKNOWN, // KEY_ADDRESSBOOK + SDL_SCANCODE_UNKNOWN, // KEY_MESSENGER + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_TOGGLE + SDL_SCANCODE_UNKNOWN, // KEY_SPELLCHECK + SDL_SCANCODE_UNKNOWN, // KEY_COFFEE + SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_REPEAT + SDL_SCANCODE_UNKNOWN, // KEY_IMAGES + SDL_SCANCODE_UNKNOWN, // KEY_BUTTONCONFIG + SDL_SCANCODE_UNKNOWN, // KEY_TASKMANAGER + SDL_SCANCODE_UNKNOWN, // KEY_JOURNAL + SDL_SCANCODE_UNKNOWN, // KEY_CONTROLPANEL + SDL_SCANCODE_UNKNOWN, // KEY_APPSELECT + SDL_SCANCODE_UNKNOWN, // KEY_SCREENSAVER + SDL_SCANCODE_UNKNOWN, // KEY_ASSISTANT + SDL_SCANCODE_UNKNOWN, // KEY_KBD_LAYOUT_NEXT + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_MIN + SDL_SCANCODE_UNKNOWN, // KEY_BRIGHTNESS_MAX + SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSISTANT_PREV + SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSISTANT_NEXT + SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSISTANT_PREVGROUP + SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSISTANT_NEXTGROUP + SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSISTANT_ACCEPT + SDL_SCANCODE_UNKNOWN, // KEY_KBDINPUTASSISTANT_CANCEL + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_FRONT + SDL_SCANCODE_UNKNOWN, // KEY_SETUP + SDL_SCANCODE_UNKNOWN, // KEY_WAKEUP + SDL_SCANCODE_UNKNOWN, // KEY_SENDFILE + SDL_SCANCODE_UNKNOWN, // KEY_XFER + SDL_SCANCODE_UNKNOWN, // KEY_PROG1 + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_PROG2 + SDL_SCANCODE_UNKNOWN, // KEY_MSDOS + SDL_SCANCODE_UNKNOWN, // KEY_SCREENLOCK + SDL_SCANCODE_UNKNOWN, // KEY_DIRECTION_ROTATE_DISPLAY + SDL_SCANCODE_UNKNOWN, // KEY_CYCLEWINDOWS + SDL_SCANCODE_UNKNOWN, // KEY_COMPUTER + SDL_SCANCODE_UNKNOWN, // KEY_EJECTCLOSECD + SDL_SCANCODE_UNKNOWN, // KEY_ISO + SDL_SCANCODE_UNKNOWN, // KEY_MOVE + SDL_SCANCODE_F13, + SDL_SCANCODE_F14, + SDL_SCANCODE_F15, + SDL_SCANCODE_F16, + SDL_SCANCODE_F17, + SDL_SCANCODE_F18, + SDL_SCANCODE_F19, + SDL_SCANCODE_F20, + SDL_SCANCODE_F21, + SDL_SCANCODE_F22, + SDL_SCANCODE_F23, + SDL_SCANCODE_F24, + SDL_SCANCODE_UNKNOWN, // KEY_PROG3 + SDL_SCANCODE_UNKNOWN, // KEY_PROG4 + SDL_SCANCODE_UNKNOWN, // KEY_DASHBOARD + SDL_SCANCODE_UNKNOWN, // KEY_SUSPEND + SDL_SCANCODE_UNKNOWN, // KEY_HP + SDL_SCANCODE_UNKNOWN, // KEY_SOUND + SDL_SCANCODE_UNKNOWN, // KEY_QUESTION + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_CONNECT + SDL_SCANCODE_UNKNOWN, // KEY_SPORT + SDL_SCANCODE_UNKNOWN, // KEY_SHOP + SDL_SCANCODE_UNKNOWN, // KEY_ALTERASE + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_SWITCHVIDEOMODE + SDL_SCANCODE_UNKNOWN, // KEY_BATTERY + SDL_SCANCODE_UNKNOWN, // KEY_BLUETOOTH + SDL_SCANCODE_UNKNOWN, // KEY_WLAN + SDL_SCANCODE_UNKNOWN, // KEY_UWB + SDL_SCANCODE_UNKNOWN, // KEY_WWAN_WIMAX + SDL_SCANCODE_UNKNOWN, // KEY_RFKILL + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_CHANNEL + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, // KEY_BTN_0 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_1 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_2 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_3 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_4 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_5 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_6 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_7 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_8 + SDL_SCANCODE_UNKNOWN, // KEY_BTN_9 +}; + +// static bool SDL_screen_keyboard_shown; + +static SDL_Scancode TranslateKeycode(int keycode) +{ + SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; + if (keycode <= -1) + { + return SDL_SCANCODE_UNKNOWN; + } + if (keycode < SDL_arraysize(OHOS_Keycodes)) + { + scancode = OHOS_Keycodes[keycode]; + } + if (scancode == SDL_SCANCODE_UNKNOWN) + { + SDL_Log("Unknown keycode %d", keycode); + } + return scancode; +} + +void OHOS_OnKeyDown(int keycode) +{ + SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, keycode, TranslateKeycode(keycode), true); +} + +void OHOS_OnKeyUp(int keycode) +{ + SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, keycode, TranslateKeycode(keycode), false); +} + +#endif diff --git a/src/video/ohos/SDL_ohoskeyboard.h b/src/video/ohos/SDL_ohoskeyboard.h new file mode 100644 index 0000000000..5dd55f39c4 --- /dev/null +++ b/src/video/ohos/SDL_ohoskeyboard.h @@ -0,0 +1,4 @@ +#ifdef SDL_VIDEO_DRIVER_OHOS +void OHOS_OnKeyDown(int keycode); +void OHOS_OnKeyUp(int keycode); +#endif From 2570e9ac5669a70b5c75aa3ef9ff5414957bafbf Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 20:31:23 +0800 Subject: [PATCH 17/92] Harmony port: video drv fix --- src/video/SDL_video.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index a1b1bba1c5..06ce3c8af9 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -148,6 +148,9 @@ static VideoBootStrap *bootstrap[] = { #endif #ifdef SDL_VIDEO_DRIVER_OPENVR &OPENVR_bootstrap, +#endif +#ifdef SDL_VIDEO_DRIVER_OHOS + &OHOS_bootstrap, #endif NULL }; From af9601874eb8db6ebcae13403db5f42e7a28fe7b Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 31 May 2025 21:00:09 +0800 Subject: [PATCH 18/92] Harmony port: napi callback shell --- src/core/ohos/SDL_ohos.c | 61 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index abbae88807..d3cab42914 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,6 +1,10 @@ #include "SDL_internal.h" #include #include +#include +#include +#include +#include #ifdef SDL_PLATFORM_OHOS @@ -17,6 +21,36 @@ static OH_NativeXComponent_Callback callback; static OH_NativeXComponent_MouseEvent_Callback mouseCallback; SDL_WindowData windowData; SDL_VideoData videoData; +struct +{ + napi_env env; + napi_threadsafe_function func; + napi_ref interface; +} napiEnv; + +typedef union +{ + int i; + short s; + char c; + long long l; + float f; + double d; + const char* str; + bool b; +} napiCallbackArg; +typedef struct +{ + const char* func; + napiCallbackArg arg1; + napiCallbackArg arg2; + napiCallbackArg arg3; + napiCallbackArg arg4; + napiCallbackArg arg5; + napiCallbackArg arg6; + napiCallbackArg arg7; + napiCallbackArg arg8; +} napiCallbackData; static napi_value minus(napi_env env, napi_callback_info info) { @@ -43,6 +77,30 @@ static napi_value minus(napi_env env, napi_callback_info info) return sum; } +static void sdlJSCallback(napi_env env, napi_value jsCb, void* content, void* data) +{ + +} + +static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) +{ + napiEnv.env = env; + size_t argc = 1; + napi_value args[1] = { NULL }; + + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + napi_create_reference(env, args[0], 1, &napiEnv.interface); + + napi_value resName = NULL; + napi_create_string_utf8(env, "SDLThreadSafe", NAPI_AUTO_LENGTH, &resName); + napi_create_threadsafe_function(env, args[0], NULL, resName, 0, 1, NULL, NULL, NULL, sdlJSCallback, &napiEnv.func); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { nativeWindow = (OHNativeWindow *)window; @@ -136,7 +194,8 @@ void OnBlurEvent(OH_NativeXComponent *component, void *window) {} static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { - { "minus", NULL, minus, NULL, NULL, NULL, napi_default, NULL } + { "minus", NULL, minus, NULL, NULL, NULL, napi_default, NULL }, + { "sdlCallbackInit", NULL, sdlCallbackInit, NULL, NULL, NULL, napi_default, NULL } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); From 4a0d0685eeefaa88e0a6077a0ec1c216d2b24a87 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 06:48:06 +0800 Subject: [PATCH 19/92] Harmony port: review changes --- src/core/ohos/SDL_ohos.c | 25 +++++++++++-------------- src/core/ohos/SDL_ohos.h | 3 +-- src/video/ohos/SDL_ohosvideo.c | 8 +++++++- src/video/ohos/SDL_ohosvulkan.c | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index d3cab42914..e7fc71d358 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -15,13 +15,12 @@ #include "SDL3/SDL_mutex.h" #include "../../video/ohos/SDL_ohoskeyboard.h" -OHNativeWindow *nativeWindow; +OHNativeWindow *g_ohosNativeWindow; SDL_Mutex *g_ohosPageMutex = NULL; static OH_NativeXComponent_Callback callback; static OH_NativeXComponent_MouseEvent_Callback mouseCallback; SDL_WindowData windowData; -SDL_VideoData videoData; -struct +static struct { napi_env env; napi_threadsafe_function func; @@ -103,7 +102,7 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { - nativeWindow = (OHNativeWindow *)window; + g_ohosNativeWindow = (OHNativeWindow *)window; uint64_t width; uint64_t height; @@ -112,10 +111,8 @@ static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); - SDL_Log("Native Window: %p", nativeWindow); - SDL_LockMutex(g_ohosPageMutex); - windowData.native_window = nativeWindow; + windowData.native_window = g_ohosNativeWindow; windowData.width = width; windowData.height = height; windowData.x = offsetX; @@ -124,7 +121,7 @@ static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) } static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) { - nativeWindow = (OHNativeWindow *)window; + g_ohosNativeWindow = (OHNativeWindow *)window; uint64_t width; uint64_t height; @@ -133,10 +130,8 @@ static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); - SDL_Log("Native Window: %p", nativeWindow); - SDL_LockMutex(g_ohosPageMutex); - windowData.native_window = nativeWindow; + windowData.native_window = g_ohosNativeWindow; windowData.width = width; windowData.height = height; windowData.x = offsetX; @@ -184,12 +179,14 @@ static void onKeyEvent(OH_NativeXComponent *component, void *window) } } } + +// TODO static void onNativeTouch(OH_NativeXComponent *component, void *window) {} static void onNativeMouse(OH_NativeXComponent *component, void *window) {} static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) {} -void OnHoverEvent(OH_NativeXComponent *component, bool isHover) {} -void OnFocusEvent(OH_NativeXComponent *component, void *window) {} -void OnBlurEvent(OH_NativeXComponent *component, void *window) {} +static void OnHoverEvent(OH_NativeXComponent *component, bool isHover) {} +static void OnFocusEvent(OH_NativeXComponent *component, void *window) {} +static void OnBlurEvent(OH_NativeXComponent *component, void *window) {} static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 0df3a0bee0..5c7e633697 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -6,9 +6,8 @@ #include extern SDL_Mutex *g_ohosPageMutex; -extern OHNativeWindow *nativeWindow; +extern OHNativeWindow *g_ohosNativeWindow; extern SDL_WindowData windowData; -extern SDL_VideoData videoData; typedef struct SDL_VideoData { SDL_Rect textRect; diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index 222247c9f8..766d58d411 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -21,13 +21,19 @@ void OHOS_DeviceFree(SDL_VideoDevice *device) static SDL_VideoDevice *OHOS_CreateDevice(void) { SDL_VideoDevice *device; + SDL_VideoData *data; device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); if (!device) { return NULL; } - device->internal = &videoData; + data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); + if (!data) { + return NULL; + } + + device->internal = data; device->free = OHOS_DeviceFree; device->VideoInit = OHOS_VideoInit; diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c index 6742189dbb..9721181d9a 100644 --- a/src/video/ohos/SDL_ohosvulkan.c +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -111,7 +111,7 @@ bool OHOS_Vulkan_CreateSurface(SDL_VideoDevice *_this, createInfo.sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.window = nativeWindow; + createInfo.window = g_ohosNativeWindow; result = vkCreateSurfaceOHOS(instance, &createInfo, NULL, surface); if (result != VK_SUCCESS) { SDL_SetError("vkCreateSurfaceOHOS failed: %d", result); From 590509b34dad1fa63f975d765397367aee9950b6 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 07:22:00 +0800 Subject: [PATCH 20/92] Harmony port: review changes --- src/core/ohos/SDL_ohos.c | 57 +++++++++++++++++++-------------- src/core/ohos/SDL_ohos.h | 5 +-- src/video/ohos/SDL_ohosgl.c | 6 ++-- src/video/ohos/SDL_ohosvideo.h | 4 +-- src/video/ohos/SDL_ohosvulkan.c | 3 +- src/video/ohos/SDL_ohoswindow.c | 40 +++++++++-------------- 6 files changed, 57 insertions(+), 58 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index e7fc71d358..32481d0f21 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -15,11 +15,11 @@ #include "SDL3/SDL_mutex.h" #include "../../video/ohos/SDL_ohoskeyboard.h" -OHNativeWindow *g_ohosNativeWindow; +static OHNativeWindow *g_ohosNativeWindow; SDL_Mutex *g_ohosPageMutex = NULL; static OH_NativeXComponent_Callback callback; static OH_NativeXComponent_MouseEvent_Callback mouseCallback; -SDL_WindowData windowData; +static int x, y, wid, hei; static struct { napi_env env; @@ -51,6 +51,29 @@ typedef struct napiCallbackArg arg8; } napiCallbackData; +void OHOS_windowDataFill(SDL_Window* w) +{ + w->internal = SDL_calloc(1, sizeof(SDL_WindowData)); + w->x = x; + w->y = y; + w->w = wid; + w->h = hei; + w->internal->native_window = g_ohosNativeWindow; + + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + +#ifdef SDL_VIDEO_OPENGL_EGL + if (w->flags & SDL_WINDOW_OPENGL) { + SDL_LockMutex(g_ohosPageMutex); + if (w->internal->egl_surface == EGL_NO_SURFACE) + { + w->internal->egl_surface = SDL_EGL_CreateSurface(_this, w, (NativeWindowType)g_ohosNativeWindow); + } + SDL_UnlockMutex(g_ohosPageMutex); + } +#endif +} + static napi_value minus(napi_env env, napi_callback_info info) { size_t argc = 2; @@ -112,11 +135,10 @@ static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); SDL_LockMutex(g_ohosPageMutex); - windowData.native_window = g_ohosNativeWindow; - windowData.width = width; - windowData.height = height; - windowData.x = offsetX; - windowData.y = offsetY; + wid = width; + hei = height; + x = (int)offsetX; + y = (int)offsetY; SDL_UnlockMutex(g_ohosPageMutex); } static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) @@ -131,27 +153,14 @@ static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetXComponentOffset(component, window, &offsetX, &offsetY); SDL_LockMutex(g_ohosPageMutex); - windowData.native_window = g_ohosNativeWindow; - windowData.width = width; - windowData.height = height; - windowData.x = offsetX; - windowData.y = offsetY; - + wid = width; + hei = height; + x = (int)offsetX; + y = (int)offsetY; SDL_UnlockMutex(g_ohosPageMutex); } static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { - SDL_VideoDevice* _this = SDL_GetVideoDevice(); -#ifdef SDL_VIDEO_OPENGL_EGL - if (windowData.egl_context) - { - SDL_EGL_DestroyContext(_this, windowData.egl_context); - } - if (windowData.egl_xcomponent) - { - SDL_EGL_DestroySurface(_this, windowData.egl_xcomponent); - } -#endif } static void onKeyEvent(OH_NativeXComponent *component, void *window) { diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 5c7e633697..967f248491 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -2,12 +2,13 @@ #define SDL_OHOS_H #include "SDL3/SDL_mutex.h" +#include "SDL3/SDL_video.h" #include "video/SDL_sysvideo.h" #include extern SDL_Mutex *g_ohosPageMutex; -extern OHNativeWindow *g_ohosNativeWindow; -extern SDL_WindowData windowData; + +void OHOS_windowDataFill(SDL_Window* w); typedef struct SDL_VideoData { SDL_Rect textRect; diff --git a/src/video/ohos/SDL_ohosgl.c b/src/video/ohos/SDL_ohosgl.c index bc4398e5a2..7f8bd92158 100644 --- a/src/video/ohos/SDL_ohosgl.c +++ b/src/video/ohos/SDL_ohosgl.c @@ -7,7 +7,7 @@ bool OHOS_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLCon { if (window && context) { - return SDL_EGL_MakeCurrent(_this, window->internal->egl_xcomponent, context); + return SDL_EGL_MakeCurrent(_this, window->internal->egl_surface, context); } else { @@ -21,7 +21,7 @@ SDL_GLContext OHOS_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window SDL_LockMutex(g_ohosPageMutex); - result = SDL_EGL_CreateContext(_this, window->internal->egl_xcomponent); + result = SDL_EGL_CreateContext(_this, window->internal->egl_surface); SDL_UnlockMutex(g_ohosPageMutex); @@ -34,7 +34,7 @@ bool OHOS_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) SDL_LockMutex(g_ohosPageMutex); - result = SDL_EGL_SwapBuffers(_this, window->internal->egl_xcomponent); + result = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface); SDL_UnlockMutex(g_ohosPageMutex); diff --git a/src/video/ohos/SDL_ohosvideo.h b/src/video/ohos/SDL_ohosvideo.h index a402429b6e..a27ee2e226 100644 --- a/src/video/ohos/SDL_ohosvideo.h +++ b/src/video/ohos/SDL_ohosvideo.h @@ -5,15 +5,13 @@ #include "../../core/ohos/SDL_ohos.h" struct SDL_WindowData { #ifdef SDL_VIDEO_OPENGL_EGL - EGLSurface egl_xcomponent; + EGLSurface egl_surface; EGLContext egl_context; #endif bool backup_done; OHNativeWindow *native_window; uint64_t width; uint64_t height; - double x; - double y; }; #endif diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c index 9721181d9a..ca2407497d 100644 --- a/src/video/ohos/SDL_ohosvulkan.c +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -8,6 +8,7 @@ #include "../SDL_sysvideo.h" #include "../../core/ohos/SDL_ohos.h" #include "vulkan/vulkan_ohos.h" +#include "SDL_ohosvideo.h" #include static int loadedCount = 0; @@ -111,7 +112,7 @@ bool OHOS_Vulkan_CreateSurface(SDL_VideoDevice *_this, createInfo.sType = VK_STRUCTURE_TYPE_SURFACE_CREATE_INFO_OHOS; createInfo.pNext = NULL; createInfo.flags = 0; - createInfo.window = g_ohosNativeWindow; + createInfo.window = window->internal->native_window; result = vkCreateSurfaceOHOS(instance, &createInfo, NULL, surface); if (result != VK_SUCCESS) { SDL_SetError("vkCreateSurfaceOHOS failed: %d", result); diff --git a/src/video/ohos/SDL_ohoswindow.c b/src/video/ohos/SDL_ohoswindow.c index 33a44dc309..8d0958fb08 100644 --- a/src/video/ohos/SDL_ohoswindow.c +++ b/src/video/ohos/SDL_ohoswindow.c @@ -1,4 +1,5 @@ #include "SDL_ohoswindow.h" +#include "SDL_internal.h" #include #ifdef SDL_VIDEO_DRIVER_OHOS @@ -6,19 +7,7 @@ #include "SDL_ohosvideo.h" bool OHOS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) { - window->internal = &windowData; -#ifdef SDL_VIDEO_OPENGL_EGL - if (window->flags & SDL_WINDOW_OPENGL) { - SDL_LockMutex(g_ohosPageMutex); - if (window->internal->egl_xcomponent == EGL_NO_SURFACE) - { - window->internal->egl_xcomponent = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)window->internal->native_window); - } - SDL_UnlockMutex(g_ohosPageMutex); - } -#endif - window->x = (int)window->internal->x; - window->y = (int)window->internal->y; + OHOS_windowDataFill(window); return true; } @@ -26,19 +15,20 @@ bool OHOS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propertie void OHOS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) { #ifdef SDL_VIDEO_OPENGL_EGL - if (window->flags & SDL_WINDOW_OPENGL) { - SDL_LockMutex(g_ohosPageMutex); - if (window->internal->egl_context) - { - SDL_EGL_DestroyContext(_this, window->internal->egl_context); + if (window->flags & SDL_WINDOW_OPENGL) { + SDL_LockMutex(g_ohosPageMutex); + if (window->internal->egl_context) + { + SDL_EGL_DestroyContext(_this, window->internal->egl_context); + } + if (window->internal->egl_surface != EGL_NO_SURFACE) + { + SDL_EGL_DestroySurface(_this, window->internal->egl_surface); + } + SDL_UnlockMutex(g_ohosPageMutex); } - if (window->internal->egl_xcomponent != EGL_NO_SURFACE) - { - SDL_EGL_DestroySurface(_this, window->internal->egl_xcomponent); - } - SDL_UnlockMutex(g_ohosPageMutex); - } -#endif + SDL_free(window->internal); + #endif } #endif From c99ae6e155f35ab5d9b768a5d99fa1d29aa01b62 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 07:36:26 +0800 Subject: [PATCH 21/92] Harmony port: review changes --- src/core/ohos/SDL_ohos.c | 56 +++++++++++++++++++++++++++++++++ src/core/ohos/SDL_ohos.h | 1 + src/video/ohos/SDL_ohoswindow.c | 16 +--------- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 32481d0f21..a9a71d10c8 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,3 +1,4 @@ +#include "SDL3/SDL_video.h" #include "SDL_internal.h" #include #include @@ -62,6 +63,16 @@ void OHOS_windowDataFill(SDL_Window* w) SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (_this->windows == NULL) + { + _this->windows = w; + } + else + { + _this->windows->next = w; + w->prev = _this->windows; + } + #ifdef SDL_VIDEO_OPENGL_EGL if (w->flags & SDL_WINDOW_OPENGL) { SDL_LockMutex(g_ohosPageMutex); @@ -73,6 +84,51 @@ void OHOS_windowDataFill(SDL_Window* w) } #endif } +void OHOS_removeWindow(SDL_Window* w) +{ + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (_this->windows == w) + { + _this->windows = _this->windows->next; + } + else + { + SDL_Window* curWin = _this->windows; + while (curWin != NULL) + { + if (curWin == w) + { + if (curWin->next == NULL) + { + curWin->prev->next = NULL; + } + else + { + curWin->prev->next = curWin->next; + curWin->next->prev = curWin->prev; + } + break; + } + curWin = curWin->next; + } + } + +#ifdef SDL_VIDEO_OPENGL_EGL + if (w->flags & SDL_WINDOW_OPENGL) { + SDL_LockMutex(g_ohosPageMutex); + if (w->internal->egl_context) + { + SDL_EGL_DestroyContext(_this, w->internal->egl_context); + } + if (w->internal->egl_surface != EGL_NO_SURFACE) + { + SDL_EGL_DestroySurface(_this, w->internal->egl_surface); + } + SDL_UnlockMutex(g_ohosPageMutex); + } + SDL_free(w->internal); +#endif +} static napi_value minus(napi_env env, napi_callback_info info) { diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 967f248491..99d584d1a0 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -9,6 +9,7 @@ extern SDL_Mutex *g_ohosPageMutex; void OHOS_windowDataFill(SDL_Window* w); +void OHOS_removeWindow(SDL_Window* w); typedef struct SDL_VideoData { SDL_Rect textRect; diff --git a/src/video/ohos/SDL_ohoswindow.c b/src/video/ohos/SDL_ohoswindow.c index 8d0958fb08..b74c725558 100644 --- a/src/video/ohos/SDL_ohoswindow.c +++ b/src/video/ohos/SDL_ohoswindow.c @@ -14,21 +14,7 @@ bool OHOS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propertie void OHOS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) { - #ifdef SDL_VIDEO_OPENGL_EGL - if (window->flags & SDL_WINDOW_OPENGL) { - SDL_LockMutex(g_ohosPageMutex); - if (window->internal->egl_context) - { - SDL_EGL_DestroyContext(_this, window->internal->egl_context); - } - if (window->internal->egl_surface != EGL_NO_SURFACE) - { - SDL_EGL_DestroySurface(_this, window->internal->egl_surface); - } - SDL_UnlockMutex(g_ohosPageMutex); - } - SDL_free(window->internal); - #endif + OHOS_removeWindow(window); } #endif From 298581d269766e79c1e3856bf97793e4f942535b Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 07:41:02 +0800 Subject: [PATCH 22/92] Harmony port: review changes --- src/core/ohos/SDL_ohos.c | 9 +++++++++ src/core/ohos/SDL_ohos.h | 4 ++-- src/video/ohos/SDL_ohosgl.c | 8 ++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index a9a71d10c8..a1bc83be95 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -130,6 +130,15 @@ void OHOS_removeWindow(SDL_Window* w) #endif } +void OHOS_LockPage() +{ + SDL_LockMutex(g_ohosPageMutex); +} +void OHOS_UnlockPage() +{ + SDL_UnlockMutex(g_ohosPageMutex); +} + static napi_value minus(napi_env env, napi_callback_info info) { size_t argc = 2; diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 99d584d1a0..476d9a6fab 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -6,10 +6,10 @@ #include "video/SDL_sysvideo.h" #include -extern SDL_Mutex *g_ohosPageMutex; - void OHOS_windowDataFill(SDL_Window* w); void OHOS_removeWindow(SDL_Window* w); +void OHOS_LockPage(); +void OHOS_UnlockPage(); typedef struct SDL_VideoData { SDL_Rect textRect; diff --git a/src/video/ohos/SDL_ohosgl.c b/src/video/ohos/SDL_ohosgl.c index 7f8bd92158..7dde4cab2f 100644 --- a/src/video/ohos/SDL_ohosgl.c +++ b/src/video/ohos/SDL_ohosgl.c @@ -19,11 +19,11 @@ SDL_GLContext OHOS_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window { SDL_GLContext result; - SDL_LockMutex(g_ohosPageMutex); + OHOS_LockPage(); result = SDL_EGL_CreateContext(_this, window->internal->egl_surface); - SDL_UnlockMutex(g_ohosPageMutex); + OHOS_UnlockPage(); return result; } @@ -32,11 +32,11 @@ bool OHOS_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) { bool result; - SDL_LockMutex(g_ohosPageMutex); + OHOS_LockPage(); result = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface); - SDL_UnlockMutex(g_ohosPageMutex); + OHOS_UnlockPage(); return result; } From 231ed48aab38f62a931307f500ea47cc0ab4087b Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 07:52:13 +0800 Subject: [PATCH 23/92] Harmony port: review changes --- src/core/ohos/SDL_ohos.c | 1 - src/video/ohos/SDL_ohoskeyboard.c | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index a1bc83be95..1a7acf4502 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,3 @@ -#include "SDL3/SDL_video.h" #include "SDL_internal.h" #include #include diff --git a/src/video/ohos/SDL_ohoskeyboard.c b/src/video/ohos/SDL_ohoskeyboard.c index 8dcfc6862b..4eab91e6b1 100644 --- a/src/video/ohos/SDL_ohoskeyboard.c +++ b/src/video/ohos/SDL_ohoskeyboard.c @@ -1,7 +1,5 @@ -#include "SDL3/SDL_log.h" -#include "SDL3/SDL_oldnames.h" -#include "SDL3/SDL_scancode.h" #include "SDL_internal.h" +#include "SDL3/SDL_scancode.h" #ifdef SDL_VIDEO_DRIVER_OHOS From 0f2b280c76d9a8ff053bcc6fa3d42851babedb76 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 08:14:40 +0800 Subject: [PATCH 24/92] Harmony port: entrypoint --- src/core/ohos/SDL_ohos.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 1a7acf4502..c54eebd566 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -16,7 +16,7 @@ #include "../../video/ohos/SDL_ohoskeyboard.h" static OHNativeWindow *g_ohosNativeWindow; -SDL_Mutex *g_ohosPageMutex = NULL; +static SDL_Mutex *g_ohosPageMutex = NULL; static OH_NativeXComponent_Callback callback; static OH_NativeXComponent_MouseEvent_Callback mouseCallback; static int x, y, wid, hei; @@ -187,6 +187,11 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) return result; } +static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) +{ + +} + static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { g_ohosNativeWindow = (OHNativeWindow *)window; @@ -265,7 +270,8 @@ static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { { "minus", NULL, minus, NULL, NULL, NULL, napi_default, NULL }, - { "sdlCallbackInit", NULL, sdlCallbackInit, NULL, NULL, NULL, napi_default, NULL } + { "sdlCallbackInit", NULL, sdlCallbackInit, NULL, NULL, NULL, napi_default, NULL }, + { "sdlLaunchMain", NULL, sdlLaunchMain, NULL, NULL, NULL, napi_default, NULL } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); From a9109972bf81a0a8ec966bd0dc230cb9cdb91f3e Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 08:25:47 +0800 Subject: [PATCH 25/92] Harmony port: entrypoint --- src/core/ohos/SDL_ohos.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index c54eebd566..53aa8fb6af 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,6 +1,8 @@ +#include "SDL3/SDL_log.h" #include "SDL_internal.h" #include #include +#include #include #include #include @@ -189,7 +191,28 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = { NULL, NULL }; + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + size_t libstringSize = 0; + napi_get_value_string_utf8(env, args[0], NULL, 0, &libstringSize); + char* libname = SDL_malloc(libstringSize + 1); + napi_get_value_string_utf8(env, args[0], libname, libstringSize + 1, &libstringSize); + + size_t fstringSize = 0; + napi_get_value_string_utf8(env, args[1], NULL, 0, &fstringSize); + char* fname = SDL_malloc(fstringSize + 1); + napi_get_value_string_utf8(env, args[1], libname, fstringSize + 1, &fstringSize); + + void* lib = dlopen(libname, RTLD_LAZY); + void* func = dlsym(lib, fname); + SDL_Log("Main func: %lld", (long long)func); + dlclose(lib); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; } static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) From b182ae0f8b361ce732d94146b246c764d0903dd0 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 08:31:51 +0800 Subject: [PATCH 26/92] Harmony port: entrypoint --- src/core/ohos/SDL_ohos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 53aa8fb6af..d2bad80137 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,3 @@ -#include "SDL3/SDL_log.h" #include "SDL_internal.h" #include #include From d031a499f0cb4be914a4922752f67c8f951e3899 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 09:16:28 +0800 Subject: [PATCH 27/92] Harmony port: entrypoint --- src/core/ohos/SDL_ohos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index d2bad80137..8cd2865e4f 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -202,11 +202,12 @@ static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) size_t fstringSize = 0; napi_get_value_string_utf8(env, args[1], NULL, 0, &fstringSize); char* fname = SDL_malloc(fstringSize + 1); - napi_get_value_string_utf8(env, args[1], libname, fstringSize + 1, &fstringSize); + napi_get_value_string_utf8(env, args[1], fname, fstringSize + 1, &fstringSize); void* lib = dlopen(libname, RTLD_LAZY); void* func = dlsym(lib, fname); - SDL_Log("Main func: %lld", (long long)func); + typedef int (*test)(); + ((test)func)(); dlclose(lib); napi_value result; From 04e80426fb98609e47d0cc95efb6e1543493c883 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 09:22:44 +0800 Subject: [PATCH 28/92] Harmony port: entrypoint --- src/video/ohos/SDL_ohosvideo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index 766d58d411..e3482c9f5b 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -33,6 +33,7 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) return NULL; } + device->num_displays = 1; device->internal = data; device->free = OHOS_DeviceFree; From d4039d3d6652b97708ba39413f4931e63fa4dc19 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 09:28:52 +0800 Subject: [PATCH 29/92] Harmony port: entrypoint --- src/core/ohos/SDL_ohos.c | 9 +++++++++ src/core/ohos/SDL_ohos.h | 2 ++ src/video/ohos/SDL_ohosvideo.c | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 8cd2865e4f..6c86dbde5f 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -139,6 +139,15 @@ void OHOS_UnlockPage() SDL_UnlockMutex(g_ohosPageMutex); } +int OHOS_FetchWidth() +{ + return wid; +} +int OHOS_FetchHeight() +{ + return hei; +} + static napi_value minus(napi_env env, napi_callback_info info) { size_t argc = 2; diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 476d9a6fab..f95941cd35 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -10,6 +10,8 @@ void OHOS_windowDataFill(SDL_Window* w); void OHOS_removeWindow(SDL_Window* w); void OHOS_LockPage(); void OHOS_UnlockPage(); +int OHOS_FetchWidth(); +int OHOS_FetchHeight(); typedef struct SDL_VideoData { SDL_Rect textRect; diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index e3482c9f5b..df99a7c97b 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -1,3 +1,5 @@ +#include "SDL3/SDL_pixels.h" +#include "SDL3/SDL_video.h" #include "SDL_internal.h" #include "../SDL_sysvideo.h" @@ -9,6 +11,20 @@ bool OHOS_VideoInit(SDL_VideoDevice *_this) { + _this->num_displays = 1; + SDL_DisplayMode mode; + SDL_zero(mode); + mode.format = SDL_PIXELFORMAT_RGBA32; + mode.w = OHOS_FetchWidth(); + mode.h = OHOS_FetchHeight(); + mode.refresh_rate = 60; + + SDL_DisplayID displayID = SDL_AddBasicVideoDisplay(&mode); + if (displayID == 0) { + return false; + } + _this->displays = SDL_calloc(1, sizeof(SDL_VideoDisplay*)); + _this->displays[0] = SDL_GetVideoDisplay(displayID); return true; } void OHOS_VideoQuit(SDL_VideoDevice *_this) @@ -33,7 +49,6 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) return NULL; } - device->num_displays = 1; device->internal = data; device->free = OHOS_DeviceFree; From 27df3404d92270b50402d1818b0568bfa6893b6a Mon Sep 17 00:00:00 2001 From: Starcloudsea <84891987+Starcloudsea@users.noreply.github.com> Date: Sun, 1 Jun 2025 09:46:50 +0800 Subject: [PATCH 30/92] Harmony port: video device --- src/video/ohos/SDL_ohosvideo.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index df99a7c97b..a48af52a71 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -11,7 +11,6 @@ bool OHOS_VideoInit(SDL_VideoDevice *_this) { - _this->num_displays = 1; SDL_DisplayMode mode; SDL_zero(mode); mode.format = SDL_PIXELFORMAT_RGBA32; @@ -20,11 +19,8 @@ bool OHOS_VideoInit(SDL_VideoDevice *_this) mode.refresh_rate = 60; SDL_DisplayID displayID = SDL_AddBasicVideoDisplay(&mode); - if (displayID == 0) { - return false; - } - _this->displays = SDL_calloc(1, sizeof(SDL_VideoDisplay*)); - _this->displays[0] = SDL_GetVideoDisplay(displayID); + SDL_Log("testvid: %u", displayID); + SDL_Log("testvid: %u", _this->displays[0]->id); return true; } void OHOS_VideoQuit(SDL_VideoDevice *_this) From cf3353a914496ef9df2418c61cdcf22d9894b19b Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 11:26:47 +0800 Subject: [PATCH 31/92] Harmony port: call test --- src/core/ohos/SDL_ohos.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 6c86dbde5f..ea91343f87 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -175,7 +175,11 @@ static napi_value minus(napi_env env, napi_callback_info info) static void sdlJSCallback(napi_env env, napi_value jsCb, void* content, void* data) { - + napi_value callb = NULL; + napi_get_reference_value(env, napiEnv.interface, &callb); + napi_value jsMethod = NULL; + napi_get_named_property(env, callb, "test", &jsMethod); + napi_call_function(env, NULL, jsMethod, 0, NULL, NULL); } static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) @@ -192,6 +196,8 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) napi_create_string_utf8(env, "SDLThreadSafe", NAPI_AUTO_LENGTH, &resName); napi_create_threadsafe_function(env, args[0], NULL, resName, 0, 1, NULL, NULL, NULL, sdlJSCallback, &napiEnv.func); + napi_call_threadsafe_function(napiEnv.func, NULL, napi_tsfn_nonblocking); + napi_value result; napi_create_int32(env, 0, &result); return result; From 9605a66f850eba2d6cfe6ccc85280823d8a92915 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 11:32:34 +0800 Subject: [PATCH 32/92] Harmony port: fix --- src/video/ohos/SDL_ohosvideo.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index a48af52a71..b8d5db49e9 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -1,5 +1,3 @@ -#include "SDL3/SDL_pixels.h" -#include "SDL3/SDL_video.h" #include "SDL_internal.h" #include "../SDL_sysvideo.h" From 56ccf29d3cfec8a630a7d3f477558073090baaa2 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 15:18:20 +0800 Subject: [PATCH 33/92] Harmony port: napi shell --- src/core/ohos/SDL_ohos.c | 99 ++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 20 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index ea91343f87..e7a41b9067 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef SDL_PLATFORM_OHOS @@ -28,28 +29,32 @@ static struct napi_ref interface; } napiEnv; -typedef union +typedef enum { - int i; - short s; - char c; - long long l; - float f; - double d; - const char* str; - bool b; + Int, + Long, + Double, + String +} napiArgType; + +typedef struct +{ + napiArgType type; + union + { + int i; + long long l; + double d; + const char* str; + } data; } napiCallbackArg; typedef struct { const char* func; - napiCallbackArg arg1; - napiCallbackArg arg2; - napiCallbackArg arg3; - napiCallbackArg arg4; - napiCallbackArg arg5; - napiCallbackArg arg6; - napiCallbackArg arg7; - napiCallbackArg arg8; + int argCount; + napiCallbackArg arg[16]; + napiArgType type; + napiCallbackArg ret; } napiCallbackData; void OHOS_windowDataFill(SDL_Window* w) @@ -175,11 +180,61 @@ static napi_value minus(napi_env env, napi_callback_info info) static void sdlJSCallback(napi_env env, napi_value jsCb, void* content, void* data) { + napiCallbackData* ar = (napiCallbackData*) data; + napi_value callb = NULL; napi_get_reference_value(env, napiEnv.interface, &callb); napi_value jsMethod = NULL; - napi_get_named_property(env, callb, "test", &jsMethod); - napi_call_function(env, NULL, jsMethod, 0, NULL, NULL); + napi_get_named_property(env, callb, ar->func, &jsMethod); + + napi_value args[16]; + for (int i = 0; i < ar->argCount; i++) + { + switch (ar->arg[i].type) + { + case Int: { + napi_create_int32(env, ar->arg[i].data.i, args + i); + break; + } + case Long: { + napi_create_int64(env, ar->arg[i].data.l, args + i); + break; + } + case Double: { + napi_create_double(env, ar->arg[i].data.d, args + i); + break; + } + case String: { + napi_create_string_utf8(env, ar->arg[i].data.str, SDL_strlen(ar->arg[i].data.str), args + i); + break; + } + } + } + + napi_value v; + napi_call_function(env, NULL, jsMethod, ar->argCount, args, &v); + switch (ar->type) { + case Int: { + napi_get_value_int32(env, v, &ar->ret.data.i); + break; + } + case Long: { + napi_get_value_int64(env, v, (int64_t*) &ar->ret.data.l); + break; + } + case String: { + size_t stringSize = 0; + napi_get_value_string_utf8(env, args[1], NULL, 0, &stringSize); + char* value = SDL_malloc(stringSize + 1); + napi_get_value_string_utf8(env, args[1], value, stringSize + 1, &stringSize); + ar->ret.data.str = value; + break; + } + case Double: { + napi_get_value_double(env, v, &ar->ret.data.d); + break; + } + } } static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) @@ -196,7 +251,11 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) napi_create_string_utf8(env, "SDLThreadSafe", NAPI_AUTO_LENGTH, &resName); napi_create_threadsafe_function(env, args[0], NULL, resName, 0, 1, NULL, NULL, NULL, sdlJSCallback, &napiEnv.func); - napi_call_threadsafe_function(napiEnv.func, NULL, napi_tsfn_nonblocking); + napiCallbackData data; + data.func = "test"; + data.argCount = 0; + + napi_call_threadsafe_function(napiEnv.func, &data, napi_tsfn_nonblocking); napi_value result; napi_create_int32(env, 0, &result); From c951070638e4569af8cfaf4709855d45ada9083c Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 18:13:48 +0800 Subject: [PATCH 34/92] Harmony port: touch event --- src/core/ohos/SDL_ohos.c | 47 ++++++++++++++++++++++++++++++++-- src/core/ohos/SDL_ohos.h | 12 ++++++++- src/video/ohos/SDL_ohostouch.c | 31 ++++++++++++++++++++++ src/video/ohos/SDL_ohostouch.h | 9 +++++++ 4 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 src/video/ohos/SDL_ohostouch.c create mode 100644 src/video/ohos/SDL_ohostouch.h diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index e7a41b9067..a9c0af9738 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,3 +1,4 @@ +#include "SDL3/SDL_events.h" #include "SDL_internal.h" #include #include @@ -14,6 +15,7 @@ #include "SDL_ohos.h" #include #include "../../video/ohos/SDL_ohosvideo.h" +#include "../../video/ohos/SDL_ohostouch.h" #include "SDL3/SDL_mutex.h" #include "../../video/ohos/SDL_ohoskeyboard.h" @@ -355,10 +357,51 @@ static void onKeyEvent(OH_NativeXComponent *component, void *window) } } +static void onNativeTouch(OH_NativeXComponent *component, void *window) +{ + OH_NativeXComponent_TouchEvent touchEvent; + OH_NativeXComponent_TouchPointToolType toolType = OH_NATIVEXCOMPONENT_TOOL_TYPE_UNKNOWN; + + OHOS_LockPage(); + OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent); + OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType); + + for (int i = 0; i < touchEvent.numPoints; i++) + { + SDL_OHOSTouchEvent e; + e.timestamp = touchEvent.timeStamp; + e.deviceId = touchEvent.deviceId; + e.fingerId = touchEvent.touchPoints[i].id; + e.area = touchEvent.touchPoints[i].size; + e.x = touchEvent.touchPoints[i].x / (float)wid; + e.y = touchEvent.touchPoints[i].y / (float)hei; + e.p = touchEvent.touchPoints[i].force; + + switch (touchEvent.touchPoints[i].type) { + case OH_NATIVEXCOMPONENT_DOWN: + e.type = SDL_EVENT_FINGER_DOWN; + break; + case OH_NATIVEXCOMPONENT_MOVE: + e.type = SDL_EVENT_FINGER_MOTION; + break; + case OH_NATIVEXCOMPONENT_UP: + e.type = SDL_EVENT_FINGER_UP; + break; + case OH_NATIVEXCOMPONENT_CANCEL: + case OH_NATIVEXCOMPONENT_UNKNOWN: + e.type = SDL_EVENT_FINGER_CANCELED; + break; + } + + OHOS_OnTouch(e); + } +} +static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) +{ + onNativeTouch(component, window); +} // TODO -static void onNativeTouch(OH_NativeXComponent *component, void *window) {} static void onNativeMouse(OH_NativeXComponent *component, void *window) {} -static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) {} static void OnHoverEvent(OH_NativeXComponent *component, bool isHover) {} static void OnFocusEvent(OH_NativeXComponent *component, void *window) {} static void OnBlurEvent(OH_NativeXComponent *component, void *window) {} diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index f95941cd35..e8adb2777b 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -1,7 +1,6 @@ #ifndef SDL_OHOS_H #define SDL_OHOS_H -#include "SDL3/SDL_mutex.h" #include "SDL3/SDL_video.h" #include "video/SDL_sysvideo.h" #include @@ -19,4 +18,15 @@ typedef struct SDL_VideoData { int isPausing; } SDL_VideoData; +typedef struct SDL_OHOSTouchEvent { + int64_t deviceId; + int32_t fingerId; + int type; + float x; + float y; + float p; + float area; + int64_t timestamp; +} SDL_OHOSTouchEvent; + #endif diff --git a/src/video/ohos/SDL_ohostouch.c b/src/video/ohos/SDL_ohostouch.c new file mode 100644 index 0000000000..673c28730c --- /dev/null +++ b/src/video/ohos/SDL_ohostouch.c @@ -0,0 +1,31 @@ +#include "../../core/ohos/SDL_ohos.h" +#include "SDL3/SDL_events.h" +#include "SDL3/SDL_touch.h" +#include "events/SDL_events_c.h" +void OHOS_OnTouch(SDL_OHOSTouchEvent event) +{ + if (SDL_AddTouch(event.deviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) + { + SDL_Log("Cannot add touch"); + return; + } + + switch (event.type) { + case SDL_EVENT_FINGER_DOWN: { + SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_DOWN, event.x, event.y, event.p); + break; + } + case SDL_EVENT_FINGER_MOTION: { + SDL_SendTouchMotion(event.timestamp, event.deviceId, event.fingerId, NULL, event.x, event.y, event.p); + break; + } + case SDL_EVENT_FINGER_UP: { + SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_UP, event.x, event.y, event.p); + break; + } + case SDL_EVENT_FINGER_CANCELED: { + SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_CANCELED, event.x, event.y, event.p); + break; + } + } +} diff --git a/src/video/ohos/SDL_ohostouch.h b/src/video/ohos/SDL_ohostouch.h new file mode 100644 index 0000000000..41dc9c6240 --- /dev/null +++ b/src/video/ohos/SDL_ohostouch.h @@ -0,0 +1,9 @@ +#ifndef SDL_OHOSTOUCH_H +#define SDL_OHOSTOUCH_H + +#include "SDL_internal.h" +#include "../../core/ohos/SDL_ohos.h" + +void OHOS_OnTouch(SDL_OHOSTouchEvent event); + +#endif From e91906683c987232ddf3ece43c004b0de85e8ee8 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 18:19:35 +0800 Subject: [PATCH 35/92] Harmony port: fix --- src/core/ohos/SDL_ohos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index a9c0af9738..563e202c35 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,3 @@ -#include "SDL3/SDL_events.h" #include "SDL_internal.h" #include #include From 048a59b21b90bb3ce36d876bd8af203331a2ade2 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 18:24:49 +0800 Subject: [PATCH 36/92] Harmony port: fix --- src/core/ohos/SDL_ohos.h | 11 ----------- src/video/ohos/SDL_ohostouch.c | 2 +- src/video/ohos/SDL_ohostouch.h | 12 ++++++++++-- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index e8adb2777b..8270b72bc5 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -18,15 +18,4 @@ typedef struct SDL_VideoData { int isPausing; } SDL_VideoData; -typedef struct SDL_OHOSTouchEvent { - int64_t deviceId; - int32_t fingerId; - int type; - float x; - float y; - float p; - float area; - int64_t timestamp; -} SDL_OHOSTouchEvent; - #endif diff --git a/src/video/ohos/SDL_ohostouch.c b/src/video/ohos/SDL_ohostouch.c index 673c28730c..bc7ae13e83 100644 --- a/src/video/ohos/SDL_ohostouch.c +++ b/src/video/ohos/SDL_ohostouch.c @@ -1,4 +1,4 @@ -#include "../../core/ohos/SDL_ohos.h" +#include "SDL_ohostouch.h" #include "SDL3/SDL_events.h" #include "SDL3/SDL_touch.h" #include "events/SDL_events_c.h" diff --git a/src/video/ohos/SDL_ohostouch.h b/src/video/ohos/SDL_ohostouch.h index 41dc9c6240..36deb44109 100644 --- a/src/video/ohos/SDL_ohostouch.h +++ b/src/video/ohos/SDL_ohostouch.h @@ -1,8 +1,16 @@ #ifndef SDL_OHOSTOUCH_H #define SDL_OHOSTOUCH_H -#include "SDL_internal.h" -#include "../../core/ohos/SDL_ohos.h" +typedef struct SDL_OHOSTouchEvent { + int64_t deviceId; + int32_t fingerId; + int type; + float x; + float y; + float p; + float area; + int64_t timestamp; +} SDL_OHOSTouchEvent; void OHOS_OnTouch(SDL_OHOSTouchEvent event); From 167fe8bdb02d1b72717de3c779c42e38a5bc0ac3 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 18:30:05 +0800 Subject: [PATCH 37/92] Harmony port: fix --- src/video/ohos/SDL_ohostouch.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/ohos/SDL_ohostouch.c b/src/video/ohos/SDL_ohostouch.c index bc7ae13e83..73a6af9aa3 100644 --- a/src/video/ohos/SDL_ohostouch.c +++ b/src/video/ohos/SDL_ohostouch.c @@ -1,7 +1,7 @@ #include "SDL_ohostouch.h" -#include "SDL3/SDL_events.h" -#include "SDL3/SDL_touch.h" -#include "events/SDL_events_c.h" +#include "SDL_internal.h" +#include "../../events/SDL_touch_c.h" + void OHOS_OnTouch(SDL_OHOSTouchEvent event) { if (SDL_AddTouch(event.deviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) From 01fed5980244e47fd19c1d2580d307e214f3618e Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 1 Jun 2025 18:35:06 +0800 Subject: [PATCH 38/92] Harmony port: fix --- src/video/ohos/SDL_ohostouch.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video/ohos/SDL_ohostouch.h b/src/video/ohos/SDL_ohostouch.h index 36deb44109..de33e45316 100644 --- a/src/video/ohos/SDL_ohostouch.h +++ b/src/video/ohos/SDL_ohostouch.h @@ -2,14 +2,14 @@ #define SDL_OHOSTOUCH_H typedef struct SDL_OHOSTouchEvent { - int64_t deviceId; - int32_t fingerId; + long long deviceId; + int fingerId; int type; float x; float y; float p; float area; - int64_t timestamp; + long long timestamp; } SDL_OHOSTouchEvent; void OHOS_OnTouch(SDL_OHOSTouchEvent event); From a4b48d3e2efaad04f9645a02483b1b42baf51d35 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Mon, 2 Jun 2025 09:19:33 +0800 Subject: [PATCH 39/92] Harmony port: surface destroy --- src/core/ohos/SDL_ohos.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 563e202c35..a651ba296b 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,3 +1,4 @@ +#include "SDL3/SDL_video.h" #include "SDL_internal.h" #include #include @@ -328,6 +329,24 @@ static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) } static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + SDL_Window *win = _this->windows; + while (win != NULL) + { +#ifdef SDL_VIDEO_OPENGL_EGL + if (win->flags & SDL_WINDOW_OPENGL) { + if (win->internal->egl_context) + { + SDL_EGL_DestroyContext(_this, win->internal->egl_context); + } + if (win->internal->egl_surface) + { + SDL_EGL_DestroySurface(_this, win->internal->egl_surface); + } + } +#endif + win = win->next; + } } static void onKeyEvent(OH_NativeXComponent *component, void *window) { From 35ea9148b2155e57bba630dafcc173d532b38763 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Mon, 2 Jun 2025 09:28:10 +0800 Subject: [PATCH 40/92] Harmony port: fix --- src/core/ohos/SDL_ohos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index a651ba296b..05ca451ac4 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,3 @@ -#include "SDL3/SDL_video.h" #include "SDL_internal.h" #include #include From ec588468a0bb6eac751bcdc0894e7ca068e8d6f7 Mon Sep 17 00:00:00 2001 From: Starcloudsea <84891987+Starcloudsea@users.noreply.github.com> Date: Mon, 2 Jun 2025 18:46:59 +0800 Subject: [PATCH 41/92] Harmony port: fix napi call --- src/core/ohos/SDL_ohos.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 05ca451ac4..b247ef1bf5 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -252,11 +252,13 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) napi_create_string_utf8(env, "SDLThreadSafe", NAPI_AUTO_LENGTH, &resName); napi_create_threadsafe_function(env, args[0], NULL, resName, 0, 1, NULL, NULL, NULL, sdlJSCallback, &napiEnv.func); - napiCallbackData data; - data.func = "test"; - data.argCount = 0; + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + data->func = "test"; + data->argCount = 0; - napi_call_threadsafe_function(napiEnv.func, &data, napi_tsfn_nonblocking); + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + SDL_free(data); napi_value result; napi_create_int32(env, 0, &result); From 9c3e5f2925bdec3c1d600b1370ed5158d4f1f50e Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sat, 7 Jun 2025 06:19:37 +0800 Subject: [PATCH 42/92] Harmony port: pthread enable --- CMakeLists.txt | 2 ++ cmake/sdlchecks.cmake | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 52021d8a55..3e0bc81c97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1543,6 +1543,8 @@ elseif(OHOS) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c") set(HAVE_SDL_TIMERS TRUE) + set(SDL_PTHREADS 1) + CheckPTHREAD() elseif(EMSCRIPTEN) # Hide noisy warnings that intend to aid mostly during initial stages of porting a new diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake index 06edce5bf5..11fd7716e5 100644 --- a/cmake/sdlchecks.cmake +++ b/cmake/sdlchecks.cmake @@ -829,7 +829,7 @@ macro(CheckPTHREAD) if(ANDROID OR SDL_PTHREADS_PRIVATE) # the android libc provides built-in support for pthreads, so no # additional linking or compile flags are necessary - elseif(LINUX) + elseif(LINUX OR OHOS) set(PTHREAD_CFLAGS "-D_REENTRANT") set(PTHREAD_LDFLAGS "-pthread") elseif(BSDI) From cf696785e81fadbd7d7c7efa67a8a6ae08b886f0 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:29:31 +0800 Subject: [PATCH 43/92] Update create-test-plan.py --- .github/workflows/create-test-plan.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 3b71e8d883..1d65042b25 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -765,10 +765,11 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta f"-DOHOS_ARCH={spec.harmony_arch}", "-DCMAKE_TOOLCHAIN_FILE=/opt/native/build/cmake/ohos.toolchain.cmake", )) - job.shared_lib = SharedLibType.SO_0 + job.shared_lib = SharedLibType.SO job.static_lib = StaticLibType.A job.run_tests = False job.test_pkg_config = False + job.werror = False case _: raise ValueError(f"Unsupported platform={spec.platform}") From 4781c6098369993ed10cf6673e7f47dec95cddc0 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:30:03 +0800 Subject: [PATCH 44/92] Update generic.yml --- .github/workflows/generic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index e50ac9857d..1cd6b62411 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -236,7 +236,7 @@ jobs: ${{ matrix.platform.source-cmd }} cmake --build build --config ${{ matrix.platform.cmake-build-type }} --verbose -- ${{ matrix.platform.cmake-build-arguments }} - name: 'Verify SDL_REVISION' - if: ${{ !matrix.platform.no-cmake && matrix.platform.platform != 'harmony' }} + if: ${{ !matrix.platform.no-cmake }} run: | echo "This should show us the SDL_REVISION" echo "Shared library:" From 56cea28cbdacfc9af1eca4b27889e1a90cd22a5c Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:32:18 +0800 Subject: [PATCH 45/92] Update CMakeLists.txt --- CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e0bc81c97..24f1ddaf3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1506,9 +1506,6 @@ elseif(OHOS) # disable warnings from the toolchain sdl_compile_options(PRIVATE "-Wno-unused-command-line-argument") - set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN "") - set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "") - sdl_link_dependency(OHOS_LIBS LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ohos/*.c") From 0f4c8f597f8b0e5f5e5be3b7ac63e2c7d112f998 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:38:39 +0800 Subject: [PATCH 46/92] Update create-test-plan.py --- .github/workflows/create-test-plan.py | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 1d65042b25..e21d28c522 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -764,6 +764,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta job.cmake_arguments.extend(( f"-DOHOS_ARCH={spec.harmony_arch}", "-DCMAKE_TOOLCHAIN_FILE=/opt/native/build/cmake/ohos.toolchain.cmake", + "-DCMAKE_PLATFORM_NO_VERSIONED_SONAME=1" )) job.shared_lib = SharedLibType.SO job.static_lib = StaticLibType.A From f6147e0a8176379053a62e52877c8975ae0d06e1 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:46:45 +0800 Subject: [PATCH 47/92] Update SDL_ohos.c --- src/core/ohos/SDL_ohos.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index b247ef1bf5..7b45afead2 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -421,9 +421,6 @@ static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) } // TODO static void onNativeMouse(OH_NativeXComponent *component, void *window) {} -static void OnHoverEvent(OH_NativeXComponent *component, bool isHover) {} -static void OnFocusEvent(OH_NativeXComponent *component, void *window) {} -static void OnBlurEvent(OH_NativeXComponent *component, void *window) {} static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { @@ -451,12 +448,9 @@ static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) mouseCallback.DispatchMouseEvent = OnDispatchTouchEventCB; mouseCallback.DispatchMouseEvent = onNativeMouse; - mouseCallback.DispatchHoverEvent = OnHoverEvent; - OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback); +OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback); OH_NativeXComponent_RegisterKeyEventCallback(nativeXComponent, onKeyEvent); - OH_NativeXComponent_RegisterFocusEventCallback(nativeXComponent, OnFocusEvent); - OH_NativeXComponent_RegisterBlurEventCallback(nativeXComponent, OnBlurEvent); g_ohosPageMutex = SDL_CreateMutex(); From 2b5815ad720083f0cd0477c4db0c39886fd08e06 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:50:03 +0800 Subject: [PATCH 48/92] Update CMakeLists.txt --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 24f1ddaf3b..6133950ebe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1506,7 +1506,7 @@ elseif(OHOS) # disable warnings from the toolchain sdl_compile_options(PRIVATE "-Wno-unused-command-line-argument") - sdl_link_dependency(OHOS_LIBS LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) + sdl_link_dependency(ohos LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ohos/*.c") if(SDL_VIDEO) @@ -3572,8 +3572,6 @@ if(SDL_SHARED) RESOURCE "${SDL_FRAMEWORK_RESOURCES}" ) endif() - elseif(OHOS) - # disable libtool postfix elseif(UNIX AND NOT ANDROID) set_target_properties(SDL3-shared PROPERTIES VERSION "${SDL_SO_VERSION}" From 376aa5dfd7065f4469b49c30ccb71691aaf39b37 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 06:57:05 +0800 Subject: [PATCH 49/92] Update create-test-plan.py --- .github/workflows/create-test-plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index e21d28c522..d002696a87 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -766,7 +766,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta "-DCMAKE_TOOLCHAIN_FILE=/opt/native/build/cmake/ohos.toolchain.cmake", "-DCMAKE_PLATFORM_NO_VERSIONED_SONAME=1" )) - job.shared_lib = SharedLibType.SO + job.shared_lib = SharedLibType.SO_0 job.static_lib = StaticLibType.A job.run_tests = False job.test_pkg_config = False From 29c6d182e27048134f55c7efc443c5f27c833333 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Sun, 8 Jun 2025 07:03:05 +0800 Subject: [PATCH 50/92] Update create-test-plan.py --- .github/workflows/create-test-plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index d002696a87..e21d28c522 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -766,7 +766,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta "-DCMAKE_TOOLCHAIN_FILE=/opt/native/build/cmake/ohos.toolchain.cmake", "-DCMAKE_PLATFORM_NO_VERSIONED_SONAME=1" )) - job.shared_lib = SharedLibType.SO_0 + job.shared_lib = SharedLibType.SO job.static_lib = StaticLibType.A job.run_tests = False job.test_pkg_config = False From a64975385338e19b6b634b6f71ba6917b796bdbc Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 07:15:06 +0800 Subject: [PATCH 51/92] Harmony port: format --- src/core/ohos/SDL_ohos.c | 209 ++++++++++++++---------------- src/video/ohos/SDL_ohosgl.c | 9 +- src/video/ohos/SDL_ohoskeyboard.c | 25 ++-- src/video/ohos/SDL_ohostouch.c | 41 +++--- src/video/ohos/SDL_ohosvideo.c | 8 +- src/video/ohos/SDL_ohosvulkan.c | 43 +++--- 6 files changed, 154 insertions(+), 181 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 7b45afead2..528e9b762e 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -10,13 +10,13 @@ #ifdef SDL_PLATFORM_OHOS -#include "napi/native_api.h" -#include "SDL_ohos.h" -#include -#include "../../video/ohos/SDL_ohosvideo.h" -#include "../../video/ohos/SDL_ohostouch.h" -#include "SDL3/SDL_mutex.h" #include "../../video/ohos/SDL_ohoskeyboard.h" +#include "../../video/ohos/SDL_ohostouch.h" +#include "../../video/ohos/SDL_ohosvideo.h" +#include "SDL3/SDL_mutex.h" +#include "SDL_ohos.h" +#include "napi/native_api.h" +#include static OHNativeWindow *g_ohosNativeWindow; static SDL_Mutex *g_ohosPageMutex = NULL; @@ -46,19 +46,19 @@ typedef struct int i; long long l; double d; - const char* str; + const char *str; } data; } napiCallbackArg; typedef struct { - const char* func; + const char *func; int argCount; napiCallbackArg arg[16]; napiArgType type; napiCallbackArg ret; } napiCallbackData; -void OHOS_windowDataFill(SDL_Window* w) +void OHOS_windowDataFill(SDL_Window *w) { w->internal = SDL_calloc(1, sizeof(SDL_WindowData)); w->x = x; @@ -69,12 +69,9 @@ void OHOS_windowDataFill(SDL_Window* w) SDL_VideoDevice *_this = SDL_GetVideoDevice(); - if (_this->windows == NULL) - { + if (_this->windows == NULL) { _this->windows = w; - } - else - { + } else { _this->windows->next = w; w->prev = _this->windows; } @@ -82,34 +79,25 @@ void OHOS_windowDataFill(SDL_Window* w) #ifdef SDL_VIDEO_OPENGL_EGL if (w->flags & SDL_WINDOW_OPENGL) { SDL_LockMutex(g_ohosPageMutex); - if (w->internal->egl_surface == EGL_NO_SURFACE) - { + if (w->internal->egl_surface == EGL_NO_SURFACE) { w->internal->egl_surface = SDL_EGL_CreateSurface(_this, w, (NativeWindowType)g_ohosNativeWindow); } SDL_UnlockMutex(g_ohosPageMutex); } #endif } -void OHOS_removeWindow(SDL_Window* w) +void OHOS_removeWindow(SDL_Window *w) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); - if (_this->windows == w) - { + if (_this->windows == w) { _this->windows = _this->windows->next; - } - else - { - SDL_Window* curWin = _this->windows; - while (curWin != NULL) - { - if (curWin == w) - { - if (curWin->next == NULL) - { + } else { + SDL_Window *curWin = _this->windows; + while (curWin != NULL) { + if (curWin == w) { + if (curWin->next == NULL) { curWin->prev->next = NULL; - } - else - { + } else { curWin->prev->next = curWin->next; curWin->next->prev = curWin->prev; } @@ -122,12 +110,10 @@ void OHOS_removeWindow(SDL_Window* w) #ifdef SDL_VIDEO_OPENGL_EGL if (w->flags & SDL_WINDOW_OPENGL) { SDL_LockMutex(g_ohosPageMutex); - if (w->internal->egl_context) - { + if (w->internal->egl_context) { SDL_EGL_DestroyContext(_this, w->internal->egl_context); } - if (w->internal->egl_surface != EGL_NO_SURFACE) - { + if (w->internal->egl_surface != EGL_NO_SURFACE) { SDL_EGL_DestroySurface(_this, w->internal->egl_surface); } SDL_UnlockMutex(g_ohosPageMutex); @@ -179,9 +165,9 @@ static napi_value minus(napi_env env, napi_callback_info info) return sum; } -static void sdlJSCallback(napi_env env, napi_value jsCb, void* content, void* data) +static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *data) { - napiCallbackData* ar = (napiCallbackData*) data; + napiCallbackData *ar = (napiCallbackData *)data; napi_value callb = NULL; napi_get_reference_value(env, napiEnv.interface, &callb); @@ -189,52 +175,58 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void* content, void* da napi_get_named_property(env, callb, ar->func, &jsMethod); napi_value args[16]; - for (int i = 0; i < ar->argCount; i++) - { - switch (ar->arg[i].type) + for (int i = 0; i < ar->argCount; i++) { + switch (ar->arg[i].type) { + case Int: { - case Int: { - napi_create_int32(env, ar->arg[i].data.i, args + i); - break; - } - case Long: { - napi_create_int64(env, ar->arg[i].data.l, args + i); - break; - } - case Double: { - napi_create_double(env, ar->arg[i].data.d, args + i); - break; - } - case String: { - napi_create_string_utf8(env, ar->arg[i].data.str, SDL_strlen(ar->arg[i].data.str), args + i); - break; - } + napi_create_int32(env, ar->arg[i].data.i, args + i); + break; + } + case Long: + { + napi_create_int64(env, ar->arg[i].data.l, args + i); + break; + } + case Double: + { + napi_create_double(env, ar->arg[i].data.d, args + i); + break; + } + case String: + { + napi_create_string_utf8(env, ar->arg[i].data.str, SDL_strlen(ar->arg[i].data.str), args + i); + break; + } } } napi_value v; napi_call_function(env, NULL, jsMethod, ar->argCount, args, &v); switch (ar->type) { - case Int: { - napi_get_value_int32(env, v, &ar->ret.data.i); - break; - } - case Long: { - napi_get_value_int64(env, v, (int64_t*) &ar->ret.data.l); - break; - } - case String: { - size_t stringSize = 0; - napi_get_value_string_utf8(env, args[1], NULL, 0, &stringSize); - char* value = SDL_malloc(stringSize + 1); - napi_get_value_string_utf8(env, args[1], value, stringSize + 1, &stringSize); - ar->ret.data.str = value; - break; - } - case Double: { - napi_get_value_double(env, v, &ar->ret.data.d); - break; - } + case Int: + { + napi_get_value_int32(env, v, &ar->ret.data.i); + break; + } + case Long: + { + napi_get_value_int64(env, v, (int64_t *)&ar->ret.data.l); + break; + } + case String: + { + size_t stringSize = 0; + napi_get_value_string_utf8(env, args[1], NULL, 0, &stringSize); + char *value = SDL_malloc(stringSize + 1); + napi_get_value_string_utf8(env, args[1], value, stringSize + 1, &stringSize); + ar->ret.data.str = value; + break; + } + case Double: + { + napi_get_value_double(env, v, &ar->ret.data.d); + break; + } } } @@ -257,7 +249,7 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) data->argCount = 0; napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); - + SDL_free(data); napi_value result; @@ -273,16 +265,16 @@ static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) size_t libstringSize = 0; napi_get_value_string_utf8(env, args[0], NULL, 0, &libstringSize); - char* libname = SDL_malloc(libstringSize + 1); + char *libname = SDL_malloc(libstringSize + 1); napi_get_value_string_utf8(env, args[0], libname, libstringSize + 1, &libstringSize); size_t fstringSize = 0; napi_get_value_string_utf8(env, args[1], NULL, 0, &fstringSize); - char* fname = SDL_malloc(fstringSize + 1); + char *fname = SDL_malloc(fstringSize + 1); napi_get_value_string_utf8(env, args[1], fname, fstringSize + 1, &fstringSize); - void* lib = dlopen(libname, RTLD_LAZY); - void* func = dlsym(lib, fname); + void *lib = dlopen(libname, RTLD_LAZY); + void *func = dlsym(lib, fname); typedef int (*test)(); ((test)func)(); dlclose(lib); @@ -332,16 +324,13 @@ static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { SDL_VideoDevice *_this = SDL_GetVideoDevice(); SDL_Window *win = _this->windows; - while (win != NULL) - { + while (win != NULL) { #ifdef SDL_VIDEO_OPENGL_EGL if (win->flags & SDL_WINDOW_OPENGL) { - if (win->internal->egl_context) - { + if (win->internal->egl_context) { SDL_EGL_DestroyContext(_this, win->internal->egl_context); } - if (win->internal->egl_surface) - { + if (win->internal->egl_surface) { SDL_EGL_DestroySurface(_this, win->internal->egl_surface); } } @@ -352,8 +341,7 @@ static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) static void onKeyEvent(OH_NativeXComponent *component, void *window) { OH_NativeXComponent_KeyEvent *keyEvent = NULL; - if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) - { + if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) { OH_NativeXComponent_KeyAction action; OH_NativeXComponent_KeyCode code; OH_NativeXComponent_EventSourceType sourceType; @@ -362,14 +350,10 @@ static void onKeyEvent(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetKeyEventCode(keyEvent, &code); OH_NativeXComponent_GetKeyEventSourceType(keyEvent, &sourceType); - if (sourceType == OH_NATIVEXCOMPONENT_SOURCE_TYPE_KEYBOARD) - { - if (OH_NATIVEXCOMPONENT_KEY_ACTION_DOWN == action) - { + if (sourceType == OH_NATIVEXCOMPONENT_SOURCE_TYPE_KEYBOARD) { + if (OH_NATIVEXCOMPONENT_KEY_ACTION_DOWN == action) { OHOS_OnKeyDown(code); - } - else if (OH_NATIVEXCOMPONENT_KEY_ACTION_UP == action) - { + } else if (OH_NATIVEXCOMPONENT_KEY_ACTION_UP == action) { OHOS_OnKeyUp(code); } } @@ -385,8 +369,7 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent); OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType); - for (int i = 0; i < touchEvent.numPoints; i++) - { + for (int i = 0; i < touchEvent.numPoints; i++) { SDL_OHOSTouchEvent e; e.timestamp = touchEvent.timeStamp; e.deviceId = touchEvent.deviceId; @@ -397,19 +380,19 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) e.p = touchEvent.touchPoints[i].force; switch (touchEvent.touchPoints[i].type) { - case OH_NATIVEXCOMPONENT_DOWN: - e.type = SDL_EVENT_FINGER_DOWN; - break; - case OH_NATIVEXCOMPONENT_MOVE: - e.type = SDL_EVENT_FINGER_MOTION; - break; - case OH_NATIVEXCOMPONENT_UP: - e.type = SDL_EVENT_FINGER_UP; - break; - case OH_NATIVEXCOMPONENT_CANCEL: - case OH_NATIVEXCOMPONENT_UNKNOWN: - e.type = SDL_EVENT_FINGER_CANCELED; - break; + case OH_NATIVEXCOMPONENT_DOWN: + e.type = SDL_EVENT_FINGER_DOWN; + break; + case OH_NATIVEXCOMPONENT_MOVE: + e.type = SDL_EVENT_FINGER_MOTION; + break; + case OH_NATIVEXCOMPONENT_UP: + e.type = SDL_EVENT_FINGER_UP; + break; + case OH_NATIVEXCOMPONENT_CANCEL: + case OH_NATIVEXCOMPONENT_UNKNOWN: + e.type = SDL_EVENT_FINGER_CANCELED; + break; } OHOS_OnTouch(e); @@ -448,7 +431,7 @@ static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) mouseCallback.DispatchMouseEvent = OnDispatchTouchEventCB; mouseCallback.DispatchMouseEvent = onNativeMouse; -OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback); + OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback); OH_NativeXComponent_RegisterKeyEventCallback(nativeXComponent, onKeyEvent); diff --git a/src/video/ohos/SDL_ohosgl.c b/src/video/ohos/SDL_ohosgl.c index 7dde4cab2f..38ad6e918a 100644 --- a/src/video/ohos/SDL_ohosgl.c +++ b/src/video/ohos/SDL_ohosgl.c @@ -1,16 +1,13 @@ #include "SDL_internal.h" #ifdef SDL_VIDEO_DRIVER_OHOS -#include "SDL_ohosvideo.h" #include "../../core/ohos/SDL_ohos.h" +#include "SDL_ohosvideo.h" bool OHOS_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context) { - if (window && context) - { + if (window && context) { return SDL_EGL_MakeCurrent(_this, window->internal->egl_surface, context); - } - else - { + } else { return SDL_EGL_MakeCurrent(_this, NULL, NULL); } } diff --git a/src/video/ohos/SDL_ohoskeyboard.c b/src/video/ohos/SDL_ohoskeyboard.c index 4eab91e6b1..86ee21685d 100644 --- a/src/video/ohos/SDL_ohoskeyboard.c +++ b/src/video/ohos/SDL_ohoskeyboard.c @@ -1,5 +1,5 @@ -#include "SDL_internal.h" #include "SDL3/SDL_scancode.h" +#include "SDL_internal.h" #ifdef SDL_VIDEO_DRIVER_OHOS @@ -21,11 +21,11 @@ static SDL_Scancode OHOS_Keycodes[] = { SDL_SCANCODE_MEDIA_NEXT_TRACK, SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, SDL_SCANCODE_MEDIA_REWIND, - SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_FAST_FORWARD + SDL_SCANCODE_UNKNOWN, // KEY_MEDIA_FAST_FORWARD SDL_SCANCODE_VOLUMEUP, SDL_SCANCODE_VOLUMEDOWN, SDL_SCANCODE_POWER, - SDL_SCANCODE_UNKNOWN, // KEY_CAMERA + SDL_SCANCODE_UNKNOWN, // KEY_CAMERA SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN, SDL_SCANCODE_MUTE, @@ -2019,9 +2019,9 @@ static SDL_Scancode OHOS_Keycodes[] = { SDL_SCANCODE_UNKNOWN, // KEY_STAR SDL_SCANCODE_UNKNOWN, // KEY_POUND SDL_SCANCODE_UP, - SDL_SCANCODE_DOWN, // KEY_DPAD_DOWN - SDL_SCANCODE_LEFT, // KEY_DPAD_LEFT - SDL_SCANCODE_RIGHT, // KEY_DPAD_RIGHT + SDL_SCANCODE_DOWN, // KEY_DPAD_DOWN + SDL_SCANCODE_LEFT, // KEY_DPAD_LEFT + SDL_SCANCODE_RIGHT, // KEY_DPAD_RIGHT SDL_SCANCODE_SELECT, // KEY_DPAD_CENTER SDL_SCANCODE_A, SDL_SCANCODE_B, @@ -2082,8 +2082,8 @@ static SDL_Scancode OHOS_Keycodes[] = { SDL_SCANCODE_RCTRL, SDL_SCANCODE_CAPSLOCK, SDL_SCANCODE_SCROLLLOCK, - SDL_SCANCODE_LGUI, // KEY_META_LEFT - SDL_SCANCODE_RGUI, // KEY_META_RIGHT + SDL_SCANCODE_LGUI, // KEY_META_LEFT + SDL_SCANCODE_RGUI, // KEY_META_RIGHT SDL_SCANCODE_UNKNOWN, // KEY_FUNCTION SDL_SCANCODE_SYSREQ, SDL_SCANCODE_PAUSE, // KEY_BREAK @@ -3123,16 +3123,13 @@ static SDL_Scancode OHOS_Keycodes[] = { static SDL_Scancode TranslateKeycode(int keycode) { SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN; - if (keycode <= -1) - { + if (keycode <= -1) { return SDL_SCANCODE_UNKNOWN; } - if (keycode < SDL_arraysize(OHOS_Keycodes)) - { + if (keycode < SDL_arraysize(OHOS_Keycodes)) { scancode = OHOS_Keycodes[keycode]; } - if (scancode == SDL_SCANCODE_UNKNOWN) - { + if (scancode == SDL_SCANCODE_UNKNOWN) { SDL_Log("Unknown keycode %d", keycode); } return scancode; diff --git a/src/video/ohos/SDL_ohostouch.c b/src/video/ohos/SDL_ohostouch.c index 73a6af9aa3..a7f16bfedc 100644 --- a/src/video/ohos/SDL_ohostouch.c +++ b/src/video/ohos/SDL_ohostouch.c @@ -1,31 +1,34 @@ #include "SDL_ohostouch.h" -#include "SDL_internal.h" #include "../../events/SDL_touch_c.h" +#include "SDL_internal.h" void OHOS_OnTouch(SDL_OHOSTouchEvent event) { - if (SDL_AddTouch(event.deviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) - { + if (SDL_AddTouch(event.deviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) { SDL_Log("Cannot add touch"); return; } switch (event.type) { - case SDL_EVENT_FINGER_DOWN: { - SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_DOWN, event.x, event.y, event.p); - break; - } - case SDL_EVENT_FINGER_MOTION: { - SDL_SendTouchMotion(event.timestamp, event.deviceId, event.fingerId, NULL, event.x, event.y, event.p); - break; - } - case SDL_EVENT_FINGER_UP: { - SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_UP, event.x, event.y, event.p); - break; - } - case SDL_EVENT_FINGER_CANCELED: { - SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_CANCELED, event.x, event.y, event.p); - break; - } + case SDL_EVENT_FINGER_DOWN: + { + SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_DOWN, event.x, event.y, event.p); + break; + } + case SDL_EVENT_FINGER_MOTION: + { + SDL_SendTouchMotion(event.timestamp, event.deviceId, event.fingerId, NULL, event.x, event.y, event.p); + break; + } + case SDL_EVENT_FINGER_UP: + { + SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_UP, event.x, event.y, event.p); + break; + } + case SDL_EVENT_FINGER_CANCELED: + { + SDL_SendTouch(event.timestamp, event.deviceId, event.fingerId, NULL, SDL_EVENT_FINGER_CANCELED, event.x, event.y, event.p); + break; + } } } diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index b8d5db49e9..f5e721e38a 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -1,11 +1,11 @@ -#include "SDL_internal.h" #include "../SDL_sysvideo.h" +#include "SDL_internal.h" #ifdef SDL_VIDEO_DRIVER_OHOS -#include "SDL_ohosvulkan.h" -#include "SDL_ohosgl.h" -#include "SDL_ohoswindow.h" #include "../../core/ohos/SDL_ohos.h" +#include "SDL_ohosgl.h" +#include "SDL_ohosvulkan.h" +#include "SDL_ohoswindow.h" bool OHOS_VideoInit(SDL_VideoDevice *_this) { diff --git a/src/video/ohos/SDL_ohosvulkan.c b/src/video/ohos/SDL_ohosvulkan.c index ca2407497d..e33aece5a7 100644 --- a/src/video/ohos/SDL_ohosvulkan.c +++ b/src/video/ohos/SDL_ohosvulkan.c @@ -4,50 +4,44 @@ #ifdef SDL_VIDEO_DRIVER_OHOS #define VK_USE_PLATFORM_OHOS 1 -#include "vulkan/vulkan.h" -#include "../SDL_sysvideo.h" #include "../../core/ohos/SDL_ohos.h" -#include "vulkan/vulkan_ohos.h" +#include "../SDL_sysvideo.h" #include "SDL_ohosvideo.h" +#include "vulkan/vulkan.h" +#include "vulkan/vulkan_ohos.h" #include static int loadedCount = 0; bool OHOS_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path) { PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; - if (_this->vulkan_config.loader_handle) - { + if (_this->vulkan_config.loader_handle) { return SDL_SetError("Vulkan already loaded"); } /* Load the Vulkan loader library */ - if (!path) - { + if (!path) { path = SDL_getenv("SDL_VULKAN_LIBRARY"); } - if (!path) - { + if (!path) { path = "libvulkan.so"; } _this->vulkan_config.loader_handle = SDL_LoadObject(path); - if (!_this->vulkan_config.loader_handle) - { + if (!_this->vulkan_config.loader_handle) { return false; } SDL_strlcpy(_this->vulkan_config.loader_path, path, SDL_arraysize(_this->vulkan_config.loader_path)); vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction( _this->vulkan_config.loader_handle, "vkGetInstanceProcAddr"); - if (!vkGetInstanceProcAddr) - { + if (!vkGetInstanceProcAddr) { goto fail; } _this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr; _this->vulkan_config.vkEnumerateInstanceExtensionProperties = (void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)( VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties"); - if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) - { + if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) { goto fail; } loadedCount++; @@ -61,8 +55,7 @@ fail: void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this) { - if (loadedCount == 0) - { + if (loadedCount == 0) { return; } loadedCount--; @@ -72,7 +65,7 @@ void OHOS_Vulkan_UnloadLibrary(SDL_VideoDevice *_this) } } -char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count) +char const *const *OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count) { static const char *const extensionsForOHOS[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_OHOS_SURFACE_EXTENSION_NAME @@ -84,10 +77,10 @@ char const* const* OHOS_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uin } bool OHOS_Vulkan_CreateSurface(SDL_VideoDevice *_this, - SDL_Window *window, - VkInstance instance, - const struct VkAllocationCallbacks *allocator, - VkSurfaceKHR *surface) + SDL_Window *window, + VkInstance instance, + const struct VkAllocationCallbacks *allocator, + VkSurfaceKHR *surface) { VkResult result; @@ -122,9 +115,9 @@ bool OHOS_Vulkan_CreateSurface(SDL_VideoDevice *_this, } void OHOS_Vulkan_DestroySurface(SDL_VideoDevice *_this, - VkInstance instance, - VkSurfaceKHR surface, - const struct VkAllocationCallbacks *allocator) + VkInstance instance, + VkSurfaceKHR surface, + const struct VkAllocationCallbacks *allocator) { if (_this->vulkan_config.loader_handle) { PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = From e7bcd9a9aec3c8ca6024deaca318617b1105fbe0 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 07:52:03 +0800 Subject: [PATCH 52/92] Harmony port: workflow fix [sdl-ci-filter harmony] --- .github/workflows/create-test-plan.py | 80 ++++++++++++++------------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index e21d28c522..2aa16c7465 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -103,47 +103,49 @@ class JobSpec: JOB_SPECS = { - # "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ), - # "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ), - # "msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ), - # "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ), - # "msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ), - # "msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ), - # "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ), - # "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ), - # "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ), - # "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ), - # "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ), - # "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), - # "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ), - # "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ), - # "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:3.0.20250408.124536", ), - # "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ), - # "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), - # "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), - # "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), - # "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ), - # "ios": JobSpec(name="iOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ), - # "tvos": JobSpec(name="tvOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ), - # "android-cmake": JobSpec(name="Android (CMake)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ), - # "android-cmake-lean": JobSpec(name="Android (CMake, lean)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-lean-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, lean=True, ), - # "android-mk": JobSpec(name="Android (Android.mk)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ), - # "android-gradle": JobSpec(name="Android (Gradle)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ), - # "emscripten": JobSpec(name="Emscripten", os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ), + "msys2-mingw32": JobSpec(name="Windows (msys2, mingw32)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw32", msys2_platform=Msys2Platform.Mingw32, ), + "msys2-mingw64": JobSpec(name="Windows (msys2, mingw64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64", msys2_platform=Msys2Platform.Mingw64, ), + "msys2-clang64": JobSpec(name="Windows (msys2, clang64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-clang", msys2_platform=Msys2Platform.Clang64, ), + "msys2-ucrt64": JobSpec(name="Windows (msys2, ucrt64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msys2, artifact="SDL-mingw64-ucrt", msys2_platform=Msys2Platform.Ucrt64, ), + "msvc-x64": JobSpec(name="Windows (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x64", msvc_arch=MsvcArch.X64, msvc_project="VisualC/SDL.sln", ), + "msvc-x86": JobSpec(name="Windows (MSVC, x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-x86", msvc_arch=MsvcArch.X86, msvc_project="VisualC/SDL.sln", ), + "msvc-clang-x64": JobSpec(name="Windows (MSVC, clang-cl x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x64", msvc_arch=MsvcArch.X64, clang_cl=True, ), + "msvc-clang-x86": JobSpec(name="Windows (MSVC, clang-cl x86)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-clang-cl-x86", msvc_arch=MsvcArch.X86, clang_cl=True, ), + "msvc-arm32": JobSpec(name="Windows (MSVC, ARM)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm32", msvc_arch=MsvcArch.Arm32, ), + "msvc-arm64": JobSpec(name="Windows (MSVC, ARM64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-arm64", msvc_arch=MsvcArch.Arm64, ), + "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)", os=JobOs.WindowsLatest, platform=SdlPlatform.Msvc, artifact="SDL-VC-GDK", msvc_arch=MsvcArch.X64, msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ), + "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), + "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ), + "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ), + "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:3.0.20250408.124536", ), + "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ), + "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), + "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), + "macos-framework-arm64": JobSpec(name="MacOS (Framework) (arm64)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact=None, apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, ), + "macos-gnu-arm64": JobSpec(name="MacOS (GNU prefix)", os=JobOs.MacosLatest, platform=SdlPlatform.MacOS, artifact="SDL-macos-arm64-gnu", apple_framework=False, apple_archs={AppleArch.Aarch64, }, ), + "ios": JobSpec(name="iOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Ios, artifact="SDL-ios-arm64", xcode=True, ), + "tvos": JobSpec(name="tvOS (CMake & xcode)", os=JobOs.MacosLatest, platform=SdlPlatform.Tvos, artifact="SDL-tvos-arm64", xcode=True, ), + "android-cmake": JobSpec(name="Android (CMake)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, ), + "android-cmake-lean": JobSpec(name="Android (CMake, lean)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact="SDL-lean-android-arm64", android_abi="arm64-v8a", android_arch="aarch64", android_platform=23, lean=True, ), + "android-mk": JobSpec(name="Android (Android.mk)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_mk=True, ), + "android-gradle": JobSpec(name="Android (Gradle)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Android, artifact=None, no_cmake=True, android_gradle=True, ), + "emscripten": JobSpec(name="Emscripten", os=JobOs.UbuntuLatest, platform=SdlPlatform.Emscripten, artifact="SDL-emscripten", ), "haiku": JobSpec(name="Haiku", os=JobOs.UbuntuLatest, platform=SdlPlatform.Haiku, artifact="SDL-haiku-x64", container="ghcr.io/haiku/cross-compiler:x86_64-r1beta5", ), - # "loongarch64": JobSpec(name="LoongArch64", os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ), - # "n3ds": JobSpec(name="Nintendo 3DS", os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ), - # "ppc": JobSpec(name="PowerPC", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ), - # "ppc64": JobSpec(name="PowerPC64", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC64, artifact="SDL-ppc64le", container="dockcross/linux-ppc64le:latest", ), - # "ps2": JobSpec(name="Sony PlayStation 2", os=JobOs.UbuntuLatest, platform=SdlPlatform.Ps2, artifact="SDL-ps2", container="ps2dev/ps2dev:latest", ), - # "psp": JobSpec(name="Sony PlayStation Portable", os=JobOs.UbuntuLatest, platform=SdlPlatform.Psp, artifact="SDL-psp", container="pspdev/pspdev:latest", ), - # "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pib", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib, ), - # "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ), - # "riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ), - # "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), - # "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), - # "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), + "loongarch64": JobSpec(name="LoongArch64", os=JobOs.UbuntuLatest, platform=SdlPlatform.LoongArch64, artifact="SDL-loongarch64", ), + "n3ds": JobSpec(name="Nintendo 3DS", os=JobOs.UbuntuLatest, platform=SdlPlatform.N3ds, artifact="SDL-n3ds", container="devkitpro/devkitarm:latest", ), + "ppc": JobSpec(name="PowerPC", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC, artifact="SDL-ppc", container="dockcross/linux-ppc:latest", ), + "ppc64": JobSpec(name="PowerPC64", os=JobOs.UbuntuLatest, platform=SdlPlatform.PowerPC64, artifact="SDL-ppc64le", container="dockcross/linux-ppc64le:latest", ), + "ps2": JobSpec(name="Sony PlayStation 2", os=JobOs.UbuntuLatest, platform=SdlPlatform.Ps2, artifact="SDL-ps2", container="ps2dev/ps2dev:latest", ), + "psp": JobSpec(name="Sony PlayStation Portable", os=JobOs.UbuntuLatest, platform=SdlPlatform.Psp, artifact="SDL-psp", container="pspdev/pspdev:latest", ), + "vita-pib": JobSpec(name="Sony PlayStation Vita (GLES w/ pib)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pib", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pib, ), + "vita-pvr": JobSpec(name="Sony PlayStation Vita (GLES w/ PVR_PSP2)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Vita, artifact="SDL-vita-pvr", container="vitasdk/vitasdk:latest", vita_gles=VitaGLES.Pvr, ), + "riscos": JobSpec(name="RISC OS", os=JobOs.UbuntuLatest, platform=SdlPlatform.Riscos, artifact="SDL-riscos", container="riscosdotinfo/riscos-gccsdk-4.7:latest", ), + "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), + "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), + "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), + "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="armeabi-v7a"), + "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="x86_64"), } From d7a01e677840f75cc2e02bf3034519dc41d8b9e1 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 07:57:03 +0800 Subject: [PATCH 53/92] Harmony port: workflow fix [sdl-ci-filter harmony] --- .github/workflows/create-test-plan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 2aa16c7465..5ab56b0df9 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -143,9 +143,9 @@ JOB_SPECS = { "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), - "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), - "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="armeabi-v7a"), - "harmony": JobSpec(name="Harmony", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="x86_64"), + "harmony": JobSpec(name="Harmony (Arm64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), + "harmony": JobSpec(name="Harmony (Arm32)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="armeabi-v7a"), + "harmony": JobSpec(name="Harmony (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="x86_64"), } From b8f497f7206f8a59099e370b5d47e238f3e40278 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 08:00:34 +0800 Subject: [PATCH 54/92] Harmony port: workflow fix [sdl-ci-filter harmony] --- .github/workflows/create-test-plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 5ab56b0df9..7970696dfe 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -117,7 +117,7 @@ JOB_SPECS = { "ubuntu-22.04": JobSpec(name="Ubuntu 22.04", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04", ), "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-ubuntu24.04-arm64", ), "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Linux, artifact="SDL-steamrt3", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ), - "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:3.0.20250408.124536", ), + "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)", os=JobOs.Ubuntu24_04_arm, platform=SdlPlatform.Linux, artifact="SDL-steamrt3-arm64", container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:latest", ), "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ), "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)", os=JobOs.Ubuntu22_04, platform=SdlPlatform.Linux, artifact="SDL-ubuntu22.04-icc", intel=IntelCompiler.Icc, ), "macos-framework-x64": JobSpec(name="MacOS (Framework) (x64)", os=JobOs.Macos13, platform=SdlPlatform.MacOS, artifact="SDL-macos-framework", apple_framework=True, apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ), From 38a7790ae91cea0d81e3ed2fbdce5ac9990f22bd Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 08:01:32 +0800 Subject: [PATCH 55/92] Harmony port: workflow fix [sdl-ci-filter harmony-*] --- .github/workflows/create-test-plan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 7970696dfe..8cae0148d6 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -143,9 +143,9 @@ JOB_SPECS = { "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), - "harmony": JobSpec(name="Harmony (Arm64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), - "harmony": JobSpec(name="Harmony (Arm32)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="armeabi-v7a"), - "harmony": JobSpec(name="Harmony (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="x86_64"), + "harmony-arm64": JobSpec(name="Harmony (Arm64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), + "harmony-arm32": JobSpec(name="Harmony (Arm32)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="armeabi-v7a"), + "harmony-x86_64": JobSpec(name="Harmony (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="x86_64"), } From e7e0bd27689cbc98c63213e81913677705ecf0ea Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 08:14:10 +0800 Subject: [PATCH 56/92] Harmony port: workflow fix [sdl-ci-filter harmony-*] --- .github/workflows/create-test-plan.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 8cae0148d6..6de1bd5205 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -143,9 +143,9 @@ JOB_SPECS = { "netbsd": JobSpec(name="NetBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.NetBSD, artifact="SDL-netbsd-x64", ), "freebsd": JobSpec(name="FreeBSD", os=JobOs.UbuntuLatest, platform=SdlPlatform.FreeBSD, artifact="SDL-freebsd-x64", ), "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), - "harmony-arm64": JobSpec(name="Harmony (Arm64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), - "harmony-arm32": JobSpec(name="Harmony (Arm32)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="armeabi-v7a"), - "harmony-x86_64": JobSpec(name="Harmony (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="x86_64"), + "harmony-arm64": JobSpec(name="Harmony (Arm64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), + "harmony-arm32": JobSpec(name="Harmony (Arm32)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm32", harmony_arch="armeabi-v7a"), + "harmony-x86_64": JobSpec(name="Harmony (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-x86_64", harmony_arch="x86_64"), } From e7fdb9c19d5aa6152bfb246a9a774464681a5e55 Mon Sep 17 00:00:00 2001 From: Jack253-png Date: Sun, 8 Jun 2025 08:19:59 +0800 Subject: [PATCH 57/92] Harmony port: workflow [sdl-ci-filter harmony-*] --- .github/workflows/create-test-plan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index 6de1bd5205..53ca8fa2b2 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -145,7 +145,7 @@ JOB_SPECS = { "ngage": JobSpec(name="N-Gage", os=JobOs.WindowsLatest, platform=SdlPlatform.NGage, artifact="SDL-ngage", ), "harmony-arm64": JobSpec(name="Harmony (Arm64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm64", harmony_arch="arm64-v8a"), "harmony-arm32": JobSpec(name="Harmony (Arm32)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-arm32", harmony_arch="armeabi-v7a"), - "harmony-x86_64": JobSpec(name="Harmony (x86_64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-x86_64", harmony_arch="x86_64"), + "harmony-x86_64": JobSpec(name="Harmony (x86-64)", os=JobOs.UbuntuLatest, platform=SdlPlatform.Harmony, artifact="SDL-harmony-x86_64", harmony_arch="x86_64"), } From 973260a851e12503b5d9fda680278d0076e24363 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 22 Jun 2025 06:10:31 +0800 Subject: [PATCH 58/92] OpenHarmony Port (renderer) --- CMakeLists.txt | 2 ++ src/core/ohos/SDL_ohos.c | 32 ++++---------------------------- src/video/ohos/SDL_ohosvideo.c | 4 +--- 3 files changed, 7 insertions(+), 31 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6133950ebe..f40062aa36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1516,7 +1516,9 @@ elseif(OHOS) set(SDL_VULKAN ON) set(HAVE_VULKAN ON) set(SDL_VIDEO_VULKAN ON) + set(SDL_VIDEO_RENDER_VULKAN 1) set(HAVE_RENDER_VULKAN TRUE) + add_definitions(-DVK_USE_PLATFORM_OHOS=1) if(SDL_OPENGLES) set(SDL_VIDEO_OPENGL_EGL 1) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 528e9b762e..4b1f272bd9 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,5 @@ #include "SDL_internal.h" +#include "dynapi/SDL_dynapi_overrides.h" #include #include #include @@ -140,31 +141,6 @@ int OHOS_FetchHeight() return hei; } -static napi_value minus(napi_env env, napi_callback_info info) -{ - size_t argc = 2; - napi_value args[2] = { NULL }; - - napi_get_cb_info(env, info, &argc, args, NULL, NULL); - - napi_valuetype valuetype0; - napi_typeof(env, args[0], &valuetype0); - - napi_valuetype valuetype1; - napi_typeof(env, args[1], &valuetype1); - - double value0; - napi_get_value_double(env, args[0], &value0); - - double value1; - napi_get_value_double(env, args[1], &value1); - - napi_value sum; - napi_create_double(env, value0 - value1, &sum); - - return sum; -} - static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *data) { napiCallbackData *ar = (napiCallbackData *)data; @@ -248,9 +224,9 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) data->func = "test"; data->argCount = 0; - napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); - SDL_free(data); + // SDL_free(data); napi_value result; napi_create_int32(env, 0, &result); @@ -286,6 +262,7 @@ static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { + SDL_Log("Native window: %p", window); g_ohosNativeWindow = (OHNativeWindow *)window; uint64_t width; @@ -408,7 +385,6 @@ static void onNativeMouse(OH_NativeXComponent *component, void *window) {} static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { - { "minus", NULL, minus, NULL, NULL, NULL, napi_default, NULL }, { "sdlCallbackInit", NULL, sdlCallbackInit, NULL, NULL, NULL, napi_default, NULL }, { "sdlLaunchMain", NULL, sdlLaunchMain, NULL, NULL, NULL, napi_default, NULL } }; diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index f5e721e38a..69e2aac22a 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -16,9 +16,7 @@ bool OHOS_VideoInit(SDL_VideoDevice *_this) mode.h = OHOS_FetchHeight(); mode.refresh_rate = 60; - SDL_DisplayID displayID = SDL_AddBasicVideoDisplay(&mode); - SDL_Log("testvid: %u", displayID); - SDL_Log("testvid: %u", _this->displays[0]->id); + SDL_AddBasicVideoDisplay(&mode); return true; } void OHOS_VideoQuit(SDL_VideoDevice *_this) From 69104d0bccce2bd3068b21c403c5f3999802d805 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 28 Jun 2025 12:21:53 +0800 Subject: [PATCH 59/92] Harmony port: entrypoint multithread --- src/core/ohos/SDL_ohos.c | 62 +++++++++++++++++++++++++++++-------- src/video/SDL_egl.c | 1 + src/video/ohos/SDL_ohosgl.c | 3 +- 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 4b1f272bd9..81d49ade95 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -67,6 +67,8 @@ void OHOS_windowDataFill(SDL_Window *w) w->w = wid; w->h = hei; w->internal->native_window = g_ohosNativeWindow; + + SDL_SetWindowSize(w, wid, hei); SDL_VideoDevice *_this = SDL_GetVideoDevice(); @@ -224,7 +226,7 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) data->func = "test"; data->argCount = 0; - napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); // SDL_free(data); @@ -233,6 +235,26 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) return result; } +typedef struct entrypoint_info_ { + char* libname; + char* func; +} entrypoint_info; +static int sdlLaunchMainInternal(void* reserved) +{ + if (!reserved) { + return -1; + } + entrypoint_info *data = (entrypoint_info*)reserved; + void *lib = dlopen(data->libname, RTLD_LAZY); + void *func = dlsym(lib, data->func); + typedef int (*test)(); + int d = ((test)func)(); + dlclose(lib); + SDL_free(reserved); + + return d; +} + static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) { size_t argc = 2; @@ -248,12 +270,12 @@ static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) napi_get_value_string_utf8(env, args[1], NULL, 0, &fstringSize); char *fname = SDL_malloc(fstringSize + 1); napi_get_value_string_utf8(env, args[1], fname, fstringSize + 1, &fstringSize); - - void *lib = dlopen(libname, RTLD_LAZY); - void *func = dlsym(lib, fname); - typedef int (*test)(); - ((test)func)(); - dlclose(lib); + + entrypoint_info *entry = (entrypoint_info*)SDL_malloc(sizeof(entrypoint_info)); + entry->func = fname; + entry->libname = libname; + SDL_Thread* m = SDL_CreateThread(sdlLaunchMainInternal, "SDL App Thread", entry); + SDL_SetMainReady(); napi_value result; napi_create_int32(env, 0, &result); @@ -278,6 +300,12 @@ static void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) x = (int)offsetX; y = (int)offsetY; SDL_UnlockMutex(g_ohosPageMutex); + + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + data->func = "onMainLaunch"; + data->argCount = 0; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); } static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) { @@ -296,6 +324,13 @@ static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) x = (int)offsetX; y = (int)offsetY; SDL_UnlockMutex(g_ohosPageMutex); + + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + SDL_Window *win = _this->windows; + while (win != NULL) { + OHOS_windowDataFill(win); + win = win->next; + } } static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { @@ -318,6 +353,7 @@ static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) static void onKeyEvent(OH_NativeXComponent *component, void *window) { OH_NativeXComponent_KeyEvent *keyEvent = NULL; + SDL_Log("key!"); if (OH_NativeXComponent_GetKeyEvent(component, &keyEvent) >= 0) { OH_NativeXComponent_KeyAction action; OH_NativeXComponent_KeyCode code; @@ -349,7 +385,8 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) for (int i = 0; i < touchEvent.numPoints; i++) { SDL_OHOSTouchEvent e; e.timestamp = touchEvent.timeStamp; - e.deviceId = touchEvent.deviceId; + // skip assertions + e.deviceId = touchEvent.deviceId + 1; e.fingerId = touchEvent.touchPoints[i].id; e.area = touchEvent.touchPoints[i].size; e.x = touchEvent.touchPoints[i].x / (float)wid; @@ -374,13 +411,13 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) OHOS_OnTouch(e); } + + OHOS_UnlockPage(); } -static void OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window) -{ +// TODO mouse data +static void onNativeMouse(OH_NativeXComponent *component, void *window) { onNativeTouch(component, window); } -// TODO -static void onNativeMouse(OH_NativeXComponent *component, void *window) {} static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { @@ -405,7 +442,6 @@ static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) callback.DispatchTouchEvent = onNativeTouch; OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback); - mouseCallback.DispatchMouseEvent = OnDispatchTouchEventCB; mouseCallback.DispatchMouseEvent = onNativeMouse; OH_NativeXComponent_RegisterMouseEventCallback(nativeXComponent, &mouseCallback); diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index 3d4df26073..fbece4136c 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -19,6 +19,7 @@ * 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_internal.h" +#include "dynapi/SDL_dynapi_overrides.h" #ifdef SDL_VIDEO_OPENGL_EGL diff --git a/src/video/ohos/SDL_ohosgl.c b/src/video/ohos/SDL_ohosgl.c index 38ad6e918a..53e13af30e 100644 --- a/src/video/ohos/SDL_ohosgl.c +++ b/src/video/ohos/SDL_ohosgl.c @@ -17,7 +17,8 @@ SDL_GLContext OHOS_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window SDL_GLContext result; OHOS_LockPage(); - + + OHOS_windowDataFill(window); result = SDL_EGL_CreateContext(_this, window->internal->egl_surface); OHOS_UnlockPage(); From 44497fce0e146c4ff23cdc6bde29079c96765f0a Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 28 Jun 2025 12:25:33 +0800 Subject: [PATCH 60/92] fix --- src/video/SDL_egl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index fbece4136c..3d4df26073 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -19,7 +19,6 @@ * 3. This notice may not be removed or altered from any source distribution. */ #include "SDL_internal.h" -#include "dynapi/SDL_dynapi_overrides.h" #ifdef SDL_VIDEO_OPENGL_EGL From 56e42de8b49bcad3d907c42a04dbed0e960ba18c Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 28 Jun 2025 17:42:46 +0800 Subject: [PATCH 61/92] Harmony port: dialog --- src/core/ohos/SDL_ohos.c | 58 ++++++++++++++++++++++++---------- src/core/ohos/SDL_ohos.h | 2 ++ src/video/ohos/SDL_ohosvideo.c | 13 +++++++- 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 81d49ade95..fcc01fada9 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -42,6 +42,7 @@ typedef enum typedef struct { napiArgType type; + bool enabled; union { int i; @@ -59,16 +60,21 @@ typedef struct napiCallbackArg ret; } napiCallbackData; -void OHOS_windowDataFill(SDL_Window *w) +void OHOS_windowUpdateAttributes(SDL_Window *w) { - w->internal = SDL_calloc(1, sizeof(SDL_WindowData)); w->x = x; w->y = y; w->w = wid; w->h = hei; - w->internal->native_window = g_ohosNativeWindow; SDL_SetWindowSize(w, wid, hei); +} + +void OHOS_windowDataFill(SDL_Window *w) +{ + w->internal = SDL_calloc(1, sizeof(SDL_WindowData)); + OHOS_windowUpdateAttributes(w); + w->internal->native_window = g_ohosNativeWindow; SDL_VideoDevice *_this = SDL_GetVideoDevice(); @@ -153,7 +159,11 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da napi_get_named_property(env, callb, ar->func, &jsMethod); napi_value args[16]; + SDL_Log("[SDL] calling js function %s with %d args", ar->func, ar->argCount); for (int i = 0; i < ar->argCount; i++) { + if (!ar->arg[i].enabled) { + continue; + } switch (ar->arg[i].type) { case Int: { @@ -172,7 +182,12 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da } case String: { - napi_create_string_utf8(env, ar->arg[i].data.str, SDL_strlen(ar->arg[i].data.str), args + i); + const char* p = ar->arg[i].data.str; int l = 0; + while (*p) { + l++; + p++; + } + napi_create_string_utf8(env, ar->arg[i].data.str, l, args + i); break; } } @@ -208,6 +223,22 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da } } +void OHOS_MessageBox(const char* title, const char* message) +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "showDialog"; + data->argCount = 2; + data->arg[0].type = String; + data->arg[0].enabled = true; + data->arg[0].data.str = title; + data->arg[1].type = String; + data->arg[1].enabled = true; + data->arg[1].data.str = message; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); +} + static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) { napiEnv.env = env; @@ -222,14 +253,6 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) napi_create_string_utf8(env, "SDLThreadSafe", NAPI_AUTO_LENGTH, &resName); napi_create_threadsafe_function(env, args[0], NULL, resName, 0, 1, NULL, NULL, NULL, sdlJSCallback, &napiEnv.func); - napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); - data->func = "test"; - data->argCount = 0; - - napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); - - // SDL_free(data); - napi_value result; napi_create_int32(env, 0, &result); return result; @@ -255,6 +278,8 @@ static int sdlLaunchMainInternal(void* reserved) return d; } +static SDL_Thread *mainThread; + static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) { size_t argc = 2; @@ -274,7 +299,7 @@ static napi_value sdlLaunchMain(napi_env env, napi_callback_info info) entrypoint_info *entry = (entrypoint_info*)SDL_malloc(sizeof(entrypoint_info)); entry->func = fname; entry->libname = libname; - SDL_Thread* m = SDL_CreateThread(sdlLaunchMainInternal, "SDL App Thread", entry); + mainThread = SDL_CreateThread(sdlLaunchMainInternal, "SDL App Thread", entry); SDL_SetMainReady(); napi_value result; @@ -326,10 +351,9 @@ static void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) SDL_UnlockMutex(g_ohosPageMutex); SDL_VideoDevice *_this = SDL_GetVideoDevice(); - SDL_Window *win = _this->windows; - while (win != NULL) { - OHOS_windowDataFill(win); - win = win->next; + if (_this && _this->windows) { + SDL_Window *win = _this->windows; + OHOS_windowUpdateAttributes(win); } } static void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 8270b72bc5..6e59b1fcef 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -12,6 +12,8 @@ void OHOS_UnlockPage(); int OHOS_FetchWidth(); int OHOS_FetchHeight(); +void OHOS_MessageBox(const char* title, const char* message); + typedef struct SDL_VideoData { SDL_Rect textRect; int isPaused; diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index 69e2aac22a..fdf676d900 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -70,10 +70,21 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) return device; } +bool OHOS_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID) +{ + int length1 = SDL_strlen(messageboxdata->title) + 1; + char* titlecopy = (char*)SDL_malloc(length1); + SDL_memcpy(titlecopy, messageboxdata->title, length1); + length1 = SDL_strlen(messageboxdata->message) + 1; + char* messagecopy = (char*)SDL_malloc(length1); + SDL_memcpy(messagecopy, messageboxdata->message, length1); + OHOS_MessageBox(titlecopy, messagecopy); + return true; +} VideoBootStrap OHOS_bootstrap = { "ohos", "OpenHarmony video driver", OHOS_CreateDevice, - NULL, + OHOS_ShowMessageBox, false }; #endif From 3e64c9e37b981faa5932c36eed3c898269a8536e Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 28 Jun 2025 18:14:03 +0800 Subject: [PATCH 62/92] Harmony port: locale --- src/core/ohos/SDL_ohos.c | 25 ++++++++++++++++++++++--- src/core/ohos/SDL_ohos.h | 1 + 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index fcc01fada9..ceee68254f 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,5 +1,4 @@ #include "SDL_internal.h" -#include "dynapi/SDL_dynapi_overrides.h" #include #include #include @@ -58,6 +57,7 @@ typedef struct napiCallbackArg arg[16]; napiArgType type; napiCallbackArg ret; + bool returned; } napiCallbackData; void OHOS_windowUpdateAttributes(SDL_Window *w) @@ -209,9 +209,9 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da case String: { size_t stringSize = 0; - napi_get_value_string_utf8(env, args[1], NULL, 0, &stringSize); + napi_get_value_string_utf8(env, v, NULL, 0, &stringSize); char *value = SDL_malloc(stringSize + 1); - napi_get_value_string_utf8(env, args[1], value, stringSize + 1, &stringSize); + napi_get_value_string_utf8(env, v, value, stringSize + 1, &stringSize); ar->ret.data.str = value; break; } @@ -221,6 +221,7 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da break; } } + ar->returned = true; } void OHOS_MessageBox(const char* title, const char* message) @@ -239,6 +240,24 @@ void OHOS_MessageBox(const char* title, const char* message) napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); } +const char* OHOS_Locale() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "fetchLocale"; + data->argCount = 0; + data->type = String; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + const char* d = data->ret.data.str; + SDL_free(data); + return d; +} + static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) { napiEnv.env = env; diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 6e59b1fcef..817f805797 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -13,6 +13,7 @@ int OHOS_FetchWidth(); int OHOS_FetchHeight(); void OHOS_MessageBox(const char* title, const char* message); +const char* OHOS_Locale(); typedef struct SDL_VideoData { SDL_Rect textRect; From bc8a018033ef36dc09d996ccfe9591258ce4da5b Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 28 Jun 2025 18:22:25 +0800 Subject: [PATCH 63/92] Harmony port: ohos project --- ohos-project | 1 + 1 file changed, 1 insertion(+) create mode 160000 ohos-project diff --git a/ohos-project b/ohos-project new file mode 160000 index 0000000000..d48a2eedef --- /dev/null +++ b/ohos-project @@ -0,0 +1 @@ +Subproject commit d48a2eedefe303910a84f74847594fe03f691dad From 3e14b2b4a07b29d6863128b716d783b29b6bb406 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 28 Jun 2025 21:32:29 +0800 Subject: [PATCH 64/92] Harmony port: fix --- CMakeLists.txt | 2 -- ohos-project | 1 - src/video/SDL_video.c | 6 +++--- 3 files changed, 3 insertions(+), 6 deletions(-) delete mode 160000 ohos-project diff --git a/CMakeLists.txt b/CMakeLists.txt index f40062aa36..f34e2370a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1513,12 +1513,10 @@ elseif(OHOS) set(SDL_VIDEO_DRIVER_OHOS 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/ohos/*.c") set(HAVE_SDL_VIDEO TRUE) - set(SDL_VULKAN ON) set(HAVE_VULKAN ON) set(SDL_VIDEO_VULKAN ON) set(SDL_VIDEO_RENDER_VULKAN 1) set(HAVE_RENDER_VULKAN TRUE) - add_definitions(-DVK_USE_PLATFORM_OHOS=1) if(SDL_OPENGLES) set(SDL_VIDEO_OPENGL_EGL 1) diff --git a/ohos-project b/ohos-project deleted file mode 160000 index d48a2eedef..0000000000 --- a/ohos-project +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d48a2eedefe303910a84f74847594fe03f691dad diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 06ce3c8af9..453a600730 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -107,6 +107,9 @@ static VideoBootStrap *bootstrap[] = { #ifdef SDL_VIDEO_DRIVER_ANDROID &Android_bootstrap, #endif +#ifdef SDL_VIDEO_DRIVER_OHOS + &OHOS_bootstrap, +#endif #ifdef SDL_VIDEO_DRIVER_PS2 &PS2_bootstrap, #endif @@ -148,9 +151,6 @@ static VideoBootStrap *bootstrap[] = { #endif #ifdef SDL_VIDEO_DRIVER_OPENVR &OPENVR_bootstrap, -#endif -#ifdef SDL_VIDEO_DRIVER_OHOS - &OHOS_bootstrap, #endif NULL }; From ed283adcaff4378ff0bc5c7bfb08eb24a5a37357 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Thu, 3 Jul 2025 20:16:47 +0800 Subject: [PATCH 65/92] Harmony port: main project --- ohos-project/.gitignore | 12 ++ ohos-project/AppScope/app.json5 | 10 ++ .../resources/base/element/string.json | 8 + .../resources/base/media/background.png | Bin 0 -> 91942 bytes .../resources/base/media/foreground.png | Bin 0 -> 14526 bytes .../resources/base/media/layered_image.json | 7 + .../resources/base/media/oforeground.png | Bin 0 -> 8805 bytes ohos-project/build-profile.json5 | 42 +++++ ohos-project/code-linter.json5 | 32 ++++ ohos-project/entry/.gitignore | 6 + ohos-project/entry/build-profile.json5 | 44 +++++ ohos-project/entry/hvigorfile.ts | 6 + ohos-project/entry/obfuscation-rules.txt | 23 +++ ohos-project/entry/oh-package-lock.json5 | 25 +++ ohos-project/entry/oh-package.json5 | 12 ++ .../entry/src/main/cpp/CMakeLists.txt | 21 +++ ohos-project/entry/src/main/cpp/napi_init.cpp | 167 ++++++++++++++++++ .../entry/src/main/cpp/sdl/Index.d.ts | 2 + .../entry/src/main/cpp/sdl/oh-package.json5 | 6 + .../src/main/cpp/types/libentry/Index.d.ts | 1 + .../main/cpp/types/libentry/oh-package.json5 | 6 + .../main/ets/entryability/EntryAbility.ets | 47 +++++ .../entrybackupability/EntryBackupAbility.ets | 16 ++ .../entry/src/main/ets/pages/Index.ets | 51 ++++++ ohos-project/entry/src/main/module.json5 | 55 ++++++ .../main/resources/base/element/color.json | 8 + .../main/resources/base/element/float.json | 8 + .../main/resources/base/element/string.json | 16 ++ .../main/resources/base/media/background.png | Bin 0 -> 91942 bytes .../main/resources/base/media/foreground.png | Bin 0 -> 8805 bytes .../resources/base/media/layered_image.json | 7 + .../main/resources/base/media/startIcon.png | Bin 0 -> 20093 bytes .../resources/base/profile/backup_config.json | 3 + .../resources/base/profile/main_pages.json | 5 + .../main/resources/dark/element/color.json | 8 + ohos-project/entry/src/mock/Libentry.mock.ets | 7 + ohos-project/entry/src/mock/mock-config.json5 | 5 + .../src/ohosTest/ets/test/Ability.test.ets | 35 ++++ .../entry/src/ohosTest/ets/test/List.test.ets | 5 + ohos-project/entry/src/ohosTest/module.json5 | 13 ++ ohos-project/entry/src/test/List.test.ets | 5 + .../entry/src/test/LocalUnit.test.ets | 33 ++++ ohos-project/hvigor/hvigor-config.json5 | 22 +++ ohos-project/hvigorfile.ts | 6 + ohos-project/oh-package-lock.json5 | 27 +++ ohos-project/oh-package.json5 | 10 ++ 46 files changed, 822 insertions(+) create mode 100644 ohos-project/.gitignore create mode 100644 ohos-project/AppScope/app.json5 create mode 100644 ohos-project/AppScope/resources/base/element/string.json create mode 100644 ohos-project/AppScope/resources/base/media/background.png create mode 100644 ohos-project/AppScope/resources/base/media/foreground.png create mode 100644 ohos-project/AppScope/resources/base/media/layered_image.json create mode 100644 ohos-project/AppScope/resources/base/media/oforeground.png create mode 100644 ohos-project/build-profile.json5 create mode 100644 ohos-project/code-linter.json5 create mode 100644 ohos-project/entry/.gitignore create mode 100644 ohos-project/entry/build-profile.json5 create mode 100644 ohos-project/entry/hvigorfile.ts create mode 100644 ohos-project/entry/obfuscation-rules.txt create mode 100644 ohos-project/entry/oh-package-lock.json5 create mode 100644 ohos-project/entry/oh-package.json5 create mode 100644 ohos-project/entry/src/main/cpp/CMakeLists.txt create mode 100644 ohos-project/entry/src/main/cpp/napi_init.cpp create mode 100644 ohos-project/entry/src/main/cpp/sdl/Index.d.ts create mode 100644 ohos-project/entry/src/main/cpp/sdl/oh-package.json5 create mode 100644 ohos-project/entry/src/main/cpp/types/libentry/Index.d.ts create mode 100644 ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 create mode 100644 ohos-project/entry/src/main/ets/entryability/EntryAbility.ets create mode 100644 ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets create mode 100644 ohos-project/entry/src/main/ets/pages/Index.ets create mode 100644 ohos-project/entry/src/main/module.json5 create mode 100644 ohos-project/entry/src/main/resources/base/element/color.json create mode 100644 ohos-project/entry/src/main/resources/base/element/float.json create mode 100644 ohos-project/entry/src/main/resources/base/element/string.json create mode 100644 ohos-project/entry/src/main/resources/base/media/background.png create mode 100644 ohos-project/entry/src/main/resources/base/media/foreground.png create mode 100644 ohos-project/entry/src/main/resources/base/media/layered_image.json create mode 100644 ohos-project/entry/src/main/resources/base/media/startIcon.png create mode 100644 ohos-project/entry/src/main/resources/base/profile/backup_config.json create mode 100644 ohos-project/entry/src/main/resources/base/profile/main_pages.json create mode 100644 ohos-project/entry/src/main/resources/dark/element/color.json create mode 100644 ohos-project/entry/src/mock/Libentry.mock.ets create mode 100644 ohos-project/entry/src/mock/mock-config.json5 create mode 100644 ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets create mode 100644 ohos-project/entry/src/ohosTest/ets/test/List.test.ets create mode 100644 ohos-project/entry/src/ohosTest/module.json5 create mode 100644 ohos-project/entry/src/test/List.test.ets create mode 100644 ohos-project/entry/src/test/LocalUnit.test.ets create mode 100644 ohos-project/hvigor/hvigor-config.json5 create mode 100644 ohos-project/hvigorfile.ts create mode 100644 ohos-project/oh-package-lock.json5 create mode 100644 ohos-project/oh-package.json5 diff --git a/ohos-project/.gitignore b/ohos-project/.gitignore new file mode 100644 index 0000000000..d2ff20141c --- /dev/null +++ b/ohos-project/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/ohos-project/AppScope/app.json5 b/ohos-project/AppScope/app.json5 new file mode 100644 index 0000000000..2a08169692 --- /dev/null +++ b/ohos-project/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.cpp.app", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ohos-project/AppScope/resources/base/element/string.json b/ohos-project/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000..1080233f01 --- /dev/null +++ b/ohos-project/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "MyApplication" + } + ] +} diff --git a/ohos-project/AppScope/resources/base/media/background.png b/ohos-project/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f GIT binary patch literal 91942 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 +#include +#include +#include +#include + +static napi_value Add(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value args[2] = {nullptr}; + + napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); + + napi_valuetype valuetype0; + napi_typeof(env, args[0], &valuetype0); + + napi_valuetype valuetype1; + napi_typeof(env, args[1], &valuetype1); + + double value0; + napi_get_value_double(env, args[0], &value0); + + double value1; + napi_get_value_double(env, args[1], &value1); + + napi_value sum; + napi_create_double(env, value0 + value1, &sum); + + SDL_Log("Add invoke!"); + + return sum; + +} + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} + +float vtxdata[] = { + -0.5f, -0.5f, 0.f, + 0.5f, -0.5f, 0.0f, + 0.0f, 0.5f, 0.0f +}; + +float vtxdata2[] = { + 0.f, 0.f, 1.f, + 0.f, 1.f, 0.f, + 1.f, 0.f, 0.f +}; + +int main() +{ + SDL_SetHint(SDL_HINT_EGL_LIBRARY, "libEGL.so"); + SDL_SetHint(SDL_HINT_OPENGL_LIBRARY, "libGLESv2.so"); + SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "libGLESv2.so"); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_Init(SDL_INIT_VIDEO); + SDL_Log("Main func invoke !!!"); + // SDL_GL_LoadLibrary("libGLESv2.so"); + SDL_Log("sdl error: %s", SDL_GetError()); + SDL_Window* win = SDL_CreateWindow("test", 1024, 1024, SDL_WINDOW_OPENGL); + + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "SDL Application", "test!", win); + + auto context = SDL_GL_CreateContext(win); + SDL_GL_MakeCurrent(win, context); + + int frgshader = ((PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader"))(GL_FRAGMENT_SHADER); + int vexshader = ((PFNGLCREATESHADERPROC)SDL_GL_GetProcAddress("glCreateShader"))(GL_VERTEX_SHADER); + + auto frag = "varying vec4 v_color;void main() {gl_FragColor = v_color;}"; + ((PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource"))(frgshader, 1, &frag, nullptr); + ((PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader"))(frgshader); + int status = 1; + ((PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"))(frgshader, GL_COMPILE_STATUS, &status); + int status2 = 1; + ((PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"))(frgshader, GL_INFO_LOG_LENGTH, &status2); + std::string log(status2, '\0'); + ((PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog"))(frgshader, status2, nullptr, (char*)log.c_str()); + + SDL_Log("test: %d %d %s", status, status2, log.c_str()); + + auto vert = "attribute vec3 pos;attribute vec3 color;varying vec4 v_color;void main() {gl_Position=vec4(pos,1.0);v_color=vec4(color, 1.0);}"; + ((PFNGLSHADERSOURCEPROC)SDL_GL_GetProcAddress("glShaderSource"))(vexshader, 1, &vert, nullptr); + ((PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader"))(vexshader); + ((PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"))(vexshader, GL_COMPILE_STATUS, &status); + ((PFNGLGETSHADERIVPROC)SDL_GL_GetProcAddress("glGetShaderiv"))(vexshader, GL_INFO_LOG_LENGTH, &status2); + std::string log2(status2, '\0'); + ((PFNGLGETSHADERINFOLOGPROC)SDL_GL_GetProcAddress("glGetShaderInfoLog"))(vexshader, status2, nullptr, (char*)log2.c_str()); + + SDL_Log("test: %d %d %s", status, status2, log2.c_str()); + + auto prog = ((PFNGLCREATEPROGRAMPROC)SDL_GL_GetProcAddress("glCreateProgram"))(); + ((PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader"))(prog, vexshader); + ((PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader"))(prog, frgshader); + ((PFNGLLINKPROGRAMPROC)SDL_GL_GetProcAddress("glLinkProgram"))(prog); + ((PFNGLGETPROGRAMIVPROC)SDL_GL_GetProcAddress("glGetProgramiv"))(prog, GL_LINK_STATUS, &status); + SDL_Log("link: %d", status); + + ((PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"))(vexshader); + ((PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"))(frgshader); + + while (true) { + int w, h; + SDL_GetWindowSize(win, &w, &h); + + ((PFNGLVIEWPORTPROC)SDL_GL_GetProcAddress("glViewport"))(0, 0, w, h); + ((PFNGLCLEARPROC)SDL_GL_GetProcAddress("glClear"))(GL_COLOR_BUFFER_BIT); + ((PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram"))(prog); + for (int i = 0; i < 9; i++) { + vtxdata2[i] += 0.01f; + if (vtxdata2[i] >= 1.f) { + vtxdata2[i] = 0.f; + } + } + ((PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer"))(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)vtxdata); + ((PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray"))(0); + ((PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer"))(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)vtxdata2); + ((PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray"))(1); + + ((PFNGLDRAWARRAYSPROC)SDL_GL_GetProcAddress("glDrawArrays"))(GL_TRIANGLES, 0, 3); + + SDL_GL_SwapWindow(win); + } + + SDL_Log("glversion: %s", ((PFNGLGETSTRINGPROC)SDL_GL_GetProcAddress("glGetString"))(GL_VERSION)); + + SDL_GL_DestroyContext(context); + + SDL_DestroyWindow(win); + + return 0; +} +EXTERN_C_END + +static napi_module demoModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&demoModule); +} diff --git a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts new file mode 100644 index 0000000000..a98f439804 --- /dev/null +++ b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts @@ -0,0 +1,2 @@ +export const sdlCallbackInit: (d) => void; +export const sdlLaunchMain: (lib: string, func: string) => number; diff --git a/ohos-project/entry/src/main/cpp/sdl/oh-package.json5 b/ohos-project/entry/src/main/cpp/sdl/oh-package.json5 new file mode 100644 index 0000000000..3a8ac3e1b5 --- /dev/null +++ b/ohos-project/entry/src/main/cpp/sdl/oh-package.json5 @@ -0,0 +1,6 @@ +{ + "name": "libSDL3.so", + "types": "./Index.d.ts", + "version": "1.0.0", + "description": "Please describe the basic information." +} diff --git a/ohos-project/entry/src/main/cpp/types/libentry/Index.d.ts b/ohos-project/entry/src/main/cpp/types/libentry/Index.d.ts new file mode 100644 index 0000000000..e44f3615a4 --- /dev/null +++ b/ohos-project/entry/src/main/cpp/types/libentry/Index.d.ts @@ -0,0 +1 @@ +export const add: (a: number, b: number) => number; \ No newline at end of file diff --git a/ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 b/ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000..ea410725a8 --- /dev/null +++ b/ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,6 @@ +{ + "name": "libentry.so", + "types": "./Index.d.ts", + "version": "1.0.0", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000..f562838e87 --- /dev/null +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,47 @@ +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import { KeyboardAvoidMode } from '@ohos.arkui.UIContext'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); + windowStage.getMainWindowSync().setWindowLayoutFullScreen(true) + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} diff --git a/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000..8e4de99282 --- /dev/null +++ b/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,16 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000..6942023db0 --- /dev/null +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,51 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import sdltest from 'libSDL3.so'; +import { intl } from '@kit.LocalizationKit'; +import { promptAction } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export class ArkNapiCallback { + onMainLaunch() { + sdltest.sdlLaunchMain("libentry.so", "main") + } + showDialog(title: string, message: string) { + promptAction.showDialog({title: title, message: message, buttons: [{text: 'Ok', color: '#999999'}]}); + } + fetchLocale(): string { + let locale = new intl.Locale(); + return locale.toString(); + } + test(): number { + hilog.info(DOMAIN, 'testTag', 'Call from native !!!'); + focusControl.requestFocus("inputHandler") + let locale = new intl.Locale(); + hilog.info(DOMAIN, 'testTag', locale.toString()); + return 1; + } +} + +let callbackRef: ArkNapiCallback = new ArkNapiCallback() + +@Entry +@Component +struct Index { + aboutToAppear(): void { + sdltest.sdlCallbackInit(callbackRef) + } + + build() { + Column() { + XComponent({ id: 'mainView', type: 'surface', libraryname: 'SDL3' }) + .id('mainView') + TextInput().id('inputHandler').onChange((value: string) => { + hilog.info(DOMAIN, 'testTag', value) + }).onSubmit(() => { + hilog.info(DOMAIN, 'testTag', "submit") + }) + + } + .alignItems(HorizontalAlign.End) + .justifyContent(FlexAlign.End) + } +} diff --git a/ohos-project/entry/src/main/module.json5 b/ohos-project/entry/src/main/module.json5 new file mode 100644 index 0000000000..b4b367580a --- /dev/null +++ b/ohos-project/entry/src/main/module.json5 @@ -0,0 +1,55 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "requestPermissions": [ + ], + + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ] + } +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/resources/base/element/color.json b/ohos-project/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000..3c712962da --- /dev/null +++ b/ohos-project/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/resources/base/element/float.json b/ohos-project/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000..33ea22304f --- /dev/null +++ b/ohos-project/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/ohos-project/entry/src/main/resources/base/element/string.json b/ohos-project/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000..3f04948b12 --- /dev/null +++ b/ohos-project/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "SDL Demo" + } + ] +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/resources/base/media/background.png b/ohos-project/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f GIT binary patch literal 91942 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

c)ijgxDm}8EsRXFt3h@+Ufr7@DN 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 literal 0 HcmV?d00001 diff --git a/ohos-project/entry/src/main/resources/base/profile/backup_config.json b/ohos-project/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000..78f40ae7c4 --- /dev/null +++ b/ohos-project/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/resources/base/profile/main_pages.json b/ohos-project/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000..1898d94f58 --- /dev/null +++ b/ohos-project/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/ohos-project/entry/src/main/resources/dark/element/color.json b/ohos-project/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000..79b11c2747 --- /dev/null +++ b/ohos-project/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/ohos-project/entry/src/mock/Libentry.mock.ets b/ohos-project/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000..c2171716d0 --- /dev/null +++ b/ohos-project/entry/src/mock/Libentry.mock.ets @@ -0,0 +1,7 @@ +const NativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default NativeMock; \ No newline at end of file diff --git a/ohos-project/entry/src/mock/mock-config.json5 b/ohos-project/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000..6540976c9a --- /dev/null +++ b/ohos-project/entry/src/mock/mock-config.json5 @@ -0,0 +1,5 @@ +{ + "libentry.so": { + "source": "src/mock/Libentry.mock.ets" + } +} \ No newline at end of file diff --git a/ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets b/ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000..85c78f6757 --- /dev/null +++ b/ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }) + }) +} \ No newline at end of file diff --git a/ohos-project/entry/src/ohosTest/ets/test/List.test.ets b/ohos-project/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000..794c7dc4ed --- /dev/null +++ b/ohos-project/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/ohos-project/entry/src/ohosTest/module.json5 b/ohos-project/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000..55725a9299 --- /dev/null +++ b/ohos-project/entry/src/ohosTest/module.json5 @@ -0,0 +1,13 @@ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ohos-project/entry/src/test/List.test.ets b/ohos-project/entry/src/test/List.test.ets new file mode 100644 index 0000000000..bb5b5c3731 --- /dev/null +++ b/ohos-project/entry/src/test/List.test.ets @@ -0,0 +1,5 @@ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ohos-project/entry/src/test/LocalUnit.test.ets b/ohos-project/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000..165fc1615e --- /dev/null +++ b/ohos-project/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,33 @@ +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/ohos-project/hvigor/hvigor-config.json5 b/ohos-project/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000..5bebc97554 --- /dev/null +++ b/ohos-project/hvigor/hvigor-config.json5 @@ -0,0 +1,22 @@ +{ + "modelVersion": "5.0.5", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/ohos-project/hvigorfile.ts b/ohos-project/hvigorfile.ts new file mode 100644 index 0000000000..f3cb9f1a87 --- /dev/null +++ b/ohos-project/hvigorfile.ts @@ -0,0 +1,6 @@ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ +} diff --git a/ohos-project/oh-package-lock.json5 b/ohos-project/oh-package-lock.json5 new file mode 100644 index 0000000000..c6f99f5c73 --- /dev/null +++ b/ohos-project/oh-package-lock.json5 @@ -0,0 +1,27 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", + "@ohos/hypium@1.0.21": "@ohos/hypium@1.0.21" + }, + "packages": { + "@ohos/hamock@1.0.0": { + "name": "@ohos/hamock", + "version": "1.0.0", + "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "registryType": "ohpm" + }, + "@ohos/hypium@1.0.21": { + "name": "@ohos/hypium", + "version": "1.0.21", + "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==", + "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.21.har", + "registryType": "ohpm" + } + } +} \ No newline at end of file diff --git a/ohos-project/oh-package.json5 b/ohos-project/oh-package.json5 new file mode 100644 index 0000000000..a8aff0c5af --- /dev/null +++ b/ohos-project/oh-package.json5 @@ -0,0 +1,10 @@ +{ + "modelVersion": "5.0.5", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + } +} From 768c89c05d05338d8e188a3cd2bac6949267940c Mon Sep 17 00:00:00 2001 From: Coder2 Date: Thu, 3 Jul 2025 20:32:45 +0800 Subject: [PATCH 66/92] Harmony port: doc v0 --- docs/README-ohos.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docs/README-ohos.md diff --git a/docs/README-ohos.md b/docs/README-ohos.md new file mode 100644 index 0000000000..5b184300a9 --- /dev/null +++ b/docs/README-ohos.md @@ -0,0 +1,28 @@ +OpenHarmony / HarmonyOS +================================================================================ + +Requirements +================================================================================ + +DevEco Studio 5.0.0 or later +https://developer.huawei.com/consumer/en/download + +Harmony OS Development Toolchain 5.0.0 (API 12) or later (Bundled in the DevEco Studio) + + +How the port works +================================================================================ + +- OpenHarmony / Harmony OS apps are based on ArkTS/JS running on the Ark JS runtime, optionally with parts written in C +- We can use the napi and ndk provided by the Harmony SDK to fetch the app window, context and so on. We wrote a simple Harmony shell for SDL, simpily initialize the basic application and the context for SDL library, then runs your app in another thread. (Harmony JS apps only contains one thread, if we runs your app main loop directly in JS, the whole app just freezes) +- This produces a .hap or .app package which can be installed in OpenHarmony and HarmonyOS Emulators (you will need to apply for a certificate to sign the app before testing it on a real HarmonyOS machine) + + +Building the example app and test it (HarmonyOS Emulator) +================================================================================ + +Download the DevEco Studio, and open the ohos-project folder in this repo + +Then, download a emulator in the Device Manager tab, and runs it. + +Click the run button, the IDE will automatically build the app and run it for you, you can act with your app in the emulator window. From 4d331f4abea7fc2917db92b9642e3d720cf52aae Mon Sep 17 00:00:00 2001 From: Coder2 Date: Mon, 4 Aug 2025 15:34:52 +0800 Subject: [PATCH 67/92] OpenHarmony: locale subsystem --- CMakeLists.txt | 3 +++ src/core/ohos/SDL_ohos.c | 8 ++++++++ src/locale/ohos/SDL_syslocale.c | 11 +++++++++++ 3 files changed, 22 insertions(+) create mode 100644 src/locale/ohos/SDL_syslocale.c diff --git a/CMakeLists.txt b/CMakeLists.txt index efceda6cb0..1585486dc6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1534,6 +1534,9 @@ elseif(OHOS) endif() endif() + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/ohos/*.c") + set(HAVE_SDL_LOCALE TRUE) + set(SDL_LOADSO_DLOPEN 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/loadso/dlopen/*.c") set(HAVE_SDL_LOADSO TRUE) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index ceee68254f..13aa8a5258 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -271,6 +271,14 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) napi_value resName = NULL; napi_create_string_utf8(env, "SDLThreadSafe", NAPI_AUTO_LENGTH, &resName); napi_create_threadsafe_function(env, args[0], NULL, resName, 0, 1, NULL, NULL, NULL, sdlJSCallback, &napiEnv.func); + + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "test"; + data->argCount = 0; + data->type = Int; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); napi_value result; napi_create_int32(env, 0, &result); diff --git a/src/locale/ohos/SDL_syslocale.c b/src/locale/ohos/SDL_syslocale.c new file mode 100644 index 0000000000..49f1270e2b --- /dev/null +++ b/src/locale/ohos/SDL_syslocale.c @@ -0,0 +1,11 @@ +#include "SDL_internal.h" +#include "../SDL_syslocale.h" +#include "../../core/ohos/SDL_ohos.h" + +bool SDL_SYS_GetPreferredLocales(char *buf, size_t buflen) +{ + const char* result = OHOS_Locale(); + SDL_memcpy(buf, result, buflen); + SDL_Log("target %s", buf); + return true; +} From cb58ba5cc3d5c9cb9f20de5ce67fb0011f3b098a Mon Sep 17 00:00:00 2001 From: Coder2 Date: Mon, 4 Aug 2025 15:50:42 +0800 Subject: [PATCH 68/92] OpenHarmony: shell update --- .../resources/base/element/string.json | 4 +++ ohos-project/entry/oh-package-lock.json5 | 3 +- ohos-project/entry/src/main/cpp/napi_init.cpp | 5 +++- .../main/ets/entryability/EntryAbility.ets | 30 +++++++++++++++++-- .../entry/src/main/ets/pages/Index.ets | 13 ++++---- ohos-project/oh-package-lock.json5 | 3 +- 6 files changed, 45 insertions(+), 13 deletions(-) diff --git a/ohos-project/AppScope/resources/base/element/string.json b/ohos-project/AppScope/resources/base/element/string.json index 1080233f01..a1b9d1934d 100644 --- a/ohos-project/AppScope/resources/base/element/string.json +++ b/ohos-project/AppScope/resources/base/element/string.json @@ -3,6 +3,10 @@ { "name": "app_name", "value": "MyApplication" + }, + { + "name": "perm_reason", + "value": "Subsystem for SDL / SDL 子系统" } ] } diff --git a/ohos-project/entry/oh-package-lock.json5 b/ohos-project/entry/oh-package-lock.json5 index ca4ac9f408..caf0346aa3 100644 --- a/ohos-project/entry/oh-package-lock.json5 +++ b/ohos-project/entry/oh-package-lock.json5 @@ -1,6 +1,7 @@ { "meta": { - "stableOrder": true + "stableOrder": true, + "enableUnifiedLockfile": false }, "lockfileVersion": 3, "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index 8730b430e4..6e36ddbf18 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -5,6 +5,7 @@ #include "SDL3/SDL_timer.h" #include "SDL3/SDL_video.h" #include "SDL3/SDL_vulkan.h" +#include "SDL3/SDL_locale.h" #include "napi/native_api.h" #include "SDL3/SDL_log.h" #include "SDL3/SDL_hints.h" @@ -73,7 +74,9 @@ int main() SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SDL_Init(SDL_INIT_VIDEO); - SDL_Log("Main func invoke !!!"); + int i = 0; + auto t = SDL_GetPreferredLocales(&i); + SDL_Log("Main func invoke !!! %s %s", t[0]->country, t[0]->language); // SDL_GL_LoadLibrary("libGLESv2.so"); SDL_Log("sdl error: %s", SDL_GetError()); SDL_Window* win = SDL_CreateWindow("test", 1024, 1024, SDL_WINDOW_OPENGL); diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets index f562838e87..ad296b578a 100644 --- a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -1,10 +1,35 @@ -import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { abilityAccessCtrl, AbilityConstant, + common, + ConfigurationConstant, + Permissions, + UIAbility, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; -import { window } from '@kit.ArkUI'; +import { promptAction, window } from '@kit.ArkUI'; import { KeyboardAvoidMode } from '@ohos.arkui.UIContext'; +import { BusinessError } from '@kit.BasicServicesKit'; const DOMAIN = 0x0000; +const permissions: Array = ['ohos.permission.INPUT_KEYBOARD_CONTROLLER']; +function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void { + let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); + atManager.requestPermissionsFromUser(context, permissions).then((data) => { + let grantStatus: Array = data.authResults; + let length: number = grantStatus.length; + for (let i = 0; i < length; i++) { + if (grantStatus[i] === 0) { + promptAction.showDialog({title: "permissions", message: "granted", buttons: [{text: 'Ok', color: '#999999'}]}); + } else { + promptAction.showDialog({title: "permissions", message: "not granted", buttons: [{text: 'Ok', color: '#999999'}]}); + return; + } + } + // 授权成功 + }).catch((err: BusinessError) => { + console.error(`Failed to request permissions from user. Code is ${err.code}, message is ${err.message}`); + }) +} + export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); @@ -20,6 +45,7 @@ export default class EntryAbility extends UIAbility { hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/Index', (err) => { + reqPermissionsFromUser(permissions, this.context); if (err.code) { hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); return; diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 6942023db0..09c74502d4 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -10,18 +10,15 @@ export class ArkNapiCallback { sdltest.sdlLaunchMain("libentry.so", "main") } showDialog(title: string, message: string) { - promptAction.showDialog({title: title, message: message, buttons: [{text: 'Ok', color: '#999999'}]}); + promptAction.showDialog({title: title, message: message, buttons: [{text: 'Ok', color: '#999999'}]}) } fetchLocale(): string { - let locale = new intl.Locale(); - return locale.toString(); + let locale = new intl.Locale() + return locale.language + "_" + locale.region } test(): number { - hilog.info(DOMAIN, 'testTag', 'Call from native !!!'); - focusControl.requestFocus("inputHandler") - let locale = new intl.Locale(); - hilog.info(DOMAIN, 'testTag', locale.toString()); - return 1; + hilog.info(DOMAIN, 'testTag', 'Call from native !!!') + return 1 } } diff --git a/ohos-project/oh-package-lock.json5 b/ohos-project/oh-package-lock.json5 index c6f99f5c73..a392505690 100644 --- a/ohos-project/oh-package-lock.json5 +++ b/ohos-project/oh-package-lock.json5 @@ -1,6 +1,7 @@ { "meta": { - "stableOrder": true + "stableOrder": true, + "enableUnifiedLockfile": false }, "lockfileVersion": 3, "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", From fcbdd08a0f4d021f1cdf9c214854f19cb5faf699 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 6 Sep 2025 17:04:55 +0800 Subject: [PATCH 69/92] OpenHarmony port: events --- .../entry/src/main/cpp/CMakeLists.txt | 10 +- ohos-project/entry/src/main/cpp/napi_init.cpp | 55 +++++- .../entry/src/main/cpp/sdl/Index.d.ts | 3 + .../main/ets/entryability/EntryAbility.ets | 6 +- .../entry/src/main/ets/pages/Index.ets | 74 +++++++- ohos-project/entry/src/main/module.json5 | 13 ++ src/core/ohos/SDL_ohos.c | 165 +++++++++++++++++- src/core/ohos/SDL_ohos.h | 5 + src/video/ohos/SDL_ohosmouse.c | 11 ++ src/video/ohos/SDL_ohosmouse.h | 15 ++ src/video/ohos/SDL_ohosvideo.c | 42 +++++ 11 files changed, 380 insertions(+), 19 deletions(-) create mode 100644 src/video/ohos/SDL_ohosmouse.c create mode 100644 src/video/ohos/SDL_ohosmouse.h diff --git a/ohos-project/entry/src/main/cpp/CMakeLists.txt b/ohos-project/entry/src/main/cpp/CMakeLists.txt index bc39e8748e..81c36da884 100644 --- a/ohos-project/entry/src/main/cpp/CMakeLists.txt +++ b/ohos-project/entry/src/main/cpp/CMakeLists.txt @@ -8,7 +8,13 @@ if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) endif() -add_subdirectory(../../../../.. external/sdlbin) +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../SDL_port) +add_subdirectory(../../../../../SDL_port external/sdlbin) +else() + message(FATAL_ERROR "没有找到 SDL 主项目,需要将 OpenMinecraft-Dev/SDL clone 到与本项目同位置的文件夹中") +endif() + +# add_subdirectory(../../../../../openal-soft external/openalbin) link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) add_definitions(-DVK_USE_PLATFORM_OHOS=1) @@ -18,4 +24,4 @@ include_directories(${NATIVERENDER_ROOT_PATH} add_library(entry SHARED napi_init.cpp) add_dependencies(entry SDL3::SDL3-shared) -target_link_libraries(entry PUBLIC libace_napi.z.so libSDL3.so libvulkan.so libGLESv2.so) +target_link_libraries(entry PUBLIC libace_napi.z.so libSDL3.so libvulkan.so libGLESv2.so libohaudio.so) diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index 6e36ddbf18..06a31e99ca 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -6,6 +6,7 @@ #include "SDL3/SDL_video.h" #include "SDL3/SDL_vulkan.h" #include "SDL3/SDL_locale.h" +#include "SDL3/SDL_clipboard.h" #include "napi/native_api.h" #include "SDL3/SDL_log.h" #include "SDL3/SDL_hints.h" @@ -14,6 +15,8 @@ #include #include #include +#include +#include static napi_value Add(napi_env env, napi_callback_info info) { @@ -67,6 +70,40 @@ float vtxdata2[] = { int main() { + /*OH_AudioStreamBuilder* builder; + OH_AudioStreamBuilder_Create(&builder, AUDIOSTREAM_TYPE_RENDERER); + + OH_AudioStreamBuilder_SetSamplingRate(builder, 48000); + OH_AudioStreamBuilder_SetChannelCount(builder, 2); + OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_U8); + OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); + OH_AudioStreamBuilder_SetRendererInfo(builder, AUDIOSTREAM_USAGE_MUSIC); + // OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST); + + OH_AudioRenderer_Callbacks callbacks; + + srand(time(nullptr)); + callbacks.OH_AudioRenderer_OnStreamEvent = nullptr; + callbacks.OH_AudioRenderer_OnInterruptEvent = nullptr; + callbacks.OH_AudioRenderer_OnError = nullptr; + callbacks.OH_AudioRenderer_OnWriteData = [](OH_AudioRenderer* renderer, void* userData, void* buffer, int32_t length) { + auto p = (uint8_t *)buffer; + int t = length; + while (t > 0) { + *p = rand() % 255; + p++; + t--; + } + return 0; + }; + + OH_AudioStreamBuilder_SetRendererCallback(builder, callbacks, nullptr); + + OH_AudioRenderer* audioRenderer; + OH_AudioStreamBuilder_GenerateRenderer(builder, &audioRenderer); + OH_AudioRenderer_Start(audioRenderer); + OH_AudioStreamBuilder_Destroy(builder);*/ + SDL_SetHint(SDL_HINT_EGL_LIBRARY, "libEGL.so"); SDL_SetHint(SDL_HINT_OPENGL_LIBRARY, "libGLESv2.so"); SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "libGLESv2.so"); @@ -82,6 +119,8 @@ int main() SDL_Window* win = SDL_CreateWindow("test", 1024, 1024, SDL_WINDOW_OPENGL); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "SDL Application", "test!", win); + SDL_StartTextInput(win); + // SDL_StopTextInput(); auto context = SDL_GL_CreateContext(win); SDL_GL_MakeCurrent(win, context); @@ -129,10 +168,11 @@ int main() ((PFNGLCLEARPROC)SDL_GL_GetProcAddress("glClear"))(GL_COLOR_BUFFER_BIT); ((PFNGLUSEPROGRAMPROC)SDL_GL_GetProcAddress("glUseProgram"))(prog); for (int i = 0; i < 9; i++) { - vtxdata2[i] += 0.01f; + vtxdata2[i] = SDL_randf(); + /*vtxdata2[i] += 0.01f; if (vtxdata2[i] >= 1.f) { vtxdata2[i] = 0.f; - } + }*/ } ((PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer"))(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)vtxdata); ((PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray"))(0); @@ -140,8 +180,17 @@ int main() ((PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray"))(1); ((PFNGLDRAWARRAYSPROC)SDL_GL_GetProcAddress("glDrawArrays"))(GL_TRIANGLES, 0, 3); - + SDL_GL_SwapWindow(win); + + SDL_Event event; + if (SDL_PollEvent(&event)) { + SDL_Log("event type: %d", event.type); + + if (event.type == SDL_EVENT_FINGER_DOWN || event.type == SDL_EVENT_FINGER_UP || event.type == SDL_EVENT_FINGER_MOTION) { + SDL_Log("%f %f", event.tfinger.x, event.tfinger.y); + } + } } SDL_Log("glversion: %s", ((PFNGLGETSTRINGPROC)SDL_GL_GetProcAddress("glGetString"))(GL_VERSION)); diff --git a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts index a98f439804..0cce95d5e2 100644 --- a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts +++ b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts @@ -1,2 +1,5 @@ export const sdlCallbackInit: (d) => void; export const sdlLaunchMain: (lib: string, func: string) => number; +export const sdlKeyEvent: (scancode: number, type: number) => number; +export const sdlTextAppend: (str: string) => number; +export const sdlTextEditing: (str: string, loc: number, length: number) => number; \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets index ad296b578a..ab31a0459a 100644 --- a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -10,7 +10,7 @@ import { BusinessError } from '@kit.BasicServicesKit'; const DOMAIN = 0x0000; -const permissions: Array = ['ohos.permission.INPUT_KEYBOARD_CONTROLLER']; +const permissions: Array = ['ohos.permission.INPUT_KEYBOARD_CONTROLLER', 'ohos.permission.READ_PASTEBOARD']; function reqPermissionsFromUser(permissions: Array, context: common.UIAbilityContext): void { let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(context, permissions).then((data) => { @@ -18,9 +18,9 @@ function reqPermissionsFromUser(permissions: Array, context: common let length: number = grantStatus.length; for (let i = 0; i < length; i++) { if (grantStatus[i] === 0) { - promptAction.showDialog({title: "permissions", message: "granted", buttons: [{text: 'Ok', color: '#999999'}]}); + // promptAction.showDialog({title: "permissions", message: "granted", buttons: [{text: 'Ok', color: '#999999'}]}); } else { - promptAction.showDialog({title: "permissions", message: "not granted", buttons: [{text: 'Ok', color: '#999999'}]}); + // promptAction.showDialog({title: "permissions", message: "not granted", buttons: [{text: 'Ok', color: '#999999'}]}); return; } } diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 09c74502d4..ec04f24838 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -2,9 +2,16 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; import sdltest from 'libSDL3.so'; import { intl } from '@kit.LocalizationKit'; import { promptAction } from '@kit.ArkUI'; +import { inputMethod } from '@kit.IMEKit' +import { Action, Key, KeyEvent } from '@kit.InputKit'; +import { pasteboard, BusinessError } from '@kit.BasicServicesKit'; const DOMAIN = 0x0000; +let controller = inputMethod.getController() +let input = false +let targetText = "" + export class ArkNapiCallback { onMainLaunch() { sdltest.sdlLaunchMain("libentry.so", "main") @@ -20,6 +27,35 @@ export class ArkNapiCallback { hilog.info(DOMAIN, 'testTag', 'Call from native !!!') return 1 } + + setPasteboardString(text: string) { + let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); + let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); + systemPasteboard.setData(pasteData, (err, data) => { + if (err) { + hilog.error(DOMAIN, 'testTag', 'Failed to set PasteData. Cause: ' + err.message); + return; + } + + hilog.info(DOMAIN, 'testTag', 'Succeed in setting PasteData.'); + }); + } + + textEditing(): number { + return input ? 1 : 0; + } + + startTextInput() { + input = true + controller.showTextInput() + hilog.info(DOMAIN, 'testTag', 'text input start') + } + stopTextInput() { + input = false + controller.hideTextInput() + hilog.info(DOMAIN, 'testTag', 'text input stop') + targetText = "" + } } let callbackRef: ArkNapiCallback = new ArkNapiCallback() @@ -27,21 +63,45 @@ let callbackRef: ArkNapiCallback = new ArkNapiCallback() @Entry @Component struct Index { - aboutToAppear(): void { + async aboutToAppear(): Promise { sdltest.sdlCallbackInit(callbackRef) + focusControl.requestFocus('mainView') + await controller.attach(true, { + inputAttribute: { + textInputType: inputMethod.TextInputType.TEXT, + enterKeyType: inputMethod.EnterKeyType.DONE + } + }); + controller.on('insertText', (text) => { + targetText += text; + sdltest.sdlTextAppend(text) + }) + controller.on('deleteLeft', (i) => { + sdltest.sdlTextEditing(targetText, targetText.length - 1 - i, i); + + if (targetText.length > 0) { + targetText = targetText.substring(0, targetText.length - i) + } + hilog.info(DOMAIN, 'testTag', targetText) + }) + controller.on('deleteRight', (i) => { + sdltest.sdlTextEditing(targetText, 0, i); + + if (targetText.length > 0) { + targetText = targetText.substring(i, targetText.length) + } + hilog.info(DOMAIN, 'testTag', targetText) + }) } build() { Column() { XComponent({ id: 'mainView', type: 'surface', libraryname: 'SDL3' }) .id('mainView') - TextInput().id('inputHandler').onChange((value: string) => { - hilog.info(DOMAIN, 'testTag', value) - }).onSubmit(() => { - hilog.info(DOMAIN, 'testTag', "submit") - }) - } + .onKeyEvent((keyevent) => { + sdltest.sdlKeyEvent(keyevent.keyCode, keyevent.type); + }) .alignItems(HorizontalAlign.End) .justifyContent(FlexAlign.End) } diff --git a/ohos-project/entry/src/main/module.json5 b/ohos-project/entry/src/main/module.json5 index b4b367580a..7e44c94de1 100644 --- a/ohos-project/entry/src/main/module.json5 +++ b/ohos-project/entry/src/main/module.json5 @@ -10,6 +10,19 @@ "2in1" ], "requestPermissions": [ + { + "name": "ohos.permission.INPUT_KEYBOARD_CONTROLLER", + "reason": "$string:perm_reason", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when":"inuse" + } + }, + { + "name": "ohos.permission.INTERNET" + } ], "deliveryWithInstall": true, diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 13aa8a5258..041c2062fa 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,6 @@ #include "SDL_internal.h" +#include "events/SDL_keyboard_c.h" +#include "video/ohos/SDL_ohosmouse.h" #include #include #include @@ -224,6 +226,59 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da ar->returned = true; } +void OHOS_SetClipboardText(const char* c) +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "setPasteboardString"; + data->argCount = 1; + data->arg[0].type = String; + data->arg[0].enabled = true; + data->arg[0].data.str = c; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); +} + +bool OHOS_IsScreenKeyboardShown() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "textEditing"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + bool d = data->ret.data.i == 1; + SDL_free(data); + return d; +} +void OHOS_StartTextInput() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "startTextInput"; + data->argCount = 0; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); + while (!data->returned) {} +} +void OHOS_StopTextInput() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "stopTextInput"; + data->argCount = 0; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); + while (!data->returned) {} +} + void OHOS_MessageBox(const char* title, const char* message) { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); @@ -438,7 +493,7 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) e.timestamp = touchEvent.timeStamp; // skip assertions e.deviceId = touchEvent.deviceId + 1; - e.fingerId = touchEvent.touchPoints[i].id; + e.fingerId = touchEvent.touchPoints[i].id + 1; e.area = touchEvent.touchPoints[i].size; e.x = touchEvent.touchPoints[i].x / (float)wid; e.y = touchEvent.touchPoints[i].y / (float)hei; @@ -459,7 +514,7 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) e.type = SDL_EVENT_FINGER_CANCELED; break; } - + OHOS_OnTouch(e); } @@ -467,14 +522,116 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) } // TODO mouse data static void onNativeMouse(OH_NativeXComponent *component, void *window) { - onNativeTouch(component, window); + OH_NativeXComponent_MouseEvent event; + OHOS_LockPage(); + OH_NativeXComponent_GetMouseEvent(component, window, &event); + if (event.button == OH_NATIVEXCOMPONENT_NONE_BUTTON || event.action == OH_NATIVEXCOMPONENT_MOUSE_NONE) { + return; + } + SDL_OHOSMouseEvent e; + e.x = event.x; + e.y = event.y; + e.timestamp = event.timestamp; + switch (event.button) + { + case OH_NATIVEXCOMPONENT_LEFT_BUTTON: + e.button = SDL_BUTTON_LEFT; + break; + case OH_NATIVEXCOMPONENT_RIGHT_BUTTON: + e.button = SDL_BUTTON_RIGHT; + break; + case OH_NATIVEXCOMPONENT_MIDDLE_BUTTON: + e.button = SDL_BUTTON_MIDDLE; + break; + case OH_NATIVEXCOMPONENT_BACK_BUTTON: + e.button = SDL_BUTTON_X1; + break; + case OH_NATIVEXCOMPONENT_FORWARD_BUTTON: + e.button = SDL_BUTTON_X2; + break; + } + + if (event.action == OH_NATIVEXCOMPONENT_MOUSE_MOVE) { + e.motion = true; + } + else { + e.down = event.action == OH_NATIVEXCOMPONENT_MOUSE_PRESS; + } + OHOS_OnMouse(e); + + OHOS_UnlockPage(); +} + +static napi_value sdlKeyEvent(napi_env env, napi_callback_info info) +{ + size_t argc = 2; + napi_value args[2] = { NULL, NULL }; + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + int keycode, type; + napi_get_value_int32(env, args[0], &keycode); + napi_get_value_int32(env, args[1], &type); + + if (type == 0) { + OHOS_OnKeyDown(keycode); + } + else { + OHOS_OnKeyUp(keycode); + } + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlTextAppend(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = { NULL }; + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + size_t fstringSize = 0; + napi_get_value_string_utf8(env, args[0], NULL, 0, &fstringSize); + char *fname = SDL_malloc(fstringSize + 1); + napi_get_value_string_utf8(env, args[0], fname, fstringSize + 1, &fstringSize); + + SDL_SendKeyboardText(fname); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlTextEditing(napi_env env, napi_callback_info info) +{ + size_t argc = 3; + napi_value args[3] = { NULL, NULL, NULL }; + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + size_t fstringSize = 0; + napi_get_value_string_utf8(env, args[0], NULL, 0, &fstringSize); + char *fname = SDL_malloc(fstringSize + 1); + napi_get_value_string_utf8(env, args[0], fname, fstringSize + 1, &fstringSize); + + int start, len; + napi_get_value_int32(env, args[1], &start); + napi_get_value_int32(env, args[2], &len); + + SDL_SendEditingText(fname, start, len); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; } static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { { "sdlCallbackInit", NULL, sdlCallbackInit, NULL, NULL, NULL, napi_default, NULL }, - { "sdlLaunchMain", NULL, sdlLaunchMain, NULL, NULL, NULL, napi_default, NULL } + { "sdlLaunchMain", NULL, sdlLaunchMain, NULL, NULL, NULL, napi_default, NULL }, + { "sdlKeyEvent", NULL, sdlKeyEvent, NULL, NULL, NULL, napi_default, NULL }, + { "sdlTextAppend", NULL, sdlTextAppend, NULL, NULL, NULL, napi_default, NULL }, + { "sdlTextEditing", NULL, sdlTextEditing, NULL, NULL, NULL, napi_default, NULL } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 817f805797..3617181114 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -14,6 +14,11 @@ int OHOS_FetchHeight(); void OHOS_MessageBox(const char* title, const char* message); const char* OHOS_Locale(); +void OHOS_SetClipboardText(const char* data); + +bool OHOS_IsScreenKeyboardShown(); +void OHOS_StartTextInput(); +void OHOS_StopTextInput(); typedef struct SDL_VideoData { SDL_Rect textRect; diff --git a/src/video/ohos/SDL_ohosmouse.c b/src/video/ohos/SDL_ohosmouse.c new file mode 100644 index 0000000000..b2d075d601 --- /dev/null +++ b/src/video/ohos/SDL_ohosmouse.c @@ -0,0 +1,11 @@ +#include "SDL_internal.h" +#include "events/SDL_mouse_c.h" +#include "SDL_ohosmouse.h" + +void OHOS_OnMouse(SDL_OHOSMouseEvent event) +{ + SDL_SendMouseMotion(event.timestamp, NULL, SDL_DEFAULT_MOUSE_ID, false, event.x, event.y); + if (!event.motion) { + SDL_SendMouseButton(event.timestamp, NULL, SDL_DEFAULT_MOUSE_ID, event.button, event.down); + } +} \ No newline at end of file diff --git a/src/video/ohos/SDL_ohosmouse.h b/src/video/ohos/SDL_ohosmouse.h new file mode 100644 index 0000000000..56310e335c --- /dev/null +++ b/src/video/ohos/SDL_ohosmouse.h @@ -0,0 +1,15 @@ +#ifndef SDL_OHOSMOUSE_H +#define SDL_OHOSMOUSE_H + +typedef struct SDL_OHOSMouseEvent { + float x; + float y; + long long timestamp; + int button; + bool motion; + bool down; +} SDL_OHOSMouseEvent; + +void OHOS_OnMouse(SDL_OHOSMouseEvent event); + +#endif diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index fdf676d900..de74fabf93 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -1,5 +1,6 @@ #include "../SDL_sysvideo.h" #include "SDL_internal.h" +#include "dynapi/SDL_dynapi_overrides.h" #ifdef SDL_VIDEO_DRIVER_OHOS #include "../../core/ohos/SDL_ohos.h" @@ -25,6 +26,37 @@ void OHOS_VideoQuit(SDL_VideoDevice *_this) void OHOS_DeviceFree(SDL_VideoDevice *device) { SDL_free(device); +} +bool OHOS_SetClipboardTextImpl(SDL_VideoDevice *, const char *data) +{ + OHOS_SetClipboardText(data); + return true; +} +bool OHOS_HasClipboardText(SDL_VideoDevice *) +{ + return false; +} +bool OHOS_HasScreenKeyboardSupport(SDL_VideoDevice *) +{ + return true; +} +bool OHOS_IsScreenKeyboardShownImpl(SDL_VideoDevice *, SDL_Window *) +{ + return OHOS_IsScreenKeyboardShown(); +} +bool OHOS_StartTextInputImpl(SDL_VideoDevice *, SDL_Window *, SDL_PropertiesID) +{ + OHOS_StartTextInput(); + return true; +} +bool OHOS_StopTextInputImpl(SDL_VideoDevice *, SDL_Window *) +{ + OHOS_StopTextInput(); + return true; +} +void OHOS_PumpEvents(SDL_VideoDevice *) +{ + } static SDL_VideoDevice *OHOS_CreateDevice(void) { @@ -67,6 +99,16 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) device->GL_GetSwapInterval = SDL_EGL_GetSwapInterval; device->GL_DestroyContext = SDL_EGL_DestroyContext; #endif + + device->SetClipboardText = OHOS_SetClipboardTextImpl; + device->HasClipboardText = OHOS_HasClipboardText; + + device->HasScreenKeyboardSupport = OHOS_HasScreenKeyboardSupport; + device->IsScreenKeyboardShown = OHOS_IsScreenKeyboardShownImpl; + device->StartTextInput = OHOS_StartTextInputImpl; + device->StopTextInput = OHOS_StopTextInputImpl; + + device->PumpEvents = OHOS_PumpEvents; return device; } From 94fe9902fa6b90979cc9abac5087e6d85efc0746 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 6 Sep 2025 19:58:52 +0800 Subject: [PATCH 70/92] OpenHarmony port: fix --- ohos-project/entry/src/main/cpp/CMakeLists.txt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ohos-project/entry/src/main/cpp/CMakeLists.txt b/ohos-project/entry/src/main/cpp/CMakeLists.txt index 81c36da884..d8e6543210 100644 --- a/ohos-project/entry/src/main/cpp/CMakeLists.txt +++ b/ohos-project/entry/src/main/cpp/CMakeLists.txt @@ -8,13 +8,7 @@ if(DEFINED PACKAGE_FIND_FILE) include(${PACKAGE_FIND_FILE}) endif() -if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../SDL_port) -add_subdirectory(../../../../../SDL_port external/sdlbin) -else() - message(FATAL_ERROR "没有找到 SDL 主项目,需要将 OpenMinecraft-Dev/SDL clone 到与本项目同位置的文件夹中") -endif() - -# add_subdirectory(../../../../../openal-soft external/openalbin) +add_subdirectory(../../../../.. external/sdlbin) link_directories(${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) add_definitions(-DVK_USE_PLATFORM_OHOS=1) From 9791c6a7dda542ece0c1b6acf6b1c4645c0f8fc8 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Fri, 3 Oct 2025 10:07:25 +0800 Subject: [PATCH 71/92] OpenHarmony: fix --- ohos-project/entry/oh-package-lock.json5 | 4 ++-- ohos-project/oh-package-lock.json5 | 4 ++-- src/core/ohos/SDL_ohos.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ohos-project/entry/oh-package-lock.json5 b/ohos-project/entry/oh-package-lock.json5 index caf0346aa3..400608bee2 100644 --- a/ohos-project/entry/oh-package-lock.json5 +++ b/ohos-project/entry/oh-package-lock.json5 @@ -13,13 +13,13 @@ "libSDL3.so@src/main/cpp/sdl": { "name": "libSDL3.so", "version": "1.0.0", - "resolved": "src/main/cpp/sdl", + "resolved": "", "registryType": "local" }, "libentry.so@src/main/cpp/types/libentry": { "name": "libentry.so", "version": "1.0.0", - "resolved": "src/main/cpp/types/libentry", + "resolved": "", "registryType": "local" } } diff --git a/ohos-project/oh-package-lock.json5 b/ohos-project/oh-package-lock.json5 index a392505690..19f267cb32 100644 --- a/ohos-project/oh-package-lock.json5 +++ b/ohos-project/oh-package-lock.json5 @@ -11,14 +11,14 @@ }, "packages": { "@ohos/hamock@1.0.0": { - "name": "@ohos/hamock", + "name": "", "version": "1.0.0", "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", "registryType": "ohpm" }, "@ohos/hypium@1.0.21": { - "name": "@ohos/hypium", + "name": "", "version": "1.0.21", "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==", "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.21.har", diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 041c2062fa..309d3edd2e 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -135,11 +135,11 @@ void OHOS_removeWindow(SDL_Window *w) void OHOS_LockPage() { - SDL_LockMutex(g_ohosPageMutex); + // SDL_LockMutex(g_ohosPageMutex); } void OHOS_UnlockPage() { - SDL_UnlockMutex(g_ohosPageMutex); + // SDL_UnlockMutex(g_ohosPageMutex); } int OHOS_FetchWidth() From 5bb106ff4e6265750c226e0b5cc83990ae88efc4 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Fri, 3 Oct 2025 10:10:15 +0800 Subject: [PATCH 72/92] OpenHarmony: fix --- src/core/ohos/SDL_ohos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 309d3edd2e..93fcb70f64 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -141,7 +141,6 @@ void OHOS_UnlockPage() { // SDL_UnlockMutex(g_ohosPageMutex); } - int OHOS_FetchWidth() { return wid; From efd94a7dd0f9939fbe284a220907fad06e1aac36 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Thu, 30 Oct 2025 22:30:22 +0800 Subject: [PATCH 73/92] OpenHarmony: test web view --- ohos-project/entry/src/main/cpp/napi_init.cpp | 4 ++ .../main/ets/entryability/EntryAbility.ets | 11 ++++-- .../entry/src/main/ets/pages/Index.ets | 7 ++++ .../src/main/ets/pages/WebPageExternal.ets | 38 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 ohos-project/entry/src/main/ets/pages/WebPageExternal.ets diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index 06a31e99ca..a23473c34f 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -1,6 +1,7 @@ #include "SDL3/SDL_assert.h" #include "SDL3/SDL_init.h" #include "SDL3/SDL_messagebox.h" +#include "SDL3/SDL_misc.h" #include "SDL3/SDL_render.h" #include "SDL3/SDL_timer.h" #include "SDL3/SDL_video.h" @@ -118,6 +119,8 @@ int main() SDL_Log("sdl error: %s", SDL_GetError()); SDL_Window* win = SDL_CreateWindow("test", 1024, 1024, SDL_WINDOW_OPENGL); + SDL_OpenURL("https://bilibili.com"); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "SDL Application", "test!", win); SDL_StartTextInput(win); // SDL_StopTextInput(); @@ -159,6 +162,7 @@ int main() ((PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"))(vexshader); ((PFNGLDELETESHADERPROC)SDL_GL_GetProcAddress("glDeleteShader"))(frgshader); + ((PFNGLCLEARCOLORPROC)SDL_GL_GetProcAddress("glClearColor"))(0, 0, 0, 0); while (true) { int w, h; diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets index ab31a0459a..9d888e8d17 100644 --- a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -40,10 +40,17 @@ export default class EntryAbility extends UIAbility { hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); } - onWindowStageCreate(windowStage: window.WindowStage): void { + async onWindowStageCreate(windowStage: window.WindowStage): Promise { // Main window is created, set main page for this ability hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + windowStage.getMainWindow().then(async (win) => { + win.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); + win.setWindowLayoutFullScreen(true) + win.setPreferredOrientation(window.Orientation.UNSPECIFIED) + win.setResizeByDragEnabled(true) + }) + windowStage.loadContent('pages/Index', (err) => { reqPermissionsFromUser(permissions, this.context); if (err.code) { @@ -51,8 +58,6 @@ export default class EntryAbility extends UIAbility { return; } hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); - windowStage.getMainWindowSync().getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); - windowStage.getMainWindowSync().setWindowLayoutFullScreen(true) }); } diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index ec04f24838..2d1bc14c32 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -5,6 +5,8 @@ import { promptAction } from '@kit.ArkUI'; import { inputMethod } from '@kit.IMEKit' import { Action, Key, KeyEvent } from '@kit.InputKit'; import { pasteboard, BusinessError } from '@kit.BasicServicesKit'; +import { webview } from '@kit.ArkWeb'; +import WebPageExternal from './WebPageExternal'; const DOMAIN = 0x0000; @@ -64,6 +66,11 @@ let callbackRef: ArkNapiCallback = new ArkNapiCallback() @Component struct Index { async aboutToAppear(): Promise { + let dlg = new CustomDialogController({ + builder: WebPageExternal({onClose: () => { dlg.close() }, url: "https://cn.bing.com"}) + }) + dlg.open() + sdltest.sdlCallbackInit(callbackRef) focusControl.requestFocus('mainView') await controller.attach(true, { diff --git a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets new file mode 100644 index 0000000000..160a449a20 --- /dev/null +++ b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets @@ -0,0 +1,38 @@ +import webview from "@ohos.web.webview"; + +@CustomDialog +export default struct WebPageExternal { + controller: CustomDialogController + webcontroller: webview.WebviewController = new webview.WebviewController(); + onClose: () => void = () => {} + url: string = "" + + build() { + Column() { + Web({ + src: this.url, + controller: this.webcontroller + }) + .height('90%') + Flex({ direction: FlexDirection.Row }) { + Button("Close").onClick((event: ClickEvent) => { + this.onClose() + }) + .width(100) + .height(20) + Button("Refresh").onClick((event: ClickEvent) => { + this.webcontroller.refresh() + }) + .width(100) + .height(20) + Button("Stop").onClick((event: ClickEvent) => { + this.webcontroller.stop() + }) + .width(100) + .height(20) + } + } + .justifyContent(FlexAlign.Center) + .alignItems(HorizontalAlign.Start) + } +} \ No newline at end of file From ecad5241ca69df63bfe943d25d0c691182887192 Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+Jack253-png@users.noreply.github.com> Date: Fri, 31 Oct 2025 05:55:25 +0800 Subject: [PATCH 74/92] Update SDL_ohosvideo.c --- src/video/ohos/SDL_ohosvideo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index de74fabf93..b6426a6dc4 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -104,7 +104,6 @@ static SDL_VideoDevice *OHOS_CreateDevice(void) device->HasClipboardText = OHOS_HasClipboardText; device->HasScreenKeyboardSupport = OHOS_HasScreenKeyboardSupport; - device->IsScreenKeyboardShown = OHOS_IsScreenKeyboardShownImpl; device->StartTextInput = OHOS_StartTextInputImpl; device->StopTextInput = OHOS_StopTextInputImpl; From 89540d980a5ef9d71df0a04981a78fa3cda10243 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Fri, 31 Oct 2025 19:44:35 +0800 Subject: [PATCH 75/92] OpenHarmony: test --- ohos-project/build-profile.json5 | 4 ++-- ohos-project/entry/src/main/cpp/napi_init.cpp | 4 ++++ .../main/ets/entryability/EntryAbility.ets | 22 +++++++++++++------ .../entry/src/main/ets/pages/Index.ets | 2 -- .../src/main/ets/pages/WebPageExternal.ets | 10 ++++----- ohos-project/entry/src/main/module.json5 | 7 +++++- ohos-project/hvigor/hvigor-config.json5 | 4 ++-- ohos-project/oh-package-lock.json5 | 10 ++++----- ohos-project/oh-package.json5 | 6 ++--- 9 files changed, 42 insertions(+), 27 deletions(-) diff --git a/ohos-project/build-profile.json5 b/ohos-project/build-profile.json5 index 0d9f5b24aa..7b6bcdee0a 100644 --- a/ohos-project/build-profile.json5 +++ b/ohos-project/build-profile.json5 @@ -5,8 +5,8 @@ { "name": "default", "signingConfig": "default", - "targetSdkVersion": "5.0.1(13)", - "compatibleSdkVersion": "5.0.1(13)", + "targetSdkVersion": "6.0.0(20)", + "compatibleSdkVersion": "5.0.2(14)", "runtimeOS": "HarmonyOS", "buildOption": { "strictMode": { diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index a23473c34f..b457697dfe 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -194,6 +194,10 @@ int main() if (event.type == SDL_EVENT_FINGER_DOWN || event.type == SDL_EVENT_FINGER_UP || event.type == SDL_EVENT_FINGER_MOTION) { SDL_Log("%f %f", event.tfinger.x, event.tfinger.y); } + + if (event.type == SDL_EVENT_QUIT) { + break; + } } } diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets index 9d888e8d17..d944faaa4d 100644 --- a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -7,6 +7,7 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; import { promptAction, window } from '@kit.ArkUI'; import { KeyboardAvoidMode } from '@ohos.arkui.UIContext'; import { BusinessError } from '@kit.BasicServicesKit'; +import bundleManager from '@ohos.bundle.bundleManager'; const DOMAIN = 0x0000; @@ -44,15 +45,22 @@ export default class EntryAbility extends UIAbility { // Main window is created, set main page for this ability hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); - windowStage.getMainWindow().then(async (win) => { - win.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET); - win.setWindowLayoutFullScreen(true) - win.setPreferredOrientation(window.Orientation.UNSPECIFIED) - win.setResizeByDragEnabled(true) - }) - windowStage.loadContent('pages/Index', (err) => { reqPermissionsFromUser(permissions, this.context); + + windowStage.getMainWindow().then(async (win) => { + try { + win.setWindowTitleButtonVisible(true, true, true) + win.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET) + // win.setWindowLayoutFullScreen(true) + // win.setPreferredOrientation(window.Orientation.FOLLOW_DESKTOP) + win.setResizeByDragEnabled(true) + } catch (error) { + let ll: BusinessError = error; + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(ll)); + } + }) + if (err.code) { hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); return; diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 2d1bc14c32..625705b2c4 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -109,7 +109,5 @@ struct Index { .onKeyEvent((keyevent) => { sdltest.sdlKeyEvent(keyevent.keyCode, keyevent.type); }) - .alignItems(HorizontalAlign.End) - .justifyContent(FlexAlign.End) } } diff --git a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets index 160a449a20..97384e0d87 100644 --- a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets +++ b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets @@ -9,11 +9,6 @@ export default struct WebPageExternal { build() { Column() { - Web({ - src: this.url, - controller: this.webcontroller - }) - .height('90%') Flex({ direction: FlexDirection.Row }) { Button("Close").onClick((event: ClickEvent) => { this.onClose() @@ -31,6 +26,11 @@ export default struct WebPageExternal { .width(100) .height(20) } + Web({ + src: this.url, + controller: this.webcontroller + }) + .height('90%') } .justifyContent(FlexAlign.Center) .alignItems(HorizontalAlign.Start) diff --git a/ohos-project/entry/src/main/module.json5 b/ohos-project/entry/src/main/module.json5 index 7e44c94de1..3d0d898350 100644 --- a/ohos-project/entry/src/main/module.json5 +++ b/ohos-project/entry/src/main/module.json5 @@ -22,6 +22,9 @@ }, { "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.SYSTEM_FLOAT_WINDOW" } ], @@ -37,14 +40,16 @@ "label": "$string:EntryAbility_label", "startWindowIcon": "$media:startIcon", "startWindowBackground": "$color:start_window_background", + "orientation": "landscape", "exported": true, + "supportWindowMode": ["floating", "fullscreen", "split"], "skills": [ { "entities": [ "entity.system.home" ], "actions": [ - "action.system.home" + "ohos.want.action.home" ] } ] diff --git a/ohos-project/hvigor/hvigor-config.json5 b/ohos-project/hvigor/hvigor-config.json5 index 5bebc97554..58a9aa9da1 100644 --- a/ohos-project/hvigor/hvigor-config.json5 +++ b/ohos-project/hvigor/hvigor-config.json5 @@ -1,5 +1,5 @@ { - "modelVersion": "5.0.5", + "modelVersion": "6.0.0", "dependencies": { }, "execution": { @@ -19,4 +19,4 @@ // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ } -} +} \ No newline at end of file diff --git a/ohos-project/oh-package-lock.json5 b/ohos-project/oh-package-lock.json5 index 19f267cb32..a3c0b60cab 100644 --- a/ohos-project/oh-package-lock.json5 +++ b/ohos-project/oh-package-lock.json5 @@ -7,7 +7,7 @@ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", "specifiers": { "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", - "@ohos/hypium@1.0.21": "@ohos/hypium@1.0.21" + "@ohos/hypium@1.0.24": "@ohos/hypium@1.0.24" }, "packages": { "@ohos/hamock@1.0.0": { @@ -17,11 +17,11 @@ "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", "registryType": "ohpm" }, - "@ohos/hypium@1.0.21": { + "@ohos/hypium@1.0.24": { "name": "", - "version": "1.0.21", - "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==", - "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hypium/-/hypium-1.0.21.har", + "version": "1.0.24", + "integrity": "sha512-3dCqc+BAR5LqEGG2Vtzi8O3r7ci/3fYU+FWjwvUobbfko7DUnXGOccaror0yYuUhJfXzFK0aZNMGSnXaTwEnbw==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.24.har", "registryType": "ohpm" } } diff --git a/ohos-project/oh-package.json5 b/ohos-project/oh-package.json5 index a8aff0c5af..374f820f3a 100644 --- a/ohos-project/oh-package.json5 +++ b/ohos-project/oh-package.json5 @@ -1,10 +1,10 @@ { - "modelVersion": "5.0.5", + "modelVersion": "6.0.0", "description": "Please describe the basic information.", "dependencies": { }, "devDependencies": { - "@ohos/hypium": "1.0.21", + "@ohos/hypium": "1.0.24", "@ohos/hamock": "1.0.0" } -} +} \ No newline at end of file From 41256bcb30a89d7cb478b00c9c7bc8ae91ad262b Mon Sep 17 00:00:00 2001 From: Coder2 Date: Fri, 31 Oct 2025 21:01:53 +0800 Subject: [PATCH 76/92] OpenHarmony: misc api --- CMakeLists.txt | 5 +++++ .../entry/src/main/ets/pages/Index.ets | 18 ++++++++++++------ .../src/main/ets/pages/WebPageExternal.ets | 8 ++++++-- src/core/ohos/SDL_ohos.c | 13 +++++++++++++ src/core/ohos/SDL_ohos.h | 1 + src/misc/ohos/SDL_sysurl.c | 10 ++++++++++ 6 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 src/misc/ohos/SDL_sysurl.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 61927056e2..7c7fb62dc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1658,6 +1658,11 @@ elseif(OHOS) endif() endif() + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/misc/ohos/*.c" + ) + set(HAVE_SDL_MISC TRUE) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/ohos/*.c") set(HAVE_SDL_LOCALE TRUE) diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 625705b2c4..b46649bcd6 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -6,13 +6,18 @@ import { inputMethod } from '@kit.IMEKit' import { Action, Key, KeyEvent } from '@kit.InputKit'; import { pasteboard, BusinessError } from '@kit.BasicServicesKit'; import { webview } from '@kit.ArkWeb'; -import WebPageExternal from './WebPageExternal'; +import WebPageExternal, { updateURL } from './WebPageExternal'; +import { common } from '@kit.AbilityKit'; const DOMAIN = 0x0000; let controller = inputMethod.getController() let input = false let targetText = "" +let dlg = new CustomDialogController({ + builder: WebPageExternal({onClose: () => { dlg.close() }}) +}) +let context: UIContext export class ArkNapiCallback { onMainLaunch() { @@ -30,6 +35,11 @@ export class ArkNapiCallback { return 1 } + openLink(url: string) { + let con = context.getHostContext() as common.UIAbilityContext + con.openLink(url) + } + setPasteboardString(text: string) { let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); @@ -66,11 +76,7 @@ let callbackRef: ArkNapiCallback = new ArkNapiCallback() @Component struct Index { async aboutToAppear(): Promise { - let dlg = new CustomDialogController({ - builder: WebPageExternal({onClose: () => { dlg.close() }, url: "https://cn.bing.com"}) - }) - dlg.open() - + context = this.getUIContext() sdltest.sdlCallbackInit(callbackRef) focusControl.requestFocus('mainView') await controller.attach(true, { diff --git a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets index 97384e0d87..d53bdfdfd8 100644 --- a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets +++ b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets @@ -1,11 +1,15 @@ import webview from "@ohos.web.webview"; +let pageURL = "" +export function updateURL(url: string) +{ + pageURL = url; +} @CustomDialog export default struct WebPageExternal { controller: CustomDialogController webcontroller: webview.WebviewController = new webview.WebviewController(); onClose: () => void = () => {} - url: string = "" build() { Column() { @@ -27,7 +31,7 @@ export default struct WebPageExternal { .height(20) } Web({ - src: this.url, + src: pageURL, controller: this.webcontroller }) .height('90%') diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 93fcb70f64..4ff71460e3 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -294,6 +294,19 @@ void OHOS_MessageBox(const char* title, const char* message) napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); } +void OHOS_OpenLink(const char* url) +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "openLink"; + data->argCount = 1; + data->arg[0].type = String; + data->arg[0].enabled = true; + data->arg[0].data.str = url; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); +} + const char* OHOS_Locale() { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 3617181114..e05b9b067b 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -14,6 +14,7 @@ int OHOS_FetchHeight(); void OHOS_MessageBox(const char* title, const char* message); const char* OHOS_Locale(); +void OHOS_OpenLink(const char* url); void OHOS_SetClipboardText(const char* data); bool OHOS_IsScreenKeyboardShown(); diff --git a/src/misc/ohos/SDL_sysurl.c b/src/misc/ohos/SDL_sysurl.c new file mode 100644 index 0000000000..f2f65c744b --- /dev/null +++ b/src/misc/ohos/SDL_sysurl.c @@ -0,0 +1,10 @@ +#include "SDL_internal.h" +#include "../../core/ohos/SDL_ohos.h" + +#include "../SDL_sysurl.h" + +bool SDL_SYS_OpenURL(const char *url) +{ + OHOS_OpenLink(url); + return true; +} From a48cde983fa0683322d2c97e1d1e0baf8046ce21 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Fri, 31 Oct 2025 21:16:24 +0800 Subject: [PATCH 77/92] OpenHarmony: battery API --- CMakeLists.txt | 9 +++ include/build_config/SDL_build_config.h.cmake | 1 + .../entry/src/main/ets/pages/Index.ets | 22 ++++-- .../src/main/ets/pages/WebPageExternal.ets | 42 ----------- src/core/ohos/SDL_ohos.c | 72 +++++++++++++++++++ src/core/ohos/SDL_ohos.h | 4 ++ src/power/SDL_power.c | 3 + src/power/SDL_syspower.h | 1 + src/power/ohos/SDL_syspower.c | 46 ++++++++++++ 9 files changed, 151 insertions(+), 49 deletions(-) delete mode 100644 ohos-project/entry/src/main/ets/pages/WebPageExternal.ets create mode 100644 src/power/ohos/SDL_syspower.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c7fb62dc4..11f5eecaef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1663,6 +1663,15 @@ elseif(OHOS) ) set(HAVE_SDL_MISC TRUE) + if(SDL_POWER) + set(SDL_POWER_OHOS 1) + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/power/ohos/*.c" + "${SDL3_SOURCE_DIR}/src/power/ohos/*.h" + ) + set(HAVE_SDL_POWER TRUE) + endif() + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/ohos/*.c") set(HAVE_SDL_LOCALE TRUE) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 054b0531c1..343be2ec55 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -491,6 +491,7 @@ /* Enable system power support */ #cmakedefine SDL_POWER_ANDROID 1 +#cmakedefine SDL_POWER_OHOS 1 #cmakedefine SDL_POWER_LINUX 1 #cmakedefine SDL_POWER_WINDOWS 1 #cmakedefine SDL_POWER_MACOSX 1 diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index b46649bcd6..d89a4ba684 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -3,20 +3,15 @@ import sdltest from 'libSDL3.so'; import { intl } from '@kit.LocalizationKit'; import { promptAction } from '@kit.ArkUI'; import { inputMethod } from '@kit.IMEKit' -import { Action, Key, KeyEvent } from '@kit.InputKit'; -import { pasteboard, BusinessError } from '@kit.BasicServicesKit'; -import { webview } from '@kit.ArkWeb'; -import WebPageExternal, { updateURL } from './WebPageExternal'; +import { pasteboard } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit'; +import { batteryInfo } from '@kit.BasicServicesKit'; const DOMAIN = 0x0000; let controller = inputMethod.getController() let input = false let targetText = "" -let dlg = new CustomDialogController({ - builder: WebPageExternal({onClose: () => { dlg.close() }}) -}) let context: UIContext export class ArkNapiCallback { @@ -40,6 +35,19 @@ export class ArkNapiCallback { con.openLink(url) } + hasBattery(): boolean { + return batteryInfo.isBatteryPresent + } + batteryCharging(): boolean { + return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.ENABLE + } + batteryCharged(): boolean { + return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.FULL + } + batteryPercent(): number { + return batteryInfo.batterySOC + } + setPasteboardString(text: string) { let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); diff --git a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets b/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets deleted file mode 100644 index d53bdfdfd8..0000000000 --- a/ohos-project/entry/src/main/ets/pages/WebPageExternal.ets +++ /dev/null @@ -1,42 +0,0 @@ -import webview from "@ohos.web.webview"; - -let pageURL = "" -export function updateURL(url: string) -{ - pageURL = url; -} -@CustomDialog -export default struct WebPageExternal { - controller: CustomDialogController - webcontroller: webview.WebviewController = new webview.WebviewController(); - onClose: () => void = () => {} - - build() { - Column() { - Flex({ direction: FlexDirection.Row }) { - Button("Close").onClick((event: ClickEvent) => { - this.onClose() - }) - .width(100) - .height(20) - Button("Refresh").onClick((event: ClickEvent) => { - this.webcontroller.refresh() - }) - .width(100) - .height(20) - Button("Stop").onClick((event: ClickEvent) => { - this.webcontroller.stop() - }) - .width(100) - .height(20) - } - Web({ - src: pageURL, - controller: this.webcontroller - }) - .height('90%') - } - .justifyContent(FlexAlign.Center) - .alignItems(HorizontalAlign.Start) - } -} \ No newline at end of file diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 4ff71460e3..e743bc9ff9 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -255,6 +255,78 @@ bool OHOS_IsScreenKeyboardShown() SDL_free(data); return d; } + +bool OHOS_IsBatteryPresent() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "hasBattery"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + bool d = data->ret.data.i == 1; + SDL_free(data); + return d; +} + +bool OHOS_IsBatteryCharging() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "batteryCharging"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + bool d = data->ret.data.i == 1; + SDL_free(data); + return d; +} + +bool OHOS_IsBatteryCharged() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "batteryCharged"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + bool d = data->ret.data.i == 1; + SDL_free(data); + return d; +} + +int OHOS_GetBatteryPercent() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "batteryPercent"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + int d = data->ret.data.i; + SDL_free(data); + return d; +} void OHOS_StartTextInput() { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index e05b9b067b..2a7908c636 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -15,6 +15,10 @@ int OHOS_FetchHeight(); void OHOS_MessageBox(const char* title, const char* message); const char* OHOS_Locale(); void OHOS_OpenLink(const char* url); +bool OHOS_IsBatteryPresent(); +bool OHOS_IsBatteryCharging(); +bool OHOS_IsBatteryCharged(); +int OHOS_GetBatteryPercent(); void OHOS_SetClipboardText(const char* data); bool OHOS_IsScreenKeyboardShown(); diff --git a/src/power/SDL_power.c b/src/power/SDL_power.c index 3d91c9a931..2eee69f541 100644 --- a/src/power/SDL_power.c +++ b/src/power/SDL_power.c @@ -74,6 +74,9 @@ static SDL_GetPowerInfo_Impl implementations[] = { #ifdef SDL_POWER_EMSCRIPTEN // handles Emscripten SDL_GetPowerInfo_Emscripten, #endif +#ifdef SDL_POWER_OHOS + SDL_GetPowerInfo_OHOS +#endif #ifdef SDL_POWER_HARDWIRED SDL_GetPowerInfo_Hardwired, diff --git a/src/power/SDL_syspower.h b/src/power/SDL_syspower.h index 5f8fa533e6..59df4d5a4a 100644 --- a/src/power/SDL_syspower.h +++ b/src/power/SDL_syspower.h @@ -35,6 +35,7 @@ bool SDL_GetPowerInfo_UIKit(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_MacOSX(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_Haiku(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_Android(SDL_PowerState *, int *, int *); +bool SDL_GetPowerInfo_OHOS(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_PSP(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_VITA(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_N3DS(SDL_PowerState *, int *, int *); diff --git a/src/power/ohos/SDL_syspower.c b/src/power/ohos/SDL_syspower.c new file mode 100644 index 0000000000..1a995de3e3 --- /dev/null +++ b/src/power/ohos/SDL_syspower.c @@ -0,0 +1,46 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifndef SDL_POWER_DISABLED +#ifdef SDL_POWER_OHOS + +#include "../SDL_syspower.h" + +#include "../../core/ohos/SDL_ohos.h" + +bool SDL_GetPowerInfo_OHOS(SDL_PowerState *state, int *seconds, int *percent) +{ + if (!OHOS_IsBatteryPresent()) { + *state = SDL_POWERSTATE_NO_BATTERY; + return true; + } + else { + *seconds = -1; + *percent = OHOS_GetBatteryPercent(); + + *state = OHOS_IsBatteryCharging() ? SDL_POWERSTATE_CHARGING : (OHOS_IsBatteryCharged() ? SDL_POWERSTATE_CHARGED : SDL_POWERSTATE_ON_BATTERY); + } + return true; +} + +#endif // SDL_POWER_OHOS +#endif // SDL_POWER_DISABLED From 9f5452fe86d4d64471d05699d166207bf3582915 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 1 Nov 2025 20:48:38 +0800 Subject: [PATCH 78/92] OpenHarmony: file selection --- ohos-project/entry/src/main/cpp/napi_init.cpp | 5 +- .../entry/src/main/cpp/sdl/Index.d.ts | 5 +- .../entry/src/main/ets/pages/Index.ets | 78 +++++++++++++++++-- ohos-project/entry/src/main/module.json5 | 3 - 4 files changed, 79 insertions(+), 12 deletions(-) diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index b457697dfe..f8f796a60b 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -11,6 +11,8 @@ #include "napi/native_api.h" #include "SDL3/SDL_log.h" #include "SDL3/SDL_hints.h" +#include "SDL3/SDL_power.h" +#include "SDL3/SDL_dialog.h" #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include static napi_value Add(napi_env env, napi_callback_info info) { @@ -119,8 +122,6 @@ int main() SDL_Log("sdl error: %s", SDL_GetError()); SDL_Window* win = SDL_CreateWindow("test", 1024, 1024, SDL_WINDOW_OPENGL); - SDL_OpenURL("https://bilibili.com"); - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "SDL Application", "test!", win); SDL_StartTextInput(win); // SDL_StopTextInput(); diff --git a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts index 0cce95d5e2..66ecc3f030 100644 --- a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts +++ b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts @@ -2,4 +2,7 @@ export const sdlCallbackInit: (d) => void; export const sdlLaunchMain: (lib: string, func: string) => number; export const sdlKeyEvent: (scancode: number, type: number) => number; export const sdlTextAppend: (str: string) => number; -export const sdlTextEditing: (str: string, loc: number, length: number) => number; \ No newline at end of file +export const sdlTextEditing: (str: string, loc: number, length: number) => number; +export const sdlDialogExecCallback: () => void; +export const sdlDialogClearSelection: () => void; +export const sdlDialogFileSelected: (path: string) => void; \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index d89a4ba684..1cb4bc9e08 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -7,6 +7,10 @@ import { pasteboard } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit'; import { batteryInfo } from '@kit.BasicServicesKit'; +import { picker } from '@kit.CoreFileKit'; +import { fileIo as fs } from '@kit.CoreFileKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + const DOMAIN = 0x0000; let controller = inputMethod.getController() @@ -35,14 +39,14 @@ export class ArkNapiCallback { con.openLink(url) } - hasBattery(): boolean { - return batteryInfo.isBatteryPresent + hasBattery(): number { + return batteryInfo.isBatteryPresent ? 1 : 0 } - batteryCharging(): boolean { - return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.ENABLE + batteryCharging(): number { + return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.ENABLE ? 1 : 0 } - batteryCharged(): boolean { - return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.FULL + batteryCharged(): number { + return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.FULL ? 1 : 0 } batteryPercent(): number { return batteryInfo.batterySOC @@ -76,6 +80,67 @@ export class ArkNapiCallback { hilog.info(DOMAIN, 'testTag', 'text input stop') targetText = "" } + + openFileDialog(id: number, defpath: string, itemcount: number, filter: string) { + const documentSelectOptions = new picker.DocumentSelectOptions(); + documentSelectOptions.maxSelectNumber = itemcount; + documentSelectOptions.defaultFilePathUri = defpath; + + if (id == 0 || id == 1) + { + documentSelectOptions.selectMode = picker.DocumentSelectMode.FILE; + } + if (id == 2) + { + documentSelectOptions.selectMode = picker.DocumentSelectMode.FOLDER; + } + + let targetfilter: string[] = [] + let temp = filter.split('\u0002') + for (let index = 0; index < temp.length; index++) { + const element = temp[index]; + + let temp2 = element.split("|") + + // broken filter! + if (temp2.length == 1) + { + targetfilter.push(element + "|.*") + } + else + { + let targettemp = temp2[0] + "|"; + + let temp3 = temp2[1].split(";") + for (let index1 = 0; index1 < temp3.length; index1++) { + targettemp += "." + temp3[index1] + ","; + } + targetfilter.push(targettemp) + } + } + + documentSelectOptions.fileSuffixFilters = targetfilter; + documentSelectOptions.authMode = false; + documentSelectOptions.mergeMode = picker.MergeTypeMode.DEFAULT; + documentSelectOptions.isEncryptionSupported = false; + + let uris: string[] = []; + let contextt = context.getHostContext() as common.UIAbilityContext; + const documentViewPicker = new picker.DocumentViewPicker(contextt); + documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array) => { + uris = documentSelectResult; + sdltest.sdlDialogClearSelection() + for (let idx = 0; idx < uris.length; idx++) + { + let target = uris[idx].replace("file://docs", "") + sdltest.sdlDialogFileSelected(target) + console.info('documentViewPicker.select to file succeed and uris are: ' + target); + } + sdltest.sdlDialogExecCallback() + }).catch((err: BusinessError) => { + console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`); + }) + } } let callbackRef: ArkNapiCallback = new ArkNapiCallback() @@ -85,6 +150,7 @@ let callbackRef: ArkNapiCallback = new ArkNapiCallback() struct Index { async aboutToAppear(): Promise { context = this.getUIContext() + sdltest.sdlCallbackInit(callbackRef) focusControl.requestFocus('mainView') await controller.attach(true, { diff --git a/ohos-project/entry/src/main/module.json5 b/ohos-project/entry/src/main/module.json5 index 3d0d898350..8b2db800bc 100644 --- a/ohos-project/entry/src/main/module.json5 +++ b/ohos-project/entry/src/main/module.json5 @@ -22,9 +22,6 @@ }, { "name": "ohos.permission.INTERNET" - }, - { - "name": "ohos.permission.SYSTEM_FLOAT_WINDOW" } ], From 38aedfd9a7c742f2b5f2ed4929cfc7ae91d05f08 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sat, 1 Nov 2025 22:03:39 +0800 Subject: [PATCH 79/92] OpenHarmony: dialog api finish --- ohos-project/entry/src/main/cpp/sdl/Index.d.ts | 3 ++- ohos-project/entry/src/main/ets/pages/Index.ets | 15 +++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts index 66ecc3f030..e74d54db8d 100644 --- a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts +++ b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts @@ -5,4 +5,5 @@ export const sdlTextAppend: (str: string) => number; export const sdlTextEditing: (str: string, loc: number, length: number) => number; export const sdlDialogExecCallback: () => void; export const sdlDialogClearSelection: () => void; -export const sdlDialogFileSelected: (path: string) => void; \ No newline at end of file +export const sdlDialogFileSelected: (path: string) => void; +export const sdlSendDialogStatus: (idx: number) => void; \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 1cb4bc9e08..a0230c8ef8 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -1,14 +1,13 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; import sdltest from 'libSDL3.so'; import { intl } from '@kit.LocalizationKit'; -import { promptAction } from '@kit.ArkUI'; +import { promptAction, ShowDialogSuccessResponse } from '@kit.ArkUI'; import { inputMethod } from '@kit.IMEKit' import { pasteboard } from '@kit.BasicServicesKit'; import { common } from '@kit.AbilityKit'; import { batteryInfo } from '@kit.BasicServicesKit'; import { picker } from '@kit.CoreFileKit'; -import { fileIo as fs } from '@kit.CoreFileKit'; import { BusinessError } from '@kit.BasicServicesKit'; const DOMAIN = 0x0000; @@ -22,8 +21,16 @@ export class ArkNapiCallback { onMainLaunch() { sdltest.sdlLaunchMain("libentry.so", "main") } - showDialog(title: string, message: string) { - promptAction.showDialog({title: title, message: message, buttons: [{text: 'Ok', color: '#999999'}]}) + + showDialog(title: string, message: string, indexMapping: number[], names: string[]) { + let target: promptAction.Button[] = [] + for (let i = 0; i < names.length; i++) + { + target.push({ text: names[i], color: '#999999' }) + } + promptAction.showDialog({ title: title, message: message, buttons: target }).then((a) => { + sdltest.sdlSendDialogStatus(indexMapping[a.index]) + }) } fetchLocale(): string { let locale = new intl.Locale() From 07b6761d58d8b1aaa5c907d8715ee33dd588eca9 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 2 Nov 2025 18:25:56 +0800 Subject: [PATCH 80/92] OpenHarmony: sensors --- ohos-project/entry/src/main/cpp/CMakeLists.txt | 2 +- ohos-project/entry/src/main/cpp/napi_init.cpp | 3 ++- ohos-project/entry/src/main/ets/pages/Index.ets | 5 +++++ ohos-project/entry/src/main/module.json5 | 6 ++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ohos-project/entry/src/main/cpp/CMakeLists.txt b/ohos-project/entry/src/main/cpp/CMakeLists.txt index d8e6543210..b3e379e17c 100644 --- a/ohos-project/entry/src/main/cpp/CMakeLists.txt +++ b/ohos-project/entry/src/main/cpp/CMakeLists.txt @@ -18,4 +18,4 @@ include_directories(${NATIVERENDER_ROOT_PATH} add_library(entry SHARED napi_init.cpp) add_dependencies(entry SDL3::SDL3-shared) -target_link_libraries(entry PUBLIC libace_napi.z.so libSDL3.so libvulkan.so libGLESv2.so libohaudio.so) +target_link_libraries(entry PUBLIC libace_napi.z.so libSDL3.so libvulkan.so libGLESv2.so libohaudio.so libohsensor.so) diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index f8f796a60b..4fb9228843 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -13,6 +13,7 @@ #include "SDL3/SDL_hints.h" #include "SDL3/SDL_power.h" #include "SDL3/SDL_dialog.h" +#include "SDL3/SDL_sensor.h" #include #include #include @@ -114,7 +115,7 @@ int main() SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_Init(SDL_INIT_VIDEO); + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_SENSOR); int i = 0; auto t = SDL_GetPreferredLocales(&i); SDL_Log("Main func invoke !!! %s %s", t[0]->country, t[0]->language); diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index a0230c8ef8..8ae12d6b5b 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -148,6 +148,11 @@ export class ArkNapiCallback { console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`); }) } + + getInternalPath(): string { + let contextt = context.getHostContext() as common.UIAbilityContext + return contextt.filesDir + } } let callbackRef: ArkNapiCallback = new ArkNapiCallback() diff --git a/ohos-project/entry/src/main/module.json5 b/ohos-project/entry/src/main/module.json5 index 8b2db800bc..679de172c8 100644 --- a/ohos-project/entry/src/main/module.json5 +++ b/ohos-project/entry/src/main/module.json5 @@ -22,6 +22,12 @@ }, { "name": "ohos.permission.INTERNET" + }, + { + "name": "ohos.permission.ACCELEROMETER" + }, + { + "name": "ohos.permission.GYROSCOPE" } ], From c617fcbb958dc2746195790484626da751a7f92f Mon Sep 17 00:00:00 2001 From: Coder2 Date: Tue, 9 Dec 2025 20:08:54 +0800 Subject: [PATCH 81/92] OpenHarmony: dialog / sensor / filesystem subsystem --- CMakeLists.txt | 20 +- include/build_config/SDL_build_config.h.cmake | 2 + ohos-project/entry/src/main/cpp/napi_init.cpp | 2 +- src/core/ohos/SDL_ohos.c | 168 ++++++++++++- src/core/ohos/SDL_ohos.h | 5 +- src/dialog/ohos/SDL_ohosdialog.c | 92 +++++++ src/filesystem/ohos/SDL_sysfilesystem.c | 58 +++++ src/sensor/SDL_sensor.c | 3 + src/sensor/SDL_syssensor.h | 1 + src/sensor/ohos/SDL_ohossensor.c | 226 ++++++++++++++++++ src/video/ohos/SDL_ohosvideo.c | 12 +- 11 files changed, 575 insertions(+), 14 deletions(-) create mode 100644 src/dialog/ohos/SDL_ohosdialog.c create mode 100644 src/filesystem/ohos/SDL_sysfilesystem.c create mode 100644 src/sensor/ohos/SDL_ohossensor.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 11f5eecaef..30d1a47657 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1636,7 +1636,7 @@ elseif(OHOS) # disable warnings from the toolchain sdl_compile_options(PRIVATE "-Wno-unused-command-line-argument") - sdl_link_dependency(ohos LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z) + sdl_link_dependency(ohos LIBS ace_napi.z hilog_ndk.z ace_ndk.z rawfile.z pixelmap_ndk.z ohsensor) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ohos/*.c") if(SDL_VIDEO) @@ -1687,6 +1687,21 @@ elseif(OHOS) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c") set(HAVE_SDL_TIMERS TRUE) + set(SDL_FILESYSTEM_OHOS 1) + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/filesystem/ohos/*.c" + "${SDL3_SOURCE_DIR}/src/filesystem/ohos/*.h" + ) + set(HAVE_SDL_FILESYSTEM TRUE) + if(SDL_SENSOR) + set(SDL_SENSOR_OHOS 1) + sdl_glob_sources( + "${SDL3_SOURCE_DIR}/src/sensor/ohos/*.c" + "${SDL3_SOURCE_DIR}/src/sensor/ohos/*.h" + ) + set(HAVE_SDL_SENSOR TRUE) + endif() + set(SDL_PTHREADS 1) CheckPTHREAD() @@ -3456,6 +3471,9 @@ if (SDL_DIALOG) if(ANDROID) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/android/SDL_androiddialog.c) set(HAVE_SDL_DIALOG TRUE) + elseif (OHOS) + sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/ohos/SDL_ohosdialog.c) + set(HAVE_SDL_DIALOG TRUE) elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_unixdialog.c) sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/unix/SDL_portaldialog.c) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 343be2ec55..bafb979da2 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -340,6 +340,7 @@ /* Enable various sensor drivers */ #cmakedefine SDL_SENSOR_ANDROID 1 +#cmakedefine SDL_SENSOR_OHOS 1 #cmakedefine SDL_SENSOR_COREMOTION 1 #cmakedefine SDL_SENSOR_WINDOWS 1 #cmakedefine SDL_SENSOR_DUMMY 1 @@ -507,6 +508,7 @@ /* Enable system filesystem support */ #cmakedefine SDL_FILESYSTEM_ANDROID 1 +#cmakedefine SDL_FILESYSTEM_OHOS 1 #cmakedefine SDL_FILESYSTEM_HAIKU 1 #cmakedefine SDL_FILESYSTEM_COCOA 1 #cmakedefine SDL_FILESYSTEM_DUMMY 1 diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/napi_init.cpp index 4fb9228843..d764002add 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/napi_init.cpp @@ -194,7 +194,7 @@ int main() SDL_Log("event type: %d", event.type); if (event.type == SDL_EVENT_FINGER_DOWN || event.type == SDL_EVENT_FINGER_UP || event.type == SDL_EVENT_FINGER_MOTION) { - SDL_Log("%f %f", event.tfinger.x, event.tfinger.y); + SDL_Log("finger %f %f", event.tfinger.x, event.tfinger.y); } if (event.type == SDL_EVENT_QUIT) { diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index e743bc9ff9..5c8ab566ab 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -37,7 +37,9 @@ typedef enum Int, Long, Double, - String + String, + IntArray, + StringArray } napiArgType; typedef struct @@ -50,6 +52,16 @@ typedef struct long long l; double d; const char *str; + + struct { + int *ia; + int ial; + }; + + struct { + const char * const *sa; + int sal; + }; } data; } napiCallbackArg; typedef struct @@ -183,12 +195,28 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da } case String: { - const char* p = ar->arg[i].data.str; int l = 0; - while (*p) { - l++; - p++; + const char* p = ar->arg[i].data.str; + napi_create_string_utf8(env, ar->arg[i].data.str, SDL_strlen(p), args + i); + break; + } + case IntArray: + { + napi_create_array_with_length(env, ar->arg[i].data.ial, args + i); + for (int ii = 0; ii < ar->arg[i].data.ial; ii++) { + napi_value itt; + napi_create_int32(env, ar->arg[i].data.ia[ii], &itt); + napi_set_element(env, *(args + i), ii, itt); + } + break; + } + case StringArray: + { + napi_create_array_with_length(env, ar->arg[i].data.sal, args + i); + for (int ii = 0; ii < ar->arg[i].data.sal; ii++) { + napi_value itt; + napi_create_string_utf8(env, ar->arg[i].data.sa[ii], SDL_strlen(ar->arg[i].data.sa[ii]), &itt); + napi_set_element(env, *(args + i), ii, itt); } - napi_create_string_utf8(env, ar->arg[i].data.str, l, args + i); break; } } @@ -225,6 +253,32 @@ static void sdlJSCallback(napi_env env, napi_value jsCb, void *content, void *da ar->returned = true; } +void OHOS_FileDialog(int id, const char* defpath, int allowmany, const char* filter) +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "openFileDialog"; + data->argCount = 4; + data->arg[0].type = Int; + data->arg[0].enabled = true; + data->arg[0].data.i = id; + data->arg[1].type = String; + data->arg[1].enabled = true; + data->arg[1].data.str = defpath; + data->arg[2].type = Int; + data->arg[2].enabled = true; + data->arg[2].data.i = allowmany; + data->arg[3].type = String; + data->arg[3].enabled = true; + data->arg[3].data.str = filter; + + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); + while (!data->returned) {} + SDL_free((void *)filter); +} + void OHOS_SetClipboardText(const char* c) { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); @@ -350,20 +404,38 @@ void OHOS_StopTextInput() while (!data->returned) {} } -void OHOS_MessageBox(const char* title, const char* message) +static bool dialogBoxFinished = false; +static int dialogBoxChoice = -1; + +int OHOS_MessageBox(const char* title, const char* message, int ml, int* mapping, int bl, const char * const *buttons) { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); SDL_memset(data, 0, sizeof(napiCallbackData)); data->func = "showDialog"; - data->argCount = 2; + data->argCount = 4; data->arg[0].type = String; data->arg[0].enabled = true; data->arg[0].data.str = title; data->arg[1].type = String; data->arg[1].enabled = true; data->arg[1].data.str = message; + data->arg[2].type = IntArray; + data->arg[2].enabled = true; + data->arg[2].data.ia = mapping; + data->arg[2].data.ial = ml; + data->arg[3].type = StringArray; + data->arg[3].enabled = true; + data->arg[3].data.sa = buttons; + data->arg[3].data.sal = bl; + + data->type = Int; - napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); + while (!data->returned) {} + SDL_free(data); + while (!dialogBoxFinished) {} + dialogBoxFinished = false; + return dialogBoxChoice; } void OHOS_OpenLink(const char* url) @@ -397,6 +469,24 @@ const char* OHOS_Locale() return d; } +char* OHOS_GetStoragePath() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "getInternalPath"; + data->argCount = 0; + data->type = String; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + const char* d = data->ret.data.str; + SDL_free(data); + return (char *)d; +} + static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) { napiEnv.env = env; @@ -708,6 +798,60 @@ static napi_value sdlTextEditing(napi_env env, napi_callback_info info) return result; } +void SDL_OHOS_FileSelected(const char* data); +void SDL_OHOS_ClearSelection(); +void SDL_OHOS_ExecCallback(); + +static napi_value sdlDialogClearSelection(napi_env env, napi_callback_info info) +{ + SDL_OHOS_ClearSelection(); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlDialogExecCallback(napi_env env, napi_callback_info info) +{ + SDL_OHOS_ExecCallback(); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlDialogFileSelected(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = { NULL }; + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + size_t stringSize = 0; + napi_get_value_string_utf8(env, args[0], NULL, 0, &stringSize); + char *value = (char *)SDL_malloc(stringSize + 1); + napi_get_value_string_utf8(env, args[0], value, stringSize + 1, &stringSize); + + SDL_OHOS_FileSelected(value); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlSendDialogStatus(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = { NULL }; + napi_get_cb_info(env, info, &argc, args, NULL, NULL); + + napi_get_value_int32(env, args[0], &dialogBoxChoice); + dialogBoxFinished = true; + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { @@ -715,7 +859,11 @@ static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { "sdlLaunchMain", NULL, sdlLaunchMain, NULL, NULL, NULL, napi_default, NULL }, { "sdlKeyEvent", NULL, sdlKeyEvent, NULL, NULL, NULL, napi_default, NULL }, { "sdlTextAppend", NULL, sdlTextAppend, NULL, NULL, NULL, napi_default, NULL }, - { "sdlTextEditing", NULL, sdlTextEditing, NULL, NULL, NULL, napi_default, NULL } + { "sdlTextEditing", NULL, sdlTextEditing, NULL, NULL, NULL, napi_default, NULL }, + { "sdlDialogClearSelection", NULL, sdlDialogClearSelection, NULL, NULL, NULL, napi_default, NULL }, + { "sdlDialogExecCallback", NULL, sdlDialogExecCallback, NULL, NULL, NULL, napi_default, NULL }, + { "sdlDialogFileSelected", NULL, sdlDialogFileSelected, NULL, NULL, NULL, napi_default, NULL }, + { "sdlSendDialogStatus", NULL, sdlSendDialogStatus, NULL, NULL, NULL, napi_default, NULL } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index 2a7908c636..b00ff16e38 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -12,7 +12,7 @@ void OHOS_UnlockPage(); int OHOS_FetchWidth(); int OHOS_FetchHeight(); -void OHOS_MessageBox(const char* title, const char* message); +int OHOS_MessageBox(const char* title, const char* message, int ml, int* mapping, int bl, const char * const *buttons); const char* OHOS_Locale(); void OHOS_OpenLink(const char* url); bool OHOS_IsBatteryPresent(); @@ -20,6 +20,9 @@ bool OHOS_IsBatteryCharging(); bool OHOS_IsBatteryCharged(); int OHOS_GetBatteryPercent(); void OHOS_SetClipboardText(const char* data); +char* OHOS_GetStoragePath(); + +void OHOS_FileDialog(int id, const char* defpath, int allowmany, const char* filter); bool OHOS_IsScreenKeyboardShown(); void OHOS_StartTextInput(); diff --git a/src/dialog/ohos/SDL_ohosdialog.c b/src/dialog/ohos/SDL_ohosdialog.c new file mode 100644 index 0000000000..ec6d00c818 --- /dev/null +++ b/src/dialog/ohos/SDL_ohosdialog.c @@ -0,0 +1,92 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#include "../SDL_dialog.h" +#include "../../core/ohos/SDL_ohos.h" + +#define MAX_FILENUM 256 +static SDL_DialogFileCallback current = NULL; +static void* userdatad = NULL; +static const char* paths[MAX_FILENUM]; +static int idxCurrent = 0; + +void SDL_OHOS_FileSelected(const char* data) +{ + if (idxCurrent >= MAX_FILENUM) { + return; + } + paths[idxCurrent] = data; + idxCurrent++; +} + +void SDL_OHOS_ClearSelection() +{ + for (int i = 0; i < MAX_FILENUM; i++) { + paths[i] = NULL; + } + idxCurrent = 0; +} + +void SDL_OHOS_ExecCallback() +{ + if (current) { + current(userdatad, (const char * const *)paths, 0); + } +} + +void SDL_SYS_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props) +{ + current = callback; + userdatad = userdata; + const char* defpath = SDL_GetStringProperty(props, SDL_PROP_FILE_DIALOG_LOCATION_STRING, ""); + bool allowmany = SDL_GetBooleanProperty(props, SDL_PROP_FILE_DIALOG_MANY_BOOLEAN, false); + + void* rawfilters = SDL_GetPointerProperty(props, SDL_PROP_FILE_DIALOG_FILTERS_POINTER, NULL); + int filterscount = SDL_GetNumberProperty(props, SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER, 0); + + char* filterstring = (char*)SDL_malloc(1024); + + if (rawfilters && filterscount > 0) { + SDL_DialogFileFilter *data = (SDL_DialogFileFilter*)rawfilters; + char *begin = filterstring; + for (int idx = 0; idx < filterscount; idx++) + { + SDL_DialogFileFilter filter = data[idx]; + + if (begin - filterstring + SDL_strlen(filter.name) >= 1024) break; + SDL_memcpy(begin, filter.name, SDL_strlen(filter.name)); + begin += SDL_strlen(filter.name); + if (begin - filterstring + 1 >= 1024) break; + *begin = '|'; + begin++; + if (begin - filterstring + SDL_strlen(filter.pattern) >= 1024) break; + SDL_memcpy(begin, filter.pattern, SDL_strlen(filter.pattern)); + begin += SDL_strlen(filter.pattern); + + if (begin - filterstring + 1 >= 1024) break; + *begin = (char)0x2; + begin++; + } + } + + OHOS_FileDialog(type, defpath, allowmany ? MAX_FILENUM : 1, filterstring); +} diff --git a/src/filesystem/ohos/SDL_sysfilesystem.c b/src/filesystem/ohos/SDL_sysfilesystem.c new file mode 100644 index 0000000000..b75aa8314e --- /dev/null +++ b/src/filesystem/ohos/SDL_sysfilesystem.c @@ -0,0 +1,58 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#if defined(SDL_FILESYSTEM_OHOS) + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +// System dependent filesystem routines + +#include "../SDL_sysfilesystem.h" +#include "../../core/ohos/SDL_ohos.h" + +char *SDL_SYS_GetBasePath(void) +{ + SDL_Unsupported(); + return NULL; +} + +char *SDL_SYS_GetPrefPath(const char *org, const char *app) +{ + return OHOS_GetStoragePath(); +} + +char *SDL_SYS_GetUserFolder(SDL_Folder folder) +{ + SDL_Unsupported(); + return NULL; +} + +char *SDL_SYS_GetCurrentDirectory(void) +{ + const char *base = SDL_GetBasePath(); + if (!base) { + return NULL; + } + + return SDL_strdup(base); +} + +#endif // SDL_FILESYSTEM_OHOS diff --git a/src/sensor/SDL_sensor.c b/src/sensor/SDL_sensor.c index f829c92a58..e8abf07c70 100644 --- a/src/sensor/SDL_sensor.c +++ b/src/sensor/SDL_sensor.c @@ -46,6 +46,9 @@ static SDL_SensorDriver *SDL_sensor_drivers[] = { #ifdef SDL_SENSOR_EMSCRIPTEN &SDL_EMSCRIPTEN_SensorDriver, #endif +#ifdef SDL_SENSOR_OHOS + &SDL_OHOS_SensorDriver, +#endif #if defined(SDL_SENSOR_DUMMY) || defined(SDL_SENSOR_DISABLED) &SDL_DUMMY_SensorDriver #endif diff --git a/src/sensor/SDL_syssensor.h b/src/sensor/SDL_syssensor.h index a1a360ae08..bf2cb75099 100644 --- a/src/sensor/SDL_syssensor.h +++ b/src/sensor/SDL_syssensor.h @@ -107,5 +107,6 @@ extern SDL_SensorDriver SDL_DUMMY_SensorDriver; extern SDL_SensorDriver SDL_VITA_SensorDriver; extern SDL_SensorDriver SDL_N3DS_SensorDriver; extern SDL_SensorDriver SDL_EMSCRIPTEN_SensorDriver; +extern SDL_SensorDriver SDL_OHOS_SensorDriver; #endif // SDL_syssensor_h_ diff --git a/src/sensor/ohos/SDL_ohossensor.c b/src/sensor/ohos/SDL_ohossensor.c new file mode 100644 index 0000000000..12fe3dfb54 --- /dev/null +++ b/src/sensor/ohos/SDL_ohossensor.c @@ -0,0 +1,226 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_SENSOR_OHOS + +#include "../SDL_syssensor.h" +#include "sensors/oh_sensor.h" +#include "sensors/oh_sensor_type.h" + +typedef struct { + Sensor_Info *info; + Sensor_Subscriber *subs; + Sensor_SubscriptionId *subid; + Sensor_SubscriptionAttribute *subattr; + SDL_Sensor *sensor; + SDL_SensorID id; +} OHSensorMapping; + +static uint32_t sensorCount; +static OHSensorMapping *mapping; + +static bool SDL_OHOS_SensorInit(void) +{ + Sensor_Info **infobase; + uint32_t s; + if (OH_Sensor_GetInfos(NULL, &s) != SENSOR_SUCCESS) { + return false; + } + sensorCount = s; + + infobase = OH_Sensor_CreateInfos(s); + mapping = (OHSensorMapping *)SDL_calloc(sizeof(OHSensorMapping), s); + + if (OH_Sensor_GetInfos(infobase, &s) != SENSOR_SUCCESS) { + return false; + } + + for (int i = 0; i < s; i++) + { + mapping[i].sensor = NULL; + mapping[i].info = infobase[i]; + mapping[i].id = SDL_GetNextObjectID(); + } + + return true; +} + +static int SDL_OHOS_SensorGetCount(void) +{ + return sensorCount; +} + +static void SDL_OHOS_SensorDetect(void) +{ +} + +static const char *SDL_OHOS_SensorGetDeviceName(int device_index) +{ + char *data; + uint32_t length; + OH_SensorInfo_GetName(mapping[device_index].info, NULL, &length); + data = (char*)SDL_malloc(length); + OH_SensorInfo_GetName(mapping[device_index].info, data, &length); + + return data; +} + +static SDL_SensorType SDL_OHOS_SensorGetDeviceType(int device_index) +{ + Sensor_Type type; + if (OH_SensorInfo_GetType(mapping[device_index].info, &type) != SENSOR_SUCCESS) { + return SDL_SENSOR_INVALID; + } + switch (type) { + case SENSOR_TYPE_ACCELEROMETER: + return SDL_SENSOR_ACCEL; + case SENSOR_TYPE_GYROSCOPE: + return SDL_SENSOR_GYRO; + default: + return SDL_SENSOR_UNKNOWN; + } +} + +static int SDL_OHOS_SensorGetDeviceNonPortableType(int device_index) +{ + Sensor_Type type; + if (OH_SensorInfo_GetType(mapping[device_index].info, &type) != SENSOR_SUCCESS) { + return -1; + } + return type; +} + +static SDL_SensorID SDL_OHOS_SensorGetDeviceInstanceID(int device_index) +{ + return mapping[device_index].id; +} + +static void SDL_OHOS_EventSub(Sensor_Event *event) +{ + Sensor_Type type; + if (OH_SensorEvent_GetType(event, &type) != SENSOR_SUCCESS) { + return; + } + int64_t timestamp; + if (OH_SensorEvent_GetTimestamp(event, ×tamp) != SENSOR_SUCCESS) { + return; + } + + for (int i = 0; i < sensorCount; i++) { + if (mapping[i].sensor && SDL_OHOS_SensorGetDeviceNonPortableType(i) == type) { + uint32_t length; + if (OH_SensorEvent_GetData(event, NULL, &length) != SENSOR_SUCCESS) { + return; + } + float *data = (float *)SDL_malloc(sizeof(float) * length); + if (OH_SensorEvent_GetData(event, &data, &length) != SENSOR_SUCCESS) { + return; + } + SDL_SendSensorUpdate(timestamp, mapping[i].sensor, timestamp, data, length); + SDL_free(data); + break; + } + } +} + +static bool SDL_OHOS_SensorOpen(SDL_Sensor *sensor, int device_index) +{ + if (device_index >= sensorCount) { + return false; + } + mapping[device_index].sensor = sensor; + + mapping[device_index].subs = OH_Sensor_CreateSubscriber(); + if (OH_SensorSubscriber_SetCallback(mapping[device_index].subs, SDL_OHOS_EventSub) != SENSOR_SUCCESS) { + return false; + } + + mapping[device_index].subid = OH_Sensor_CreateSubscriptionId(); + if (OH_SensorSubscriptionId_SetType(mapping[device_index].subid, (Sensor_Type)SDL_OHOS_SensorGetDeviceNonPortableType(device_index)) != SENSOR_SUCCESS) { + return false; + } + + mapping[device_index].subattr = OH_Sensor_CreateSubscriptionAttribute(); + if (OH_SensorSubscriptionAttribute_SetSamplingInterval(mapping[device_index].subattr, 10000000) != SENSOR_SUCCESS) { + return false; + } + + if (OH_Sensor_Subscribe(mapping[device_index].subid, mapping[device_index].subattr, mapping[device_index].subs) != SENSOR_SUCCESS) { + return false; + } + + return true; +} + +static void SDL_OHOS_SensorUpdate(SDL_Sensor *sensor) +{ +} + +static void SDL_OHOS_SensorClose(SDL_Sensor *sensor) +{ + for (int i = 0; i < sensorCount; i++) { + if (mapping[i].sensor == sensor) { + mapping[i].sensor = NULL; + OH_Sensor_Unsubscribe(mapping[i].subid, mapping[i].subs); + if (mapping[i].subattr) { + OH_Sensor_DestroySubscriptionAttribute(mapping[i].subattr); + mapping[i].subattr = NULL; + } + if (mapping[i].subid) { + OH_Sensor_DestroySubscriptionId(mapping[i].subid); + mapping[i].subid = NULL; + } + if (mapping[i].subs) { + OH_Sensor_DestroySubscriber(mapping[i].subs); + mapping[i].subs = NULL; + } + break; + } + } +} + +static void SDL_OHOS_SensorQuit(void) +{ + for (int i = 0; i < sensorCount; i++) { + if (mapping[i].sensor) { + SDL_OHOS_SensorClose(mapping[i].sensor); + } + } + sensorCount = 0; + SDL_free(mapping); +} + +SDL_SensorDriver SDL_OHOS_SensorDriver = { + SDL_OHOS_SensorInit, + SDL_OHOS_SensorGetCount, + SDL_OHOS_SensorDetect, + SDL_OHOS_SensorGetDeviceName, + SDL_OHOS_SensorGetDeviceType, + SDL_OHOS_SensorGetDeviceNonPortableType, + SDL_OHOS_SensorGetDeviceInstanceID, + SDL_OHOS_SensorOpen, + SDL_OHOS_SensorUpdate, + SDL_OHOS_SensorClose, + SDL_OHOS_SensorQuit, +}; + +#endif // SDL_SENSOR_DUMMY || SDL_SENSOR_DISABLED diff --git a/src/video/ohos/SDL_ohosvideo.c b/src/video/ohos/SDL_ohosvideo.c index b6426a6dc4..44f1f4f5cd 100644 --- a/src/video/ohos/SDL_ohosvideo.c +++ b/src/video/ohos/SDL_ohosvideo.c @@ -119,7 +119,17 @@ bool OHOS_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID length1 = SDL_strlen(messageboxdata->message) + 1; char* messagecopy = (char*)SDL_malloc(length1); SDL_memcpy(messagecopy, messageboxdata->message, length1); - OHOS_MessageBox(titlecopy, messagecopy); + + int* mapping = (int *)SDL_malloc(sizeof(int) * messageboxdata->numbuttons); + const char ** btns = (const char **)SDL_malloc(sizeof(void*) * messageboxdata->numbuttons); + + for (int i = 0; i < messageboxdata->numbuttons; i++) + { + mapping[i] = messageboxdata->buttons[i].buttonID; + btns[i] = messageboxdata->buttons[i].text; + } + + *buttonID = OHOS_MessageBox(titlecopy, messagecopy, messageboxdata->numbuttons, mapping, messageboxdata->numbuttons, btns); return true; } VideoBootStrap OHOS_bootstrap = { From 4a3c920d8aed16b387301fbdbeb426fa048efdaf Mon Sep 17 00:00:00 2001 From: Coder2 <83895170+MetsukiMio@users.noreply.github.com> Date: Tue, 9 Dec 2025 20:40:45 +0800 Subject: [PATCH 82/92] Update action.yml --- .github/actions/setup-harmony-toolchain/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/setup-harmony-toolchain/action.yml b/.github/actions/setup-harmony-toolchain/action.yml index b13a29888c..ae00be8c69 100644 --- a/.github/actions/setup-harmony-toolchain/action.yml +++ b/.github/actions/setup-harmony-toolchain/action.yml @@ -2,7 +2,7 @@ name: 'Setup Harmony toolchain' inputs: version: description: 'Harmony version' - default: '5.0.0-Release' + default: '6.0-Release' runs: using: 'composite' steps: From 4cb2b0c71b392b1f375eeec42e85dc3d2e948e1b Mon Sep 17 00:00:00 2001 From: artin Date: Wed, 4 Feb 2026 02:02:06 +0800 Subject: [PATCH 83/92] fix(ohos): process only the changed touch point in touch events The previous implementation processed all touch points in the array for every touch event, which could cause duplicate or incorrect events since the array contains the current state of all fingers. Now we correctly identify and process only the finger that triggered the current event (touchEvent.id), improving touch event accuracy on OpenHarmony platforms. --- src/core/ohos/SDL_ohos.c | 62 ++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 5c8ab566ab..890863250d 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -662,36 +662,48 @@ static void onNativeTouch(OH_NativeXComponent *component, void *window) OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent); OH_NativeXComponent_GetTouchPointToolType(component, 0, &toolType); + // Only process the finger that triggered this event (touchEvent.id). + // The touchPoints array contains current state of all fingers, not just the changed one. + int targetIndex = -1; for (int i = 0; i < touchEvent.numPoints; i++) { - SDL_OHOSTouchEvent e; - e.timestamp = touchEvent.timeStamp; - // skip assertions - e.deviceId = touchEvent.deviceId + 1; - e.fingerId = touchEvent.touchPoints[i].id + 1; - e.area = touchEvent.touchPoints[i].size; - e.x = touchEvent.touchPoints[i].x / (float)wid; - e.y = touchEvent.touchPoints[i].y / (float)hei; - e.p = touchEvent.touchPoints[i].force; - - switch (touchEvent.touchPoints[i].type) { - case OH_NATIVEXCOMPONENT_DOWN: - e.type = SDL_EVENT_FINGER_DOWN; - break; - case OH_NATIVEXCOMPONENT_MOVE: - e.type = SDL_EVENT_FINGER_MOTION; - break; - case OH_NATIVEXCOMPONENT_UP: - e.type = SDL_EVENT_FINGER_UP; - break; - case OH_NATIVEXCOMPONENT_CANCEL: - case OH_NATIVEXCOMPONENT_UNKNOWN: - e.type = SDL_EVENT_FINGER_CANCELED; + if (touchEvent.touchPoints[i].id == touchEvent.id) { + targetIndex = i; break; } - - OHOS_OnTouch(e); } + if (targetIndex < 0) { + OHOS_UnlockPage(); + return; + } + + SDL_OHOSTouchEvent e; + e.timestamp = touchEvent.timeStamp; + e.deviceId = touchEvent.deviceId + 1; + e.fingerId = touchEvent.touchPoints[targetIndex].id + 1; + e.area = touchEvent.touchPoints[targetIndex].size; + e.x = touchEvent.touchPoints[targetIndex].x / (float)wid; + e.y = touchEvent.touchPoints[targetIndex].y / (float)hei; + e.p = touchEvent.touchPoints[targetIndex].force; + + switch (touchEvent.touchPoints[targetIndex].type) { + case OH_NATIVEXCOMPONENT_DOWN: + e.type = SDL_EVENT_FINGER_DOWN; + break; + case OH_NATIVEXCOMPONENT_MOVE: + e.type = SDL_EVENT_FINGER_MOTION; + break; + case OH_NATIVEXCOMPONENT_UP: + e.type = SDL_EVENT_FINGER_UP; + break; + case OH_NATIVEXCOMPONENT_CANCEL: + case OH_NATIVEXCOMPONENT_UNKNOWN: + e.type = SDL_EVENT_FINGER_CANCELED; + break; + } + + OHOS_OnTouch(e); + OHOS_UnlockPage(); } // TODO mouse data From f2c9b334a18d68f9a5c22947f5838f18c0d3bf8c Mon Sep 17 00:00:00 2001 From: Coder2 Date: Tue, 17 Mar 2026 20:35:31 +0800 Subject: [PATCH 84/92] OpenHarmony: merge / fix --- src/video/ohos/SDL_ohosgl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video/ohos/SDL_ohosgl.c b/src/video/ohos/SDL_ohosgl.c index 53e13af30e..27f09a6f85 100644 --- a/src/video/ohos/SDL_ohosgl.c +++ b/src/video/ohos/SDL_ohosgl.c @@ -41,7 +41,7 @@ bool OHOS_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window) bool OHOS_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path) { - return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)0, 0); + return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)0); } #endif From 0011f07acf5b758578b035ab0973d2c92989d635 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Wed, 18 Mar 2026 20:43:52 +0800 Subject: [PATCH 85/92] OpenHarmony: port & fix to 6.0.0 --- ohos-project/AppScope/app.json5 | 4 +- .../resources/base/element/string.json | 2 +- .../resources/base/media/foreground.png | Bin 14526 -> 8805 bytes .../resources/base/media/foreground0.png | Bin 0 -> 14526 bytes .../resources/base/media/oforeground.png | Bin 8805 -> 0 bytes ohos-project/build-profile.json5 | 3 +- ohos-project/entry/build-profile.json5 | 13 +++--- ohos-project/entry/hvigorfile.ts | 6 +-- ohos-project/entry/oh-package-lock.json5 | 9 +--- ohos-project/entry/oh-package.json5 | 3 +- .../src/main/cpp/types/libentry/Index.d.ts | 1 - .../main/cpp/types/libentry/oh-package.json5 | 6 --- .../main/ets/entryability/EntryAbility.ets | 29 +++++++------ .../entrybackupability/EntryBackupAbility.ets | 4 +- .../entry/src/main/ets/pages/Index.ets | 39 +++++++++--------- ohos-project/entry/src/mock/Libentry.mock.ets | 7 ---- ohos-project/entry/src/mock/mock-config.json5 | 5 --- .../src/ohosTest/ets/test/Ability.test.ets | 35 ---------------- .../entry/src/ohosTest/ets/test/List.test.ets | 5 --- ohos-project/entry/src/ohosTest/module.json5 | 13 ------ ohos-project/entry/src/test/List.test.ets | 5 --- .../entry/src/test/LocalUnit.test.ets | 33 --------------- ohos-project/hvigor/hvigor-config.json5 | 5 ++- ohos-project/hvigorfile.ts | 6 +-- ohos-project/oh-package-lock.json5 | 2 +- ohos-project/oh-package.json5 | 2 +- src/core/ohos/SDL_ohos.c | 3 +- 27 files changed, 62 insertions(+), 178 deletions(-) create mode 100644 ohos-project/AppScope/resources/base/media/foreground0.png delete mode 100644 ohos-project/AppScope/resources/base/media/oforeground.png delete mode 100644 ohos-project/entry/src/main/cpp/types/libentry/Index.d.ts delete mode 100644 ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 delete mode 100644 ohos-project/entry/src/mock/Libentry.mock.ets delete mode 100644 ohos-project/entry/src/mock/mock-config.json5 delete mode 100644 ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets delete mode 100644 ohos-project/entry/src/ohosTest/ets/test/List.test.ets delete mode 100644 ohos-project/entry/src/ohosTest/module.json5 delete mode 100644 ohos-project/entry/src/test/List.test.ets delete mode 100644 ohos-project/entry/src/test/LocalUnit.test.ets diff --git a/ohos-project/AppScope/app.json5 b/ohos-project/AppScope/app.json5 index 2a08169692..a65624e4b6 100644 --- a/ohos-project/AppScope/app.json5 +++ b/ohos-project/AppScope/app.json5 @@ -1,7 +1,7 @@ { "app": { - "bundleName": "com.cpp.app", - "vendor": "example", + "bundleName": "org.libsdl.SdlShell", + "vendor": "libsdl-org", "versionCode": 1000000, "versionName": "1.0.0", "icon": "$media:layered_image", diff --git a/ohos-project/AppScope/resources/base/element/string.json b/ohos-project/AppScope/resources/base/element/string.json index a1b9d1934d..2b6cf61a6d 100644 --- a/ohos-project/AppScope/resources/base/element/string.json +++ b/ohos-project/AppScope/resources/base/element/string.json @@ -2,7 +2,7 @@ "string": [ { "name": "app_name", - "value": "MyApplication" + "value": "SDL Demo" }, { "name": "perm_reason", diff --git a/ohos-project/AppScope/resources/base/media/foreground.png b/ohos-project/AppScope/resources/base/media/foreground.png index 959c384b08eb45ef38765fecbfba3891c15132b8..97014d3e10e5ff511409c378cd4255713aecd85f 100644 GIT binary patch literal 8805 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 number; \ No newline at end of file diff --git a/ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 b/ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 deleted file mode 100644 index ea410725a8..0000000000 --- a/ohos-project/entry/src/main/cpp/types/libentry/oh-package.json5 +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "libentry.so", - "types": "./Index.d.ts", - "version": "1.0.0", - "description": "Please describe the basic information." -} \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets index d944faaa4d..36fa126877 100644 --- a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -4,10 +4,9 @@ import { abilityAccessCtrl, AbilityConstant, Permissions, UIAbility, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; -import { promptAction, window } from '@kit.ArkUI'; +import { window } from '@kit.ArkUI'; import { KeyboardAvoidMode } from '@ohos.arkui.UIContext'; import { BusinessError } from '@kit.BasicServicesKit'; -import bundleManager from '@ohos.bundle.bundleManager'; const DOMAIN = 0x0000; @@ -34,53 +33,53 @@ function reqPermissionsFromUser(permissions: Array, context: common export default class EntryAbility extends UIAbility { onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); - hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onCreate'); } onDestroy(): void { - hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onDestroy'); } async onWindowStageCreate(windowStage: window.WindowStage): Promise { // Main window is created, set main page for this ability - hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onWindowStageCreate'); windowStage.loadContent('pages/Index', (err) => { reqPermissionsFromUser(permissions, this.context); windowStage.getMainWindow().then(async (win) => { try { - win.setWindowTitleButtonVisible(true, true, true) win.getUIContext().setKeyboardAvoidMode(KeyboardAvoidMode.OFFSET) - // win.setWindowLayoutFullScreen(true) - // win.setPreferredOrientation(window.Orientation.FOLLOW_DESKTOP) - win.setResizeByDragEnabled(true) } catch (error) { let ll: BusinessError = error; - hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(ll)); + hilog.error(DOMAIN, 'surfaceLayer', 'Failed to load the content. Cause: %{public}s', JSON.stringify(ll)); } }) if (err.code) { - hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + hilog.error(DOMAIN, 'surfaceLayer', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); return; } - hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + hilog.info(DOMAIN, 'surfaceLayer', 'Succeeded in loading the content.'); }); } onWindowStageDestroy(): void { // Main window is destroyed, release UI related resources - hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onWindowStageDestroy'); } onForeground(): void { // Ability has brought to foreground - hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onForeground'); } onBackground(): void { // Ability has back to background - hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onBackground'); + } + + onMemoryLevel(level: AbilityConstant.MemoryLevel): void { + } } diff --git a/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets index 8e4de99282..8e9efdda96 100644 --- a/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +++ b/ohos-project/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -5,12 +5,12 @@ const DOMAIN = 0x0000; export default class EntryBackupAbility extends BackupExtensionAbility { async onBackup() { - hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + hilog.info(DOMAIN, 'surfaceLayer', 'onBackup ok'); await Promise.resolve(); } async onRestore(bundleVersion: BundleVersion) { - hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + hilog.info(DOMAIN, 'surfaceLayer', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); await Promise.resolve(); } } \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 8ae12d6b5b..dea6ad2451 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -1,5 +1,5 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; -import sdltest from 'libSDL3.so'; +import sdl from 'libSDL3.so'; import { intl } from '@kit.LocalizationKit'; import { promptAction, ShowDialogSuccessResponse } from '@kit.ArkUI'; import { inputMethod } from '@kit.IMEKit' @@ -19,7 +19,7 @@ let context: UIContext export class ArkNapiCallback { onMainLaunch() { - sdltest.sdlLaunchMain("libentry.so", "main") + sdl.sdlLaunchMain("libentry.so", "main") } showDialog(title: string, message: string, indexMapping: number[], names: string[]) { @@ -29,16 +29,15 @@ export class ArkNapiCallback { target.push({ text: names[i], color: '#999999' }) } promptAction.showDialog({ title: title, message: message, buttons: target }).then((a) => { - sdltest.sdlSendDialogStatus(indexMapping[a.index]) + sdl.sdlSendDialogStatus(indexMapping[a.index]) }) } fetchLocale(): string { let locale = new intl.Locale() return locale.language + "_" + locale.region } - test(): number { - hilog.info(DOMAIN, 'testTag', 'Call from native !!!') - return 1 + firstCall() { + hilog.info(DOMAIN, 'surfaceLayer', 'Native binding finished.') } openLink(url: string) { @@ -64,11 +63,11 @@ export class ArkNapiCallback { let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); systemPasteboard.setData(pasteData, (err, data) => { if (err) { - hilog.error(DOMAIN, 'testTag', 'Failed to set PasteData. Cause: ' + err.message); + hilog.error(DOMAIN, 'surfaceLayer', 'Failed to set PasteData. Cause: ' + err.message); return; } - hilog.info(DOMAIN, 'testTag', 'Succeed in setting PasteData.'); + hilog.info(DOMAIN, 'surfaceLayer', 'Succeed in setting PasteData.'); }); } @@ -79,12 +78,12 @@ export class ArkNapiCallback { startTextInput() { input = true controller.showTextInput() - hilog.info(DOMAIN, 'testTag', 'text input start') + hilog.info(DOMAIN, 'surfaceLayer', 'text input start') } stopTextInput() { input = false controller.hideTextInput() - hilog.info(DOMAIN, 'testTag', 'text input stop') + hilog.info(DOMAIN, 'surfaceLayer', 'text input stop') targetText = "" } @@ -136,14 +135,14 @@ export class ArkNapiCallback { const documentViewPicker = new picker.DocumentViewPicker(contextt); documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array) => { uris = documentSelectResult; - sdltest.sdlDialogClearSelection() + sdl.sdlDialogClearSelection() for (let idx = 0; idx < uris.length; idx++) { let target = uris[idx].replace("file://docs", "") - sdltest.sdlDialogFileSelected(target) + sdl.sdlDialogFileSelected(target) console.info('documentViewPicker.select to file succeed and uris are: ' + target); } - sdltest.sdlDialogExecCallback() + sdl.sdlDialogExecCallback() }).catch((err: BusinessError) => { console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`); }) @@ -163,7 +162,7 @@ struct Index { async aboutToAppear(): Promise { context = this.getUIContext() - sdltest.sdlCallbackInit(callbackRef) + sdl.sdlCallbackInit(callbackRef) focusControl.requestFocus('mainView') await controller.attach(true, { inputAttribute: { @@ -173,23 +172,23 @@ struct Index { }); controller.on('insertText', (text) => { targetText += text; - sdltest.sdlTextAppend(text) + sdl.sdlTextAppend(text) }) controller.on('deleteLeft', (i) => { - sdltest.sdlTextEditing(targetText, targetText.length - 1 - i, i); + sdl.sdlTextEditing(targetText, targetText.length - 1 - i, i); if (targetText.length > 0) { targetText = targetText.substring(0, targetText.length - i) } - hilog.info(DOMAIN, 'testTag', targetText) + hilog.info(DOMAIN, 'surfaceLayer', targetText) }) controller.on('deleteRight', (i) => { - sdltest.sdlTextEditing(targetText, 0, i); + sdl.sdlTextEditing(targetText, 0, i); if (targetText.length > 0) { targetText = targetText.substring(i, targetText.length) } - hilog.info(DOMAIN, 'testTag', targetText) + hilog.info(DOMAIN, 'surfaceLayer', targetText) }) } @@ -199,7 +198,7 @@ struct Index { .id('mainView') } .onKeyEvent((keyevent) => { - sdltest.sdlKeyEvent(keyevent.keyCode, keyevent.type); + sdl.sdlKeyEvent(keyevent.keyCode, keyevent.type); }) } } diff --git a/ohos-project/entry/src/mock/Libentry.mock.ets b/ohos-project/entry/src/mock/Libentry.mock.ets deleted file mode 100644 index c2171716d0..0000000000 --- a/ohos-project/entry/src/mock/Libentry.mock.ets +++ /dev/null @@ -1,7 +0,0 @@ -const NativeMock: Record = { - 'add': (a: number, b: number) => { - return a + b; - }, -}; - -export default NativeMock; \ No newline at end of file diff --git a/ohos-project/entry/src/mock/mock-config.json5 b/ohos-project/entry/src/mock/mock-config.json5 deleted file mode 100644 index 6540976c9a..0000000000 --- a/ohos-project/entry/src/mock/mock-config.json5 +++ /dev/null @@ -1,5 +0,0 @@ -{ - "libentry.so": { - "source": "src/mock/Libentry.mock.ets" - } -} \ No newline at end of file diff --git a/ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets b/ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets deleted file mode 100644 index 85c78f6757..0000000000 --- a/ohos-project/entry/src/ohosTest/ets/test/Ability.test.ets +++ /dev/null @@ -1,35 +0,0 @@ -import { hilog } from '@kit.PerformanceAnalysisKit'; -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; - -export default function abilityTest() { - describe('ActsAbilityTest', () => { - // Defines a test suite. Two parameters are supported: test suite name and test suite function. - beforeAll(() => { - // Presets an action, which is performed only once before all test cases of the test suite start. - // This API supports only one parameter: preset action function. - }) - beforeEach(() => { - // Presets an action, which is performed before each unit test case starts. - // The number of execution times is the same as the number of test cases defined by **it**. - // This API supports only one parameter: preset action function. - }) - afterEach(() => { - // Presets a clear action, which is performed after each unit test case ends. - // The number of execution times is the same as the number of test cases defined by **it**. - // This API supports only one parameter: clear action function. - }) - afterAll(() => { - // Presets a clear action, which is performed after all test cases of the test suite end. - // This API supports only one parameter: clear action function. - }) - it('assertContain', 0, () => { - // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. - hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); - let a = 'abc'; - let b = 'b'; - // Defines a variety of assertion methods, which are used to declare expected boolean conditions. - expect(a).assertContain(b); - expect(a).assertEqual(a); - }) - }) -} \ No newline at end of file diff --git a/ohos-project/entry/src/ohosTest/ets/test/List.test.ets b/ohos-project/entry/src/ohosTest/ets/test/List.test.ets deleted file mode 100644 index 794c7dc4ed..0000000000 --- a/ohos-project/entry/src/ohosTest/ets/test/List.test.ets +++ /dev/null @@ -1,5 +0,0 @@ -import abilityTest from './Ability.test'; - -export default function testsuite() { - abilityTest(); -} \ No newline at end of file diff --git a/ohos-project/entry/src/ohosTest/module.json5 b/ohos-project/entry/src/ohosTest/module.json5 deleted file mode 100644 index 55725a9299..0000000000 --- a/ohos-project/entry/src/ohosTest/module.json5 +++ /dev/null @@ -1,13 +0,0 @@ -{ - "module": { - "name": "entry_test", - "type": "feature", - "deviceTypes": [ - "phone", - "tablet", - "2in1" - ], - "deliveryWithInstall": true, - "installationFree": false - } -} diff --git a/ohos-project/entry/src/test/List.test.ets b/ohos-project/entry/src/test/List.test.ets deleted file mode 100644 index bb5b5c3731..0000000000 --- a/ohos-project/entry/src/test/List.test.ets +++ /dev/null @@ -1,5 +0,0 @@ -import localUnitTest from './LocalUnit.test'; - -export default function testsuite() { - localUnitTest(); -} \ No newline at end of file diff --git a/ohos-project/entry/src/test/LocalUnit.test.ets b/ohos-project/entry/src/test/LocalUnit.test.ets deleted file mode 100644 index 165fc1615e..0000000000 --- a/ohos-project/entry/src/test/LocalUnit.test.ets +++ /dev/null @@ -1,33 +0,0 @@ -import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; - -export default function localUnitTest() { - describe('localUnitTest', () => { - // Defines a test suite. Two parameters are supported: test suite name and test suite function. - beforeAll(() => { - // Presets an action, which is performed only once before all test cases of the test suite start. - // This API supports only one parameter: preset action function. - }); - beforeEach(() => { - // Presets an action, which is performed before each unit test case starts. - // The number of execution times is the same as the number of test cases defined by **it**. - // This API supports only one parameter: preset action function. - }); - afterEach(() => { - // Presets a clear action, which is performed after each unit test case ends. - // The number of execution times is the same as the number of test cases defined by **it**. - // This API supports only one parameter: clear action function. - }); - afterAll(() => { - // Presets a clear action, which is performed after all test cases of the test suite end. - // This API supports only one parameter: clear action function. - }); - it('assertContain', 0, () => { - // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. - let a = 'abc'; - let b = 'b'; - // Defines a variety of assertion methods, which are used to declare expected boolean conditions. - expect(a).assertContain(b); - expect(a).assertEqual(a); - }); - }); -} \ No newline at end of file diff --git a/ohos-project/hvigor/hvigor-config.json5 b/ohos-project/hvigor/hvigor-config.json5 index 58a9aa9da1..7a7ab8914d 100644 --- a/ohos-project/hvigor/hvigor-config.json5 +++ b/ohos-project/hvigor/hvigor-config.json5 @@ -3,11 +3,12 @@ "dependencies": { }, "execution": { - // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + // "optimizationStrategy": "memory" /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */ }, "logging": { // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ @@ -19,4 +20,4 @@ // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ } -} \ No newline at end of file +} diff --git a/ohos-project/hvigorfile.ts b/ohos-project/hvigorfile.ts index f3cb9f1a87..47113e2e36 100644 --- a/ohos-project/hvigorfile.ts +++ b/ohos-project/hvigorfile.ts @@ -1,6 +1,6 @@ import { appTasks } from '@ohos/hvigor-ohos-plugin'; export default { - system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ - plugins:[] /* Custom plugin to extend the functionality of Hvigor. */ -} + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/ohos-project/oh-package-lock.json5 b/ohos-project/oh-package-lock.json5 index a3c0b60cab..6b264af261 100644 --- a/ohos-project/oh-package-lock.json5 +++ b/ohos-project/oh-package-lock.json5 @@ -14,7 +14,7 @@ "name": "", "version": "1.0.0", "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", - "resolved": "https://repo.harmonyos.com/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har", "registryType": "ohpm" }, "@ohos/hypium@1.0.24": { diff --git a/ohos-project/oh-package.json5 b/ohos-project/oh-package.json5 index 374f820f3a..c72aa05d54 100644 --- a/ohos-project/oh-package.json5 +++ b/ohos-project/oh-package.json5 @@ -7,4 +7,4 @@ "@ohos/hypium": "1.0.24", "@ohos/hamock": "1.0.0" } -} \ No newline at end of file +} diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 890863250d..72e7762d27 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -1,4 +1,5 @@ #include "SDL_internal.h" +#include "events/SDL_events_c.h" #include "events/SDL_keyboard_c.h" #include "video/ohos/SDL_ohosmouse.h" #include @@ -503,7 +504,7 @@ static napi_value sdlCallbackInit(napi_env env, napi_callback_info info) napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); SDL_memset(data, 0, sizeof(napiCallbackData)); - data->func = "test"; + data->func = "firstCall"; data->argCount = 0; data->type = Int; From d38a78f38360846462f29e4262c3e2d649a5b3c5 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Wed, 18 Mar 2026 21:16:26 +0800 Subject: [PATCH 86/92] OpenHarmony: more events --- .../entry/src/main/cpp/sdl/Index.d.ts | 7 +- .../main/ets/entryability/EntryAbility.ets | 16 +++- .../entry/src/main/ets/pages/Index.ets | 8 +- src/core/ohos/SDL_ohos.c | 77 ++++++++++++++++++- src/core/ohos/SDL_ohos.h | 1 + 5 files changed, 102 insertions(+), 7 deletions(-) diff --git a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts index e74d54db8d..826606cef7 100644 --- a/ohos-project/entry/src/main/cpp/sdl/Index.d.ts +++ b/ohos-project/entry/src/main/cpp/sdl/Index.d.ts @@ -6,4 +6,9 @@ export const sdlTextEditing: (str: string, loc: number, length: number) => numbe export const sdlDialogExecCallback: () => void; export const sdlDialogClearSelection: () => void; export const sdlDialogFileSelected: (path: string) => void; -export const sdlSendDialogStatus: (idx: number) => void; \ No newline at end of file +export const sdlSendDialogStatus: (idx: number) => void; +export const sdlOnBackground: () => void; +export const sdlOnForeground: () => void; +export const sdlOnLowMemory: () => void; +export const sdlOnTerminate: () => void; +export const sdlOnConfigUpdate: () => void; \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets index 36fa126877..022255cf25 100644 --- a/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets +++ b/ohos-project/entry/src/main/ets/entryability/EntryAbility.ets @@ -1,5 +1,6 @@ import { abilityAccessCtrl, AbilityConstant, common, + Configuration, ConfigurationConstant, Permissions, UIAbility, Want } from '@kit.AbilityKit'; @@ -7,6 +8,7 @@ import { hilog } from '@kit.PerformanceAnalysisKit'; import { window } from '@kit.ArkUI'; import { KeyboardAvoidMode } from '@ohos.arkui.UIContext'; import { BusinessError } from '@kit.BasicServicesKit'; +import sdl from 'libSDL3.so'; const DOMAIN = 0x0000; @@ -65,21 +67,27 @@ export default class EntryAbility extends UIAbility { } onWindowStageDestroy(): void { - // Main window is destroyed, release UI related resources hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onWindowStageDestroy'); + sdl.sdlOnTerminate(); } onForeground(): void { - // Ability has brought to foreground hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onForeground'); + sdl.sdlOnForeground(); } onBackground(): void { - // Ability has back to background hilog.info(DOMAIN, 'surfaceLayer', '%{public}s', 'Ability onBackground'); + sdl.sdlOnBackground(); } onMemoryLevel(level: AbilityConstant.MemoryLevel): void { - + if (level == AbilityConstant.MemoryLevel.MEMORY_LEVEL_LOW || level == AbilityConstant.MemoryLevel.MEMORY_LEVEL_CRITICAL) { + sdl.sdlOnLowMemory(); + } + } + + onConfigurationUpdate(newConfig: Configuration): void { + sdl.sdlOnConfigUpdate(); } } diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index dea6ad2451..8ec3487e9f 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -4,7 +4,7 @@ import { intl } from '@kit.LocalizationKit'; import { promptAction, ShowDialogSuccessResponse } from '@kit.ArkUI'; import { inputMethod } from '@kit.IMEKit' import { pasteboard } from '@kit.BasicServicesKit'; -import { common } from '@kit.AbilityKit'; +import { common, ConfigurationConstant } from '@kit.AbilityKit'; import { batteryInfo } from '@kit.BasicServicesKit'; import { picker } from '@kit.CoreFileKit'; @@ -38,6 +38,7 @@ export class ArkNapiCallback { } firstCall() { hilog.info(DOMAIN, 'surfaceLayer', 'Native binding finished.') + sdl.sdlOnConfigUpdate(); } openLink(url: string) { @@ -152,6 +153,11 @@ export class ArkNapiCallback { let contextt = context.getHostContext() as common.UIAbilityContext return contextt.filesDir } + + themeIsDark(): number { + let contextt = context.getHostContext() as common.UIAbilityContext + return (contextt.config.colorMode == ConfigurationConstant.ColorMode.COLOR_MODE_DARK) ? 1 : 0; + } } let callbackRef: ArkNapiCallback = new ArkNapiCallback() diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 72e7762d27..5792f914a6 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -452,6 +452,22 @@ void OHOS_OpenLink(const char* url) napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_blocking); } +bool OHOS_ThemeDark() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "themeIsDark"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + return data->ret.data.i; +} + const char* OHOS_Locale() { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); @@ -865,6 +881,60 @@ static napi_value sdlSendDialogStatus(napi_env env, napi_callback_info info) return result; } +static napi_value sdlOnBackground(napi_env env, napi_callback_info info) +{ + SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_BACKGROUND); + SDL_SendAppEvent(SDL_EVENT_DID_ENTER_BACKGROUND); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlOnForeground(napi_env env, napi_callback_info info) +{ + SDL_SendAppEvent(SDL_EVENT_WILL_ENTER_FOREGROUND); + SDL_SendAppEvent(SDL_EVENT_DID_ENTER_FOREGROUND); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlOnLowMemory(napi_env env, napi_callback_info info) +{ + SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlOnTerminate(napi_env env, napi_callback_info info) +{ + SDL_SendAppEvent(SDL_EVENT_TERMINATING); + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +static napi_value sdlOnConfigUpdate(napi_env env, napi_callback_info info) +{ + SDL_SendAppEvent(SDL_EVENT_LOCALE_CHANGED); + SDL_SendAppEvent(SDL_EVENT_SYSTEM_THEME_CHANGED); + + SDL_VideoDevice *_this = SDL_GetVideoDevice(); + if (_this) + { + _this->system_theme = OHOS_ThemeDark() ? SDL_SYSTEM_THEME_DARK : SDL_SYSTEM_THEME_LIGHT; + } + + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { @@ -876,7 +946,12 @@ static napi_value SDL_OHOS_NAPI_Init(napi_env env, napi_value exports) { "sdlDialogClearSelection", NULL, sdlDialogClearSelection, NULL, NULL, NULL, napi_default, NULL }, { "sdlDialogExecCallback", NULL, sdlDialogExecCallback, NULL, NULL, NULL, napi_default, NULL }, { "sdlDialogFileSelected", NULL, sdlDialogFileSelected, NULL, NULL, NULL, napi_default, NULL }, - { "sdlSendDialogStatus", NULL, sdlSendDialogStatus, NULL, NULL, NULL, napi_default, NULL } + { "sdlSendDialogStatus", NULL, sdlSendDialogStatus, NULL, NULL, NULL, napi_default, NULL }, + { "sdlOnBackground", NULL, sdlOnBackground, NULL, NULL, NULL, napi_default, NULL }, + { "sdlOnForeground", NULL, sdlOnForeground, NULL, NULL, NULL, napi_default, NULL }, + { "sdlOnLowMemory", NULL, sdlOnLowMemory, NULL, NULL, NULL, napi_default, NULL }, + { "sdlOnTerminate", NULL, sdlOnTerminate, NULL, NULL, NULL, napi_default, NULL }, + { "sdlOnConfigUpdate", NULL, sdlOnConfigUpdate, NULL, NULL, NULL, napi_default, NULL } }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index b00ff16e38..e82b8ff376 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -21,6 +21,7 @@ bool OHOS_IsBatteryCharged(); int OHOS_GetBatteryPercent(); void OHOS_SetClipboardText(const char* data); char* OHOS_GetStoragePath(); +bool OHOS_ThemeDark(); void OHOS_FileDialog(int id, const char* defpath, int allowmany, const char* filter); From 274b90f7e5be08390c9cb6b6331c21976d241234 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Wed, 18 Mar 2026 21:44:05 +0800 Subject: [PATCH 87/92] OpenHarmony: text edit --- .../entry/src/main/cpp/CMakeLists.txt | 2 +- .../cpp/{napi_init.cpp => entrypoint.cpp} | 64 ++----------------- .../entry/src/main/ets/pages/Index.ets | 2 - src/core/ohos/SDL_ohos.c | 4 ++ 4 files changed, 11 insertions(+), 61 deletions(-) rename ohos-project/entry/src/main/cpp/{napi_init.cpp => entrypoint.cpp} (84%) diff --git a/ohos-project/entry/src/main/cpp/CMakeLists.txt b/ohos-project/entry/src/main/cpp/CMakeLists.txt index b3e379e17c..1b8714f992 100644 --- a/ohos-project/entry/src/main/cpp/CMakeLists.txt +++ b/ohos-project/entry/src/main/cpp/CMakeLists.txt @@ -16,6 +16,6 @@ include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include ${SDL3_SOURCE_DIR}/include) -add_library(entry SHARED napi_init.cpp) +add_library(entry SHARED entrypoint.cpp) add_dependencies(entry SDL3::SDL3-shared) target_link_libraries(entry PUBLIC libace_napi.z.so libSDL3.so libvulkan.so libGLESv2.so libohaudio.so libohsensor.so) diff --git a/ohos-project/entry/src/main/cpp/napi_init.cpp b/ohos-project/entry/src/main/cpp/entrypoint.cpp similarity index 84% rename from ohos-project/entry/src/main/cpp/napi_init.cpp rename to ohos-project/entry/src/main/cpp/entrypoint.cpp index d764002add..08922b3e57 100644 --- a/ohos-project/entry/src/main/cpp/napi_init.cpp +++ b/ohos-project/entry/src/main/cpp/entrypoint.cpp @@ -8,7 +8,6 @@ #include "SDL3/SDL_vulkan.h" #include "SDL3/SDL_locale.h" #include "SDL3/SDL_clipboard.h" -#include "napi/native_api.h" #include "SDL3/SDL_log.h" #include "SDL3/SDL_hints.h" #include "SDL3/SDL_power.h" @@ -23,44 +22,6 @@ #include #include -static napi_value Add(napi_env env, napi_callback_info info) -{ - size_t argc = 2; - napi_value args[2] = {nullptr}; - - napi_get_cb_info(env, info, &argc, args , nullptr, nullptr); - - napi_valuetype valuetype0; - napi_typeof(env, args[0], &valuetype0); - - napi_valuetype valuetype1; - napi_typeof(env, args[1], &valuetype1); - - double value0; - napi_get_value_double(env, args[0], &value0); - - double value1; - napi_get_value_double(env, args[1], &value1); - - napi_value sum; - napi_create_double(env, value0 + value1, &sum); - - SDL_Log("Add invoke!"); - - return sum; - -} - -EXTERN_C_START -static napi_value Init(napi_env env, napi_value exports) -{ - napi_property_descriptor desc[] = { - { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr } - }; - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - return exports; -} - float vtxdata[] = { -0.5f, -0.5f, 0.f, 0.5f, -0.5f, 0.0f, @@ -124,8 +85,6 @@ int main() SDL_Window* win = SDL_CreateWindow("test", 1024, 1024, SDL_WINDOW_OPENGL); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "SDL Application", "test!", win); - SDL_StartTextInput(win); - // SDL_StopTextInput(); auto context = SDL_GL_CreateContext(win); SDL_GL_MakeCurrent(win, context); @@ -167,6 +126,7 @@ int main() ((PFNGLCLEARCOLORPROC)SDL_GL_GetProcAddress("glClearColor"))(0, 0, 0, 0); while (true) { + SDL_StartTextInput(win); int w, h; SDL_GetWindowSize(win, &w, &h); @@ -200,6 +160,10 @@ int main() if (event.type == SDL_EVENT_QUIT) { break; } + + if (event.type == SDL_EVENT_TEXT_INPUT) { + SDL_Log("text %s", event.text.text); + } } } @@ -210,20 +174,4 @@ int main() SDL_DestroyWindow(win); return 0; -} -EXTERN_C_END - -static napi_module demoModule = { - .nm_version = 1, - .nm_flags = 0, - .nm_filename = nullptr, - .nm_register_func = Init, - .nm_modname = "entry", - .nm_priv = ((void*)0), - .reserved = { 0 }, -}; - -extern "C" __attribute__((constructor)) void RegisterEntryModule(void) -{ - napi_module_register(&demoModule); -} +} \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 8ec3487e9f..72da526504 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -186,7 +186,6 @@ struct Index { if (targetText.length > 0) { targetText = targetText.substring(0, targetText.length - i) } - hilog.info(DOMAIN, 'surfaceLayer', targetText) }) controller.on('deleteRight', (i) => { sdl.sdlTextEditing(targetText, 0, i); @@ -194,7 +193,6 @@ struct Index { if (targetText.length > 0) { targetText = targetText.substring(i, targetText.length) } - hilog.info(DOMAIN, 'surfaceLayer', targetText) }) } diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index 5792f914a6..318dce9e87 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -800,6 +800,8 @@ static napi_value sdlTextAppend(napi_env env, napi_callback_info info) SDL_SendKeyboardText(fname); + SDL_free(fname); + napi_value result; napi_create_int32(env, 0, &result); return result; @@ -822,6 +824,8 @@ static napi_value sdlTextEditing(napi_env env, napi_callback_info info) SDL_SendEditingText(fname, start, len); + SDL_free(fname); + napi_value result; napi_create_int32(env, 0, &result); return result; From 933dbbefc467c07f626fb62965270c501344f6f5 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 24 May 2026 18:39:41 +0800 Subject: [PATCH 88/92] openharmony: update & merge --- ohos-project/entry/oh-package-lock.json5 | 36 +- .../entry/src/main/ets/pages/Index.ets | 420 +++++++++--------- ohos-project/oh-package-lock.json5 | 54 +-- src/SDL.c | 8 +- src/core/ohos/SDL_ohos.c | 18 + src/core/ohos/SDL_ohos.h | 78 ++-- 6 files changed, 322 insertions(+), 292 deletions(-) diff --git a/ohos-project/entry/oh-package-lock.json5 b/ohos-project/entry/oh-package-lock.json5 index 8d56dfdc2f..2967845e7e 100644 --- a/ohos-project/entry/oh-package-lock.json5 +++ b/ohos-project/entry/oh-package-lock.json5 @@ -1,19 +1,19 @@ -{ - "meta": { - "stableOrder": true, - "enableUnifiedLockfile": false - }, - "lockfileVersion": 3, - "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", - "specifiers": { - "libSDL3.so@src/main/cpp/sdl": "libSDL3.so@src/main/cpp/sdl" - }, - "packages": { - "libSDL3.so@src/main/cpp/sdl": { - "name": "libSDL3.so", - "version": "1.0.0", - "resolved": "", - "registryType": "local" - } - } +{ + "meta": { + "stableOrder": true, + "enableUnifiedLockfile": false + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "libSDL3.so@src/main/cpp/sdl": "libSDL3.so@src/main/cpp/sdl" + }, + "packages": { + "libSDL3.so@src/main/cpp/sdl": { + "name": "libSDL3.so", + "version": "1.0.0", + "resolved": "", + "registryType": "local" + } + } } \ No newline at end of file diff --git a/ohos-project/entry/src/main/ets/pages/Index.ets b/ohos-project/entry/src/main/ets/pages/Index.ets index 72da526504..5b94ed296a 100644 --- a/ohos-project/entry/src/main/ets/pages/Index.ets +++ b/ohos-project/entry/src/main/ets/pages/Index.ets @@ -1,208 +1,212 @@ -import { hilog } from '@kit.PerformanceAnalysisKit'; -import sdl from 'libSDL3.so'; -import { intl } from '@kit.LocalizationKit'; -import { promptAction, ShowDialogSuccessResponse } from '@kit.ArkUI'; -import { inputMethod } from '@kit.IMEKit' -import { pasteboard } from '@kit.BasicServicesKit'; -import { common, ConfigurationConstant } from '@kit.AbilityKit'; -import { batteryInfo } from '@kit.BasicServicesKit'; - -import { picker } from '@kit.CoreFileKit'; -import { BusinessError } from '@kit.BasicServicesKit'; - -const DOMAIN = 0x0000; - -let controller = inputMethod.getController() -let input = false -let targetText = "" -let context: UIContext - -export class ArkNapiCallback { - onMainLaunch() { - sdl.sdlLaunchMain("libentry.so", "main") - } - - showDialog(title: string, message: string, indexMapping: number[], names: string[]) { - let target: promptAction.Button[] = [] - for (let i = 0; i < names.length; i++) - { - target.push({ text: names[i], color: '#999999' }) - } - promptAction.showDialog({ title: title, message: message, buttons: target }).then((a) => { - sdl.sdlSendDialogStatus(indexMapping[a.index]) - }) - } - fetchLocale(): string { - let locale = new intl.Locale() - return locale.language + "_" + locale.region - } - firstCall() { - hilog.info(DOMAIN, 'surfaceLayer', 'Native binding finished.') - sdl.sdlOnConfigUpdate(); - } - - openLink(url: string) { - let con = context.getHostContext() as common.UIAbilityContext - con.openLink(url) - } - - hasBattery(): number { - return batteryInfo.isBatteryPresent ? 1 : 0 - } - batteryCharging(): number { - return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.ENABLE ? 1 : 0 - } - batteryCharged(): number { - return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.FULL ? 1 : 0 - } - batteryPercent(): number { - return batteryInfo.batterySOC - } - - setPasteboardString(text: string) { - let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); - let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); - systemPasteboard.setData(pasteData, (err, data) => { - if (err) { - hilog.error(DOMAIN, 'surfaceLayer', 'Failed to set PasteData. Cause: ' + err.message); - return; - } - - hilog.info(DOMAIN, 'surfaceLayer', 'Succeed in setting PasteData.'); - }); - } - - textEditing(): number { - return input ? 1 : 0; - } - - startTextInput() { - input = true - controller.showTextInput() - hilog.info(DOMAIN, 'surfaceLayer', 'text input start') - } - stopTextInput() { - input = false - controller.hideTextInput() - hilog.info(DOMAIN, 'surfaceLayer', 'text input stop') - targetText = "" - } - - openFileDialog(id: number, defpath: string, itemcount: number, filter: string) { - const documentSelectOptions = new picker.DocumentSelectOptions(); - documentSelectOptions.maxSelectNumber = itemcount; - documentSelectOptions.defaultFilePathUri = defpath; - - if (id == 0 || id == 1) - { - documentSelectOptions.selectMode = picker.DocumentSelectMode.FILE; - } - if (id == 2) - { - documentSelectOptions.selectMode = picker.DocumentSelectMode.FOLDER; - } - - let targetfilter: string[] = [] - let temp = filter.split('\u0002') - for (let index = 0; index < temp.length; index++) { - const element = temp[index]; - - let temp2 = element.split("|") - - // broken filter! - if (temp2.length == 1) - { - targetfilter.push(element + "|.*") - } - else - { - let targettemp = temp2[0] + "|"; - - let temp3 = temp2[1].split(";") - for (let index1 = 0; index1 < temp3.length; index1++) { - targettemp += "." + temp3[index1] + ","; - } - targetfilter.push(targettemp) - } - } - - documentSelectOptions.fileSuffixFilters = targetfilter; - documentSelectOptions.authMode = false; - documentSelectOptions.mergeMode = picker.MergeTypeMode.DEFAULT; - documentSelectOptions.isEncryptionSupported = false; - - let uris: string[] = []; - let contextt = context.getHostContext() as common.UIAbilityContext; - const documentViewPicker = new picker.DocumentViewPicker(contextt); - documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array) => { - uris = documentSelectResult; - sdl.sdlDialogClearSelection() - for (let idx = 0; idx < uris.length; idx++) - { - let target = uris[idx].replace("file://docs", "") - sdl.sdlDialogFileSelected(target) - console.info('documentViewPicker.select to file succeed and uris are: ' + target); - } - sdl.sdlDialogExecCallback() - }).catch((err: BusinessError) => { - console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`); - }) - } - - getInternalPath(): string { - let contextt = context.getHostContext() as common.UIAbilityContext - return contextt.filesDir - } - - themeIsDark(): number { - let contextt = context.getHostContext() as common.UIAbilityContext - return (contextt.config.colorMode == ConfigurationConstant.ColorMode.COLOR_MODE_DARK) ? 1 : 0; - } -} - -let callbackRef: ArkNapiCallback = new ArkNapiCallback() - -@Entry -@Component -struct Index { - async aboutToAppear(): Promise { - context = this.getUIContext() - - sdl.sdlCallbackInit(callbackRef) - focusControl.requestFocus('mainView') - await controller.attach(true, { - inputAttribute: { - textInputType: inputMethod.TextInputType.TEXT, - enterKeyType: inputMethod.EnterKeyType.DONE - } - }); - controller.on('insertText', (text) => { - targetText += text; - sdl.sdlTextAppend(text) - }) - controller.on('deleteLeft', (i) => { - sdl.sdlTextEditing(targetText, targetText.length - 1 - i, i); - - if (targetText.length > 0) { - targetText = targetText.substring(0, targetText.length - i) - } - }) - controller.on('deleteRight', (i) => { - sdl.sdlTextEditing(targetText, 0, i); - - if (targetText.length > 0) { - targetText = targetText.substring(i, targetText.length) - } - }) - } - - build() { - Column() { - XComponent({ id: 'mainView', type: 'surface', libraryname: 'SDL3' }) - .id('mainView') - } - .onKeyEvent((keyevent) => { - sdl.sdlKeyEvent(keyevent.keyCode, keyevent.type); - }) - } -} +import { hilog } from '@kit.PerformanceAnalysisKit'; +import sdl from 'libSDL3.so'; +import { intl } from '@kit.LocalizationKit'; +import { promptAction, ShowDialogSuccessResponse } from '@kit.ArkUI'; +import { inputMethod } from '@kit.IMEKit' +import { deviceInfo, pasteboard } from '@kit.BasicServicesKit'; +import { common, ConfigurationConstant } from '@kit.AbilityKit'; +import { batteryInfo } from '@kit.BasicServicesKit'; + +import { picker } from '@kit.CoreFileKit'; +import { BusinessError } from '@kit.BasicServicesKit'; + +const DOMAIN = 0x0000; + +let controller = inputMethod.getController() +let input = false +let targetText = "" +let context: UIContext + +export class ArkNapiCallback { + onMainLaunch() { + sdl.sdlLaunchMain("libentry.so", "main") + } + + showDialog(title: string, message: string, indexMapping: number[], names: string[]) { + let target: promptAction.Button[] = [] + for (let i = 0; i < names.length; i++) + { + target.push({ text: names[i], color: '#999999' }) + } + promptAction.showDialog({ title: title, message: message, buttons: target }).then((a) => { + sdl.sdlSendDialogStatus(indexMapping[a.index]) + }) + } + fetchLocale(): string { + let locale = new intl.Locale() + return locale.language + "_" + locale.region + } + firstCall() { + hilog.info(DOMAIN, 'surfaceLayer', 'Native binding finished.') + sdl.sdlOnConfigUpdate(); + } + + openLink(url: string) { + let con = context.getHostContext() as common.UIAbilityContext + con.openLink(url) + } + + hasBattery(): number { + return batteryInfo.isBatteryPresent ? 1 : 0 + } + batteryCharging(): number { + return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.ENABLE ? 1 : 0 + } + batteryCharged(): number { + return batteryInfo.chargingStatus == batteryInfo.BatteryChargeState.FULL ? 1 : 0 + } + batteryPercent(): number { + return batteryInfo.batterySOC + } + + setPasteboardString(text: string) { + let pasteData: pasteboard.PasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, text); + let systemPasteboard: pasteboard.SystemPasteboard = pasteboard.getSystemPasteboard(); + systemPasteboard.setData(pasteData, (err, data) => { + if (err) { + hilog.error(DOMAIN, 'surfaceLayer', 'Failed to set PasteData. Cause: ' + err.message); + return; + } + + hilog.info(DOMAIN, 'surfaceLayer', 'Succeed in setting PasteData.'); + }); + } + + textEditing(): number { + return input ? 1 : 0; + } + + startTextInput() { + input = true + controller.showTextInput() + hilog.info(DOMAIN, 'surfaceLayer', 'text input start') + } + stopTextInput() { + input = false + controller.hideTextInput() + hilog.info(DOMAIN, 'surfaceLayer', 'text input stop') + targetText = "" + } + + openFileDialog(id: number, defpath: string, itemcount: number, filter: string) { + const documentSelectOptions = new picker.DocumentSelectOptions(); + documentSelectOptions.maxSelectNumber = itemcount; + documentSelectOptions.defaultFilePathUri = defpath; + + if (id == 0 || id == 1) + { + documentSelectOptions.selectMode = picker.DocumentSelectMode.FILE; + } + if (id == 2) + { + documentSelectOptions.selectMode = picker.DocumentSelectMode.FOLDER; + } + + let targetfilter: string[] = [] + let temp = filter.split('\u0002') + for (let index = 0; index < temp.length; index++) { + const element = temp[index]; + + let temp2 = element.split("|") + + // broken filter! + if (temp2.length == 1) + { + targetfilter.push(element + "|.*") + } + else + { + let targettemp = temp2[0] + "|"; + + let temp3 = temp2[1].split(";") + for (let index1 = 0; index1 < temp3.length; index1++) { + targettemp += "." + temp3[index1] + ","; + } + targetfilter.push(targettemp) + } + } + + documentSelectOptions.fileSuffixFilters = targetfilter; + documentSelectOptions.authMode = false; + documentSelectOptions.mergeMode = picker.MergeTypeMode.DEFAULT; + documentSelectOptions.isEncryptionSupported = false; + + let uris: string[] = []; + let contextt = context.getHostContext() as common.UIAbilityContext; + const documentViewPicker = new picker.DocumentViewPicker(contextt); + documentViewPicker.select(documentSelectOptions).then((documentSelectResult: Array) => { + uris = documentSelectResult; + sdl.sdlDialogClearSelection() + for (let idx = 0; idx < uris.length; idx++) + { + let target = uris[idx].replace("file://docs", "") + sdl.sdlDialogFileSelected(target) + console.info('documentViewPicker.select to file succeed and uris are: ' + target); + } + sdl.sdlDialogExecCallback() + }).catch((err: BusinessError) => { + console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`); + }) + } + + getInternalPath(): string { + let contextt = context.getHostContext() as common.UIAbilityContext + return contextt.filesDir + } + + themeIsDark(): number { + let contextt = context.getHostContext() as common.UIAbilityContext + return (contextt.config.colorMode == ConfigurationConstant.ColorMode.COLOR_MODE_DARK) ? 1 : 0; + } + + isPhone(): number { + return deviceInfo.deviceType == "phone" ? 1 : 0; + } +} + +let callbackRef: ArkNapiCallback = new ArkNapiCallback() + +@Entry +@Component +struct Index { + async aboutToAppear(): Promise { + context = this.getUIContext() + + sdl.sdlCallbackInit(callbackRef) + focusControl.requestFocus('mainView') + await controller.attach(true, { + inputAttribute: { + textInputType: inputMethod.TextInputType.TEXT, + enterKeyType: inputMethod.EnterKeyType.DONE + } + }); + controller.on('insertText', (text) => { + targetText += text; + sdl.sdlTextAppend(text) + }) + controller.on('deleteLeft', (i) => { + sdl.sdlTextEditing(targetText, targetText.length - 1 - i, i); + + if (targetText.length > 0) { + targetText = targetText.substring(0, targetText.length - i) + } + }) + controller.on('deleteRight', (i) => { + sdl.sdlTextEditing(targetText, 0, i); + + if (targetText.length > 0) { + targetText = targetText.substring(i, targetText.length) + } + }) + } + + build() { + Column() { + XComponent({ id: 'mainView', type: 'surface', libraryname: 'SDL3' }) + .id('mainView') + } + .onKeyEvent((keyevent) => { + sdl.sdlKeyEvent(keyevent.keyCode, keyevent.type); + }) + } +} diff --git a/ohos-project/oh-package-lock.json5 b/ohos-project/oh-package-lock.json5 index 6b264af261..35c2f794fa 100644 --- a/ohos-project/oh-package-lock.json5 +++ b/ohos-project/oh-package-lock.json5 @@ -1,28 +1,28 @@ -{ - "meta": { - "stableOrder": true, - "enableUnifiedLockfile": false - }, - "lockfileVersion": 3, - "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", - "specifiers": { - "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", - "@ohos/hypium@1.0.24": "@ohos/hypium@1.0.24" - }, - "packages": { - "@ohos/hamock@1.0.0": { - "name": "", - "version": "1.0.0", - "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", - "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har", - "registryType": "ohpm" - }, - "@ohos/hypium@1.0.24": { - "name": "", - "version": "1.0.24", - "integrity": "sha512-3dCqc+BAR5LqEGG2Vtzi8O3r7ci/3fYU+FWjwvUobbfko7DUnXGOccaror0yYuUhJfXzFK0aZNMGSnXaTwEnbw==", - "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.24.har", - "registryType": "ohpm" - } - } +{ + "meta": { + "stableOrder": true, + "enableUnifiedLockfile": false + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", + "@ohos/hypium@1.0.24": "@ohos/hypium@1.0.24" + }, + "packages": { + "@ohos/hamock@1.0.0": { + "name": "", + "version": "1.0.0", + "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "registryType": "ohpm" + }, + "@ohos/hypium@1.0.24": { + "name": "", + "version": "1.0.24", + "integrity": "sha512-3dCqc+BAR5LqEGG2Vtzi8O3r7ci/3fYU+FWjwvUobbfko7DUnXGOccaror0yYuUhJfXzFK0aZNMGSnXaTwEnbw==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.24.har", + "registryType": "ohpm" + } + } } \ No newline at end of file diff --git a/src/SDL.c b/src/SDL.c index ed27b2e64b..b6408818e6 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -61,6 +61,10 @@ #include "core/android/SDL_android.h" #endif +#ifdef SDL_PLATFORM_OHOS +#include "core/ohos/SDL_ohos.h" +#endif + #define SDL_ALL_SUBSYSTEM_FLAGS ~0U // Initialization/Cleanup routines @@ -820,7 +824,7 @@ const char *SDL_GetPlatform(void) #elif defined(__managarm__) return "Managarm"; #elif defined(SDL_PLATFORM_OHOS) - return "OpenHarmony/HarmonyOS" + return "OpenHarmony/HarmonyOS"; #else return "Unknown (see SDL_platform.h)"; #endif @@ -833,6 +837,8 @@ bool SDL_IsPhone(void) if (!SDL_IsTablet() && !SDL_IsTV()) { return true; } +#elif defined(SDL_PLATFORM_OHOS) + return OHOS_IsPhone(); #endif return false; } diff --git a/src/core/ohos/SDL_ohos.c b/src/core/ohos/SDL_ohos.c index eb140504b9..c2082467a0 100644 --- a/src/core/ohos/SDL_ohos.c +++ b/src/core/ohos/SDL_ohos.c @@ -468,6 +468,24 @@ bool OHOS_ThemeDark() return data->ret.data.i; } +bool OHOS_IsPhone() +{ + napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); + SDL_memset(data, 0, sizeof(napiCallbackData)); + data->func = "isPhone"; + data->argCount = 0; + data->type = Int; + data->returned = false; + + napi_call_threadsafe_function(napiEnv.func, data, napi_tsfn_nonblocking); + + while (!data->returned) {} + + int d = data->ret.data.i; + SDL_free(data); + return d; +} + const char* OHOS_Locale() { napiCallbackData *data = SDL_malloc(sizeof(napiCallbackData)); diff --git a/src/core/ohos/SDL_ohos.h b/src/core/ohos/SDL_ohos.h index e82b8ff376..fa2788af8b 100644 --- a/src/core/ohos/SDL_ohos.h +++ b/src/core/ohos/SDL_ohos.h @@ -1,38 +1,40 @@ -#ifndef SDL_OHOS_H -#define SDL_OHOS_H - -#include "SDL3/SDL_video.h" -#include "video/SDL_sysvideo.h" -#include - -void OHOS_windowDataFill(SDL_Window* w); -void OHOS_removeWindow(SDL_Window* w); -void OHOS_LockPage(); -void OHOS_UnlockPage(); -int OHOS_FetchWidth(); -int OHOS_FetchHeight(); - -int OHOS_MessageBox(const char* title, const char* message, int ml, int* mapping, int bl, const char * const *buttons); -const char* OHOS_Locale(); -void OHOS_OpenLink(const char* url); -bool OHOS_IsBatteryPresent(); -bool OHOS_IsBatteryCharging(); -bool OHOS_IsBatteryCharged(); -int OHOS_GetBatteryPercent(); -void OHOS_SetClipboardText(const char* data); -char* OHOS_GetStoragePath(); -bool OHOS_ThemeDark(); - -void OHOS_FileDialog(int id, const char* defpath, int allowmany, const char* filter); - -bool OHOS_IsScreenKeyboardShown(); -void OHOS_StartTextInput(); -void OHOS_StopTextInput(); - -typedef struct SDL_VideoData { - SDL_Rect textRect; - int isPaused; - int isPausing; -} SDL_VideoData; - -#endif +#ifndef SDL_OHOS_H +#define SDL_OHOS_H + +#include "SDL3/SDL_video.h" +#include "video/SDL_sysvideo.h" +#include + +void OHOS_windowDataFill(SDL_Window* w); +void OHOS_removeWindow(SDL_Window* w); +void OHOS_LockPage(); +void OHOS_UnlockPage(); +int OHOS_FetchWidth(); +int OHOS_FetchHeight(); + +int OHOS_MessageBox(const char* title, const char* message, int ml, int* mapping, int bl, const char * const *buttons); +const char* OHOS_Locale(); +void OHOS_OpenLink(const char* url); +bool OHOS_IsBatteryPresent(); +bool OHOS_IsBatteryCharging(); +bool OHOS_IsBatteryCharged(); +int OHOS_GetBatteryPercent(); +void OHOS_SetClipboardText(const char* data); +char* OHOS_GetStoragePath(); +bool OHOS_ThemeDark(); + +bool OHOS_IsPhone(); + +void OHOS_FileDialog(int id, const char* defpath, int allowmany, const char* filter); + +bool OHOS_IsScreenKeyboardShown(); +void OHOS_StartTextInput(); +void OHOS_StopTextInput(); + +typedef struct SDL_VideoData { + SDL_Rect textRect; + int isPaused; + int isPausing; +} SDL_VideoData; + +#endif From 689f00933631baf8415fd933c7122c8a8c51d504 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 24 May 2026 18:53:58 +0800 Subject: [PATCH 89/92] openharmony: fix script --- .github/workflows/create-test-plan.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/create-test-plan.py b/.github/workflows/create-test-plan.py index b043d218d5..16be2a535c 100755 --- a/.github/workflows/create-test-plan.py +++ b/.github/workflows/create-test-plan.py @@ -106,6 +106,7 @@ class JobSpec: gdk: bool = False vita_gles: Optional[VitaGLES] = None more_hard_deps: bool = False + harmony_arch: Optional[str] = None JOB_SPECS = { @@ -873,6 +874,17 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool, ctest_args job.run_tests = False job.test_pkg_config = False job.cmake_toolchain_file = "$GITHUB_WORKSPACE/build-scripts/i586-pc-msdosdjgpp.cmake" + case SdlPlatform.Harmony: + job.cmake_arguments.extend(( + f"-DOHOS_ARCH={spec.harmony_arch}", + "-DCMAKE_TOOLCHAIN_FILE=/opt/native/build/cmake/ohos.toolchain.cmake", + "-DCMAKE_PLATFORM_NO_VERSIONED_SONAME=1" + )) + job.shared_lib = SharedLibType.SO + job.static_lib = StaticLibType.A + job.run_tests = False + job.test_pkg_config = False + job.werror = False case _: raise ValueError(f"Unsupported platform={spec.platform}") From c504de4176bc851c3d06319245f6930fbe54f47f Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 24 May 2026 18:58:13 +0800 Subject: [PATCH 90/92] openharmony: fix --- .github/workflows/generic.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index 5e627bd6df..145794b71d 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -22,6 +22,8 @@ jobs: matrix: platform: ${{ fromJSON(inputs.platforms) }} steps: + - name: 'Install unzip' + runs: sudo apt install unzip - name: 'Set up MSYS2' if: ${{ matrix.platform.platform == 'msys2' }} uses: msys2/setup-msys2@v2 From b5c1ca55e2e8dfd2bc4b2fcf162e32aed1ffbb1d Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 24 May 2026 18:58:43 +0800 Subject: [PATCH 91/92] openharmony: fix --- .github/workflows/generic.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index 145794b71d..6d51495ab4 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -23,7 +23,7 @@ jobs: platform: ${{ fromJSON(inputs.platforms) }} steps: - name: 'Install unzip' - runs: sudo apt install unzip + run: sudo apt install unzip - name: 'Set up MSYS2' if: ${{ matrix.platform.platform == 'msys2' }} uses: msys2/setup-msys2@v2 From 68ae162d52de1e49aec0816a50d00f99b41b7b69 Mon Sep 17 00:00:00 2001 From: Coder2 Date: Sun, 24 May 2026 19:02:21 +0800 Subject: [PATCH 92/92] openharmony: fix --- .github/workflows/generic.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/generic.yml b/.github/workflows/generic.yml index 6d51495ab4..89cb520783 100644 --- a/.github/workflows/generic.yml +++ b/.github/workflows/generic.yml @@ -22,8 +22,6 @@ jobs: matrix: platform: ${{ fromJSON(inputs.platforms) }} steps: - - name: 'Install unzip' - run: sudo apt install unzip - name: 'Set up MSYS2' if: ${{ matrix.platform.platform == 'msys2' }} uses: msys2/setup-msys2@v2 @@ -52,13 +50,12 @@ jobs: with: arch: ${{ matrix.platform.setup-libusb-arch }} - uses: mymindstorm/setup-emsdk@v15 - - name: 'Set up Harmony toolchain' - if: ${{ matrix.platform.platform == 'harmony' }} - uses: ./.github/actions/setup-harmony-toolchain - - uses: mymindstorm/setup-emsdk@v14 if: ${{ matrix.platform.platform == 'emscripten' }} with: version: 3.1.35 + - name: 'Set up Harmony toolchain' + if: ${{ matrix.platform.platform == 'harmony' }} + uses: ./.github/actions/setup-harmony-toolchain - uses: browser-actions/setup-chrome@v2 id: setup-chrome if: ${{ matrix.platform.platform == 'emscripten' }}