1 关键字

熄屏;任意按键;唤醒屏幕

2 问题描述

设备型号:XXXXXX

系统版本:OpenHarmony 3.2 Release

代码版本:XXXXXX

问题现象:在设备熄屏状态下,操作遥控器上的任意按键,屏幕都被唤醒了。

3 问题原因

3.1 正常机制

对遥控器操作,只有在按电源键才会将熄屏的设备屏幕唤醒。

3.2 异常机制

熄屏状态下,遥控器的任意按键都会将屏幕唤醒点亮。

4 解决方案

在key事件处理将唤醒屏幕的动作进行分类处理,只对遥控器电源按键进行屏幕唤醒,对遥控器其他按键不进行唤醒处理;同时对任意触屏操作也按照遥控器key按键流程处理。

4.1 保留原有电源按键接口HandlePowerKeyUp处理

void PowerMgrService::HandlePowerKeyUp()
{
    POWER_HILOGI(FEATURE_INPUT, "Receive release powerkey");
​
    if (isDialogstatus_ || this->shutdownService_.IsShuttingDown()) {
        POWER_HILOGW(FEATURE_INPUT, "System is shutting down");
        isDialogstatus_ = false;
        return;
    }
    int64_t now = static_cast<int64_t>(time(0));
    if (this->IsScreenOn()) {
        this->SuspendDevice(now, SuspendDeviceType::SUSPEND_DEVICE_REASON_POWER_BUTTON, false);
    } else {
        this->WakeupDevice(now, WakeupDeviceType::WAKEUP_DEVICE_POWER_BUTTON, REASON_POWER_KEY);
    }
}

4.2 处理对除电源按键的其他按键接口HandleKeyEvent事件,使其在屏幕息屏下不会被唤醒

void PowerMgrService::HandleKeyEvent(int32_t keyCode)
{
    POWER_HILOGD(FEATURE_INPUT, "keyCode: %{public}d", keyCode);
    int64_t now = static_cast<int64_t>(time(0));
    if (IsScreenOn()) {
        this->RefreshActivity(now, UserActivityType::USER_ACTIVITY_TYPE_BUTTON, false);
    } 
}

4.3 对触屏事件处理,使其在屏幕息屏下不会被唤醒

void PowerMgrService::HandlePointEvent(int32_t type)
{
    POWER_HILOGD(FEATURE_INPUT, "type: %{public}d", type);
    int64_t now = static_cast<int64_t>(time(0));
    if (this->IsScreenOn()) {
        this->RefreshActivity(now, UserActivityType::USER_ACTIVITY_TYPE_ATTENTION, false);
    } 
}

5 定位过程

 

5.1 不管是触摸,键盘,还是遥控器,在事件响应类型都会在初始化中进行分类,那么先找到key事件的分类,可以看出在KeyMonitorInit 方法中,对不同类型的事件进行了不同的处理

void PowerMgrService::KeyMonitorInit()
{
    ............
    ............
    powerkeyLongPressId_ = InputManager::GetInstance()->SubscribeKeyEvent(keyOption,
        [this](std::shared_ptr<OHOS::MMI::KeyEvent> keyEvent) {
            POWER_HILOGI(FEATURE_INPUT, "Receive long press powerkey");
            handler_->SendEvent(PowermsEventHandler::SHUTDOWN_REQUEST_MSG);
    });
    if (powerkeyLongPressId_ >= 0) {
        ............
        ............
         if (!IsScreenOn()) {
             handler_->SendEvent(PowermsEventHandler::SCREEN_ON_TIMEOUT_MSG, 0, POWER_KEY_PRESS_DELAY_MS);
                }
        });
        .............
        .............
        powerkeyReleaseId_ = InputManager::GetInstance()->SubscribeKeyEvent(keyOption,
            [this](std::shared_ptr<OHOS::MMI::KeyEvent> keyEvent) {
                powerkeyPressed_ = false;
                this->HandlePowerKeyUp();
        });
​
        .............
        .............
        doubleClickId_ = InputManager::GetInstance()->SubscribeKeyEvent(keyOption,
            [this](std::shared_ptr<OHOS::MMI::KeyEvent> keyEvent) {
                .............
                this->HandleKeyEvent(keyEvent->GetKeyCode());
        });
    } else if (powerkeyLongPressId_ != ERROR_UNSUPPORT) {
        .............
        handler_->SendEvent(PowermsEventHandler::INIT_KEY_MONITOR_MSG, 0, INIT_KEY_MONITOR_DELAY_MS);
        return;
    }
    ............
    ............
}

5.2 通过HandlePowerKeyUp方法查看除了电源按键是否还有其他流程处理

void PowerMgrService::HandlePowerKeyUp()
{
    ............
    ............
    int64_t now = static_cast<int64_t>(time(0));
    if (this->IsScreenOn()) {
        this->SuspendDevice(now, SuspendDeviceType::SUSPEND_DEVICE_REASON_POWER_BUTTON, false);
    } else {
        this->WakeupDevice(now, WakeupDeviceType::WAKEUP_DEVICE_POWER_BUTTON, REASON_POWER_KEY);
    }
}

5.3 继续对HandleKeyEvent事件进行分析,可以看出任意键屏幕唤醒的原因了

void PowerMgrService::HandleKeyEvent(int32_t keyCode)
{
    ............
    ............
    else {
        if (keyCode == KeyEvent::KEYCODE_F1) {
            POWER_HILOGI(FEATURE_WAKEUP, "Wakeup by double click");
            std::string reason = "double click";
            reason.append(std::to_string(keyCode));
            this->WakeupDevice(now, WakeupDeviceType::WAKEUP_DEVICE_DOUBLE_CLICK, reason);
        } else if (keyCode >= KeyEvent::KEYCODE_0
            && keyCode <= KeyEvent::KEYCODE_NUMPAD_RIGHT_PAREN) {
            POWER_HILOGI(FEATURE_WAKEUP, "Wakeup by keyboard");
            std::string reason = "keyboard:";
            reason.append(std::to_string(keyCode));
            this->WakeupDevice(now, WakeupDeviceType::WAKEUP_DEVICE_KEYBOARD, reason);
        }
    }
}
在上面处理中,可以看出对按键KEYCODE_F1以及keyCode在KEYCODE_0和KEYCODE_NUMPAD_RIGHT_PAREN之间的事件都进行了屏幕唤醒,那么我们在处理时不需要进行唤醒即可。

5.4 继续对HandlePointEvent事件进行分析,采用了与HandleKeyEvent类似的处理方式

void PowerMgrService::HandlePointEvent(int32_t type)
{
    ............
    ............ 
    else {
        if (type == PointerEvent::SOURCE_TYPE_MOUSE) {
            std::string reason = "mouse click";
            POWER_HILOGI(FEATURE_WAKEUP, "Wakeup by mouse");
            this->WakeupDevice(now, WakeupDeviceType::WAKEUP_DEVICE_MOUSE, reason);
        }
    }
}
同上面一样的操作,不需要唤醒屏幕

5.5 那么问题来了,为何原有处理方式会特意对其他按键进行设备唤醒:原来通用的处理方式是需要任意键唤醒的,如我们的电脑在息屏下按任意键。那么针对不同的产品,使用场景要求不一样,就需要进行不同的处理。

6 知识分享

针对不同类型的多模输入设备,其实在底层都是通过key事件进行统一响应,只是针对不同的方式有不同的处理任务,同时可通过上面的按键设置对不同的按键code有更好的了解。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐