Skip to content

Cocos2d x 4.0 #20892

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 19 additions & 100 deletions cocos/platform/ohos/CCGLViewImpl-ohos.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,110 +110,29 @@ void GLViewImpl::setIMEKeyboardState(bool bOpen) {
}

Rect GLViewImpl::getSafeAreaRect() const {
Rect safeAreaRect = GLView::getSafeAreaRect();
float deviceAspectRatio = 0;
if(safeAreaRect.size.height > safeAreaRect.size.width) {
deviceAspectRatio = safeAreaRect.size.height / safeAreaRect.size.width;
} else {
deviceAspectRatio = safeAreaRect.size.width / safeAreaRect.size.height;
}

float marginX = DEFAULT_MARGIN_OHOS / _scaleX;
float marginY = DEFAULT_MARGIN_OHOS / _scaleY;
bool isScreenRound;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.isRoundScreen")) {
isScreenRound = function->Invoke<bool>();
Rect safeAreaRect1;
int left;
if (auto getSafeAreaLeft = aki::JSBind::GetJSFunction("DeviceUtils.getSafeAreaLeft")) {
left = getSafeAreaLeft->Invoke<int>();
}
bool hasSoftKeys;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.hasSoftKeys")) {
hasSoftKeys = function->Invoke<bool>();
int top;
if (auto getSafeAreaTop = aki::JSBind::GetJSFunction("DeviceUtils.getSafeAreaTop")) {
top = getSafeAreaTop->Invoke<int>();
}
bool isCutoutEnabled;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.isCutoutEnable")) {
isCutoutEnabled = function->Invoke<bool>();
}

if(isScreenRound) {
// edge screen
if(safeAreaRect.size.width < safeAreaRect.size.height) {
safeAreaRect.origin.y += marginY * 2.f;
safeAreaRect.size.height -= (marginY * 2.f);

safeAreaRect.origin.x += marginX;
safeAreaRect.size.width -= (marginX * 2.f);
} else {
safeAreaRect.origin.y += marginY;
safeAreaRect.size.height -= (marginY * 2.f);

// landscape: no changes with X-coords
}
} else if (deviceAspectRatio >= WIDE_SCREEN_ASPECT_RATIO_OHOS) {
// almost all devices on the market have round corners
float bottomMarginIfPortrait = 0;
if(hasSoftKeys) {
bottomMarginIfPortrait = marginY * 2.f;
}

if(safeAreaRect.size.width < safeAreaRect.size.height) {
// portrait: double margin space if device has soft menu
safeAreaRect.origin.y += bottomMarginIfPortrait;
safeAreaRect.size.height -= (bottomMarginIfPortrait + marginY);
} else {
// landscape: ignore double margin at the bottom in any cases
// prepare signle margin for round corners
safeAreaRect.origin.y += marginY;
safeAreaRect.size.height -= (marginY * 2.f);
}
} else {
if(hasSoftKeys && (safeAreaRect.size.width < safeAreaRect.size.height)) {
// portrait: preserve only for soft system menu
safeAreaRect.origin.y += marginY * 2.f;
safeAreaRect.size.height -= (marginY * 2.f);
}
int width;
if (auto getSafeAreaWidth = aki::JSBind::GetJSFunction("DeviceUtils.getSafeAreaWidth")) {
width = getSafeAreaWidth->Invoke<int>();
}

if (isCutoutEnabled) {
// screen with enabled cutout area

int orientation;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.getOrientation")) {
orientation = function->Invoke<int>();
}

if(static_cast<int>(GLViewImpl::Orientation::PORTRAIT) == orientation) {
int result;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.getCutoutHeight")) {
result = function->Invoke<int>();
}
double height = result / _scaleY;
safeAreaRect.origin.y += height;
safeAreaRect.size.height -= height;
} else if(static_cast<int>(GLViewImpl::Orientation::PORTRAIT_INVERTED) == orientation) {
int result;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.getCutoutHeight")) {
result = function->Invoke<int>();
}
double height = result / _scaleY;
safeAreaRect.size.height -= height;
} else if(static_cast<int>(GLViewImpl::Orientation::LANDSCAPE) == orientation) {
int result;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.getCutoutWidth")) {
result = function->Invoke<int>();
}
double width = result / _scaleX;
safeAreaRect.size.width -= width;
} else if(static_cast<int>(GLViewImpl::Orientation::LANDSCAPE_INVERTED) == orientation) {
int result;
if (auto function = aki::JSBind::GetJSFunction("DeviceUtils.getCutoutWidth")) {
result = function->Invoke<int>();
}
double width = result / _scaleX;
safeAreaRect.origin.x += width;
safeAreaRect.size.width -= width;
}
int height;
if (auto getSafeAreaHeight = aki::JSBind::GetJSFunction("DeviceUtils.getSafeAreaHeight")) {
height = getSafeAreaHeight->Invoke<int>();
}

return safeAreaRect;
safeAreaRect1.origin.x = left / _scaleX;
safeAreaRect1.origin.y = top / _scaleY;
safeAreaRect1.size.width = width / _scaleX;
safeAreaRect1.size.height = height / _scaleX;
OHOS_LOGD("GLViewImpl getsafeAreaRect1, x:%{public}f, y:%{public}f, width:%{public}f, height:%{public}f", safeAreaRect1.origin.x, safeAreaRect1.origin.y, safeAreaRect1.size.width, safeAreaRect1.size.height);
return safeAreaRect1;
}
NS_CC_END

Expand Down
3 changes: 0 additions & 3 deletions cocos/platform/ohos/napi/helper/Js_Cocos2dxHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ napi_value Js_Cocos2dxHelper::initJsCocos2dxHelper(napi_env env, napi_callback_i
* If you have more information that can be obtained asynchronously, add it here.
*/
napi_value Js_Cocos2dxHelper::initAsyncInfo(napi_env env, napi_callback_info info) {
if (auto initScreenInfo = aki::JSBind::GetJSFunction("DeviceUtils.initScreenInfo")) {
initScreenInfo->Invoke<void>();
}
return nullptr;
}

Expand Down
26 changes: 22 additions & 4 deletions cocos/platform/ohos/napi/render/plugin_render.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <ace/xcomponent/native_xcomponent_key_event.h>
#include <stdint.h>
#include <unistd.h>

Expand Down Expand Up @@ -32,7 +33,7 @@ float mousePositionY = -1;
bool isMouseLeftActive = false;
double scrollDistance = 0;

std::unordered_map<int, cocos2d::EventKeyboard::KeyCode> ohKeyMap = {
const std::unordered_map<OH_NativeXComponent_KeyCode, cocos2d::EventKeyboard::KeyCode> ohKeyMap = {
{KEY_ESCAPE, cocos2d::EventKeyboard::KeyCode::KEY_ESCAPE},
{KEY_GRAVE, cocos2d::EventKeyboard::KeyCode::KEY_GRAVE},
{KEY_MINUS, cocos2d::EventKeyboard::KeyCode::KEY_MINUS},
Expand Down Expand Up @@ -62,7 +63,23 @@ std::unordered_map<int, cocos2d::EventKeyboard::KeyCode> ohKeyMap = {
{KEY_DPAD_UP, cocos2d::EventKeyboard::KeyCode::KEY_DPAD_UP},
{KEY_SYSRQ, cocos2d::EventKeyboard::KeyCode::KEY_PRINT},
{KEY_INSERT, cocos2d::EventKeyboard::KeyCode::KEY_INSERT},
{KEY_FORWARD_DEL, cocos2d::EventKeyboard::KeyCode::KEY_DELETE}
{KEY_FORWARD_DEL, cocos2d::EventKeyboard::KeyCode::KEY_DELETE},
{KEY_SCROLL_LOCK, cocos2d::EventKeyboard::KeyCode::KEY_SCROLL_LOCK},
{KEY_MINUS, cocos2d::EventKeyboard::KeyCode::KEY_MINUS},
{KEY_AT, cocos2d::EventKeyboard::KeyCode::KEY_AT},
{KEY_PLUS, cocos2d::EventKeyboard::KeyCode::KEY_PLUS},
{KEY_MENU, cocos2d::EventKeyboard::KeyCode::KEY_MENU},
{KEY_BREAK, cocos2d::EventKeyboard::KeyCode::KEY_PAUSE},
{KEY_MOVE_HOME, cocos2d::EventKeyboard::KeyCode::KEY_HOME},
{KEY_MOVE_END, cocos2d::EventKeyboard::KeyCode::KEY_END},
{KEY_PAGE_UP, cocos2d::EventKeyboard::KeyCode::KEY_PG_UP},
{KEY_PAGE_DOWN, cocos2d::EventKeyboard::KeyCode::KEY_PG_DOWN},
{KEY_NUMPAD_ADD, cocos2d::EventKeyboard::KeyCode::KEY_KP_PLUS},
{KEY_NUMPAD_SUBTRACT, cocos2d::EventKeyboard::KeyCode::KEY_KP_MINUS},
{KEY_NUMPAD_MULTIPLY, cocos2d::EventKeyboard::KeyCode::KEY_KP_MULTIPLY},
{KEY_NUMPAD_DIVIDE, cocos2d::EventKeyboard::KeyCode::KEY_KP_DIVIDE},
{KEY_NUMPAD_ENTER, cocos2d::EventKeyboard::KeyCode::KEY_KP_ENTER}

};

cocos2d::EventKeyboard::KeyCode ohKeyCodeToCocosKeyCode(OH_NativeXComponent_KeyCode ohKeyCode)
Expand All @@ -82,8 +99,9 @@ cocos2d::EventKeyboard::KeyCode ohKeyCodeToCocosKeyCode(OH_NativeXComponent_KeyC
if (ohKeyCode >= KEY_A && ohKeyCode <= KEY_Z) {
// A - Z
return cocos2d::EventKeyboard::KeyCode(int(cocos2d::EventKeyboard::KeyCode::KEY_A) + (ohKeyCode - KEY_A));
}
return cocos2d::EventKeyboard::KeyCode(ohKeyCode);
}
OHOS_LOGW("Unmapped OH key code: %d", ohKeyCode);
return cocos2d::EventKeyboard::KeyCode::KEY_NONE;
}

void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
Expand Down
2 changes: 1 addition & 1 deletion tests/cpp-tests/proj.ohos/build-profile.json5
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "5.0.0(12)",
"compatibleSdkVersion": "5.0.3(15)",
"runtimeOS": "HarmonyOS"
}
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import window from '@ohos.window';
import UIAbility from '@ohos.app.ability.UIAbility';
import nativeRender from "libnativerender.so";
import { ContextType, DeviceUtils } from "@ohos/libSysCapabilities"
import { GlobalContext,GlobalContextConstants} from "@ohos/libSysCapabilities"
import { BusinessError } from '@kit.BasicServicesKit';
import Want from '@ohos.app.ability.Want';
import AbilityConstant from '@ohos.app.ability.AbilityConstant';

const nativeAppLifecycle: nativeRender.CPPFunctions = nativeRender.getContext(ContextType.APP_LIFECYCLE);
const rawFileUtils: nativeRender.CPPFunctions = nativeRender.getContext(ContextType.RAW_FILE_UTILS);

GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG, true);
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG, true);
export default class MainAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
nativeAppLifecycle.onCreate();
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_ABILITY_CONTEXT, this.context);
console.info('[LIFECYCLE-App] onCreate')
}

onDestroy() {
nativeAppLifecycle.onDestroy();
console.info('[LIFECYCLE-App] onDestroy')
}

onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
windowStage.loadContent('pages/Index', (err:BusinessError, data) => {
if (err.code) {
return;
}
rawFileUtils.nativeResourceManagerInit(this.context.resourceManager);
rawFileUtils.writablePathInit(this.context.filesDir);
});

windowStage.getMainWindow().then((windowIns: window.Window) => {
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_MAIN_WINDOW, windowIns);
// Set whether to display the status bar and navigation bar. If they are not displayed, [] is displayed.
let systemBarPromise = windowIns.setWindowSystemBarEnable([]);
// Whether the window layout is displayed in full screen mode
let fullScreenPromise = windowIns.setWindowLayoutFullScreen(true);
// Sets whether the screen is always on.
let keepScreenOnPromise = windowIns.setWindowKeepScreenOn(true);
Promise.all([systemBarPromise, fullScreenPromise, keepScreenOnPromise]).then(() => {
console.info('Succeeded in setting the window');
}).catch((err: BusinessError) => {
console.error('Failed to set the window, cause ' + JSON.stringify(err));
});

try {
DeviceUtils.calculateSafeArea(windowIns.getWindowAvoidArea(window.AvoidAreaType.TYPE_CUTOUT), windowIns.getWindowProperties().windowRect);
windowIns.on('avoidAreaChange', (data) => {
console.info('getSafeAreaRect Succeeded in enabling the listener for system avoid area changes. type:' +
JSON.stringify(data.type) + ', area: ' + JSON.stringify(data.area));

if(data.type == window.AvoidAreaType.TYPE_SYSTEM_GESTURE || data.type == window.AvoidAreaType.TYPE_KEYBOARD) {
return;
}

let mainWindow: window.Window = GlobalContext.loadGlobalThis(GlobalContextConstants.COCOS2DX_MAIN_WINDOW);
DeviceUtils.calculateSafeArea(data.area, mainWindow.getWindowProperties().windowRect);
});
} catch (exception) {
console.error(`Failed to enable the listener for system avoid area changes. Cause code: ${exception.code}, message: ${exception.message}`);
}
})

windowStage.on("windowStageEvent", (data:window.WindowStageEventType) => {
let stageEventType: window.WindowStageEventType = data;
switch (stageEventType) {
case window.WindowStageEventType.RESUMED:
console.info('[LIFECYCLE-App] onShow_RESUMED')
if(GlobalContext.loadGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG)){
nativeAppLifecycle.onShow();
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG, false);
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG, true);
}
break;
case window.WindowStageEventType.PAUSED:
if(GlobalContext.loadGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG)){
console.info('[LIFECYCLE-App] onHide_PAUSED')
nativeAppLifecycle.onHide();
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG, false);
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG, true);
}
break;
default:
break;
}
});
}

onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
}

onForeground() {
if(GlobalContext.loadGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG)){
// Ability has brought to foreground
console.info('[LIFECYCLE-App] onShow')
nativeAppLifecycle.onShow();
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG, false);
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG, true);
}
}

onBackground() {
if(GlobalContext.loadGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG)){
// Ability has back to background
console.info('[LIFECYCLE-App] onHide')
nativeAppLifecycle.onHide();
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_HIDE_FLAG, false);
GlobalContext.storeGlobalThis(GlobalContextConstants.COCOS2DX_SHOW_FLAG, true);
}
}
};

This file was deleted.

Loading