唤醒windows内嵌键盘

通过com组件与进程TabTip.exe的结合

system_tool.h

#pragma once

class SystemTool {
public:
    SystemTool &Instance();
    bool OpenScreenKeyboard();

private:
    SystemTool() = default;
    ~SystemTool() = default;
    // \brief 打开系统内置osk应用键盘
    bool OpenOSK();
    // \brief 打开系统触摸键盘
    bool OpenTabTip();
    // \brief win10判断触摸键盘是否已显示
    bool IsWin10KeyboardVisable();
    // \brief win7判断触摸键盘是否已显示
    bool IsWin7KeyboardVisable();
    // \brief 判断系统版本是否大于或等于win10 10.0.14393.0
    bool IsNewVersion();
};

 

system_tool.cpp

#include "system_tools.h"

#include <iostream>

#include <windows.h>
#include <filesystem>
#include <algorithm>
#include <initguid.h>
#include <Objbase.h>
#include <atlbase.h>

#pragma hdrstop

// 4ce576fa-83dc-4F88-951c-9d0782b4e376
DEFINE_GUID(CLSID_UIHostNoLaunch,
            0x4CE576FA, 0x83DC, 0x4f88, 0x95, 0x1C, 0x9D, 0x07, 0x82, 0xB4, 0xE3, 0x76);

// 37c994e7_432b_4834_a2f7_dce1f13b834b
DEFINE_GUID(IID_ITipInvocation,
            0x37c994e7, 0x432b, 0x4834, 0xa2, 0xf7, 0xdc, 0xe1, 0xf1, 0x3b, 0x83, 0x4b);

struct ITipInvocation : IUnknown {
    virtual HRESULT STDMETHODCALLTYPE Toggle(HWND wnd) = 0;
};

namespace {
const char* KeyboardWindowClass = "IPTip_Main_Window";
const char* WindowParentClass = "ApplicationFrameWindow";
const char* WindowClass = "Windows.UI.Core.CoreWindow";
const char* WindowCaption = "Microsoft Text Input Application";
}

SystemTool &SystemTool::Instance() {
    static SystemTool instance;
    return instance;
}

bool SystemTool::OpenScreenKeyboard() {
    return OpenTabTip();
}

bool SystemTool::OpenOSK() {
    PVOID OldValue = NULL;
    //64位系统中32位程序要访问本机system32文件夹,需取消重定向到Syswow64
    BOOL bRet = Wow64DisableWow64FsRedirection(&OldValue);
    ShellExecuteA(NULL, "open", "osk.exe", NULL, NULL, SW_SHOWNORMAL);
    if (bRet) {
        Wow64RevertWow64FsRedirection(OldValue);
        return true;
    } else {
        std::cout << "Wow64DisableWow64FsRedirection fail err code:" << GetLastError();
        return false;
    }
}

bool SystemTool::OpenTabTip() {
    if (IsWin10KeyboardVisable() || IsWin7KeyboardVisable()) {
        std::cout << "keyboard is visible";
        return true;
    }
    std::string tabTipPath = "C:\\Program Files\\Common Files\\Microsoft Shared\\ink\\TabTip.exe";
    std::error_code err;
    if (!std::experimental::filesystem::exists(tabTipPath, err)) {
        std::cout << "wrong path,err:" << err << "  path:" << tabTipPath;
        return false;
    }
    //系统版本大于win10 10.0.14393.0,需要使用com组件的接口才能将键盘界面显示出来
    if (IsNewVersion()) {
        //判断进程是否已经存在,不存在的话拉起进程即可,存在的话调用com组件
        //自行遍历进程,查询对应的进程。
        process = FindProcess("TabTip.exe", tabTipPath);
        if (process.empty()) {
            std::cout << "IsNewVisable start process TabTip.exe";
            ShellExecuteA(NULL, "open", tabTipPath.c_str(), NULL, NULL, SW_SHOWNORMAL);
            Sleep(600);//第一次启动需要等待TabTip初始化完成
        }
        if (IsWin10KeyboardVisable() || IsWin7KeyboardVisable()) {
            std::cout << "keyboard is visible";
            return true;
        }
        std::cout << "IsNewVisable show TabTip";
        CoInitialize(nullptr);
        CComPtr<ITipInvocation> _tip;
        CoCreateInstance(CLSID_UIHostNoLaunch, 0, CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER, IID_ITipInvocation, (void**)&_tip);
        if (!_tip) {
            std::cout << "tip is nullptr";
            CoUninitialize();
            return false;
        } else {
            _tip->Toggle(GetDesktopWindow());//显示触摸键盘
        }
    } else {
        //将进程TabTip.exe拉起,如果是进程存在的情况下,再次调用会直接显示键盘界面
        ShellExecuteA(NULL, "open", tabTipPath.c_str(), NULL, NULL, SW_SHOWNORMAL);
    }
    CoUninitialize();
    return true;
}

bool SystemTool::IsWin10KeyboardVisable() {
    //win10下父窗口是ApplicationFrameWindow子窗口是Windows.UI.Core.CoreWindow
    HWND parent = FindWindowExA(NULL, NULL, WindowParentClass, NULL);
    if (!parent) {
        std::cout << "without parent window:" << WindowParentClass;
        return false;
    }
    HWND wnd = FindWindowExA(parent, NULL, WindowClass, WindowCaption);
    if (!wnd) {
        std::cout << "without child window class:" << WindowClass << " caption" << WindowCaption;
        return false;
    }
    return true;
}

bool SystemTool::IsWin7KeyboardVisable() {
    HWND touchhWnd = FindWindowA(KeyboardWindowClass, NULL);
    if (!touchhWnd) {
        std::cout << "without window:" << KeyboardWindowClass;
        return false;
    }

    unsigned long style = GetWindowLong(touchhWnd, GWL_STYLE);
    // 由于有的系统在键盘不显示时候只是多返回一个WS_DISABLED这个字段。所以加一个它的判断
    std::cout << "WS_CLIPSIBLINGS " << (style & WS_CLIPSIBLINGS);
    std::cout << "WS_VISIBLE " << (style & WS_VISIBLE);
    std::cout << "WS_POPUP " << (style & WS_POPUP);
    std::cout << "WS_DISABLED " << (style & WS_VISIBLE);
    return (style & WS_CLIPSIBLINGS) && (style & WS_VISIBLE) && (style & WS_POPUP) && !(style & WS_DISABLED);
}

bool SystemTool::IsNewVersion() {
    //获取当前的系统版本,与10.0.14393.0比较
    // 自行去获取,version="10.0.19042.0"
    std::string version = "";
    std::cout << "compare version 10.0.14393,current windows version:" << version;
    auto versionList = Split(version, ".");
    int compareVersion[] = { 10, 0, 14393 };
    for (int i = 0; i < versionList.size(); ++i) {
        switch (i) {
        case 0:
        case 1:
        case 2:
            if (std::stoi(versionList[i]) > compareVersion[i]) {
                return true;
            } else if (std::stoi(versionList[i]) < compareVersion[i]) {
                return false;
            }
            break;
        case 3:
            return true;
        }
    }
    return true;
}

 

posted @ 2021-05-22 10:26  gd_沐辰  阅读(470)  评论(0编辑  收藏  举报