Quản lý Bảng Nhập Liệu Mềm trong Ứng Dụng Windows CE

Bảng nhập liệu mềm (Software Input Panel - SIP) là thành phần thiết yếu trên các thiết bị chạy Windows CE, cho phép người dùng nhập dữ liệu qua giao diện bàn phím ảo. Khi làm việc với SIP, có hai khía cạnh chính: phát triển SIP và tích hợp SIP vào ứng dụng. Bài viết này tập trung vào việc điều khiển SIP từ bên trong ứng dụng của bạn.

SIP được hiện thực dưới dạng đối tượng COM tuân thủ giao diện IInputMethod hoặc IInputMethod2. Do giới hạn nền tảng, SIP không thể phát triển bằng C# mà nên dùng C/C++ kết hợp với ATL để đơn giản hóa quá trình. Tuy nhiên, SDK của Windows CE đã cung cấp ví dụ mẫu ATLDvoraksip — bạn có thể tham khảo để tìm hiểu cách tạo SIP tùy chỉnh.

Các API Win32 liên quan đến SIP

Các hàm điều khiển SIP nằm trong file sipapi.h, bao gồm:

DWORD WINAPI SipStatus();
BOOL WINAPI SipSetDefaultRect(RECT *);
BOOL WINAPI SipRegisterNotification(HWND);
BOOL WINAPI SipShowIM(DWORD);
BOOL WINAPI SipGetInfo(SIPINFO *);
BOOL WINAPI SipSetInfo(SIPINFO *);
int WINAPI SipEnumIM(IMENUMPROC);
BOOL WINAPI SipGetCurrentIM(CLSID *);
BOOL WINAPI SipSetCurrentIM(CLSID *);

Những hàm này tương thích cả với Windows Mobile và Windows CE .NET. Ngoài ra, nếu nhắm đến Windows Mobile, bạn có thể dùng các hàm mở rộng từ aygshell.h như SHSipPreference hoặc SHSipInfo để có nhiều tùy chọn hơn.

Liệt kê các SIP khả dụng

Để lấy danh sách SIP đã cài đặt, sử dụng hàm SipEnumIM kèm theo callback xử lý thông tin từng phương pháp nhập:

CTypedPtrMap<CMapStringToPtr, CString, CLSID*> g_SipRegistry;

int CALLBACK EnumSipCallback(IMENUMINFO* pInfo)
{
    if (!pInfo) return 0;
    CLSID* pId = new CLSID(pInfo->clsid);
    g_SipRegistry.SetAt(CString(pInfo->szName), pId);
    return 1;
}

void EnumerateAvailableSIPs()
{
    SipEnumIM(EnumSipCallback);
}

Ví dụ trên lưu trữ tên SIP và định danh lớp (CLSID) tương ứng vào một map toàn cục để sử dụng sau.

Chọn và điều khiển hiển thị SIP

Khi đã có CLSID của SIP mong muốn, bạn có thể kích hoạt nó và điều khiển trạng thái hiển thị:

void ActivateSelectedSIP(const CString& sipName)
{
    CLSID* pClsid = nullptr;
    if (g_SipRegistry.Lookup(sipName, pClsid))
        SipSetCurrentIM(pClsid);
}

void ToggleSipVisibility(bool show)
{
    SipShowIM(show ? SIPF_ON : SIPF_OFF);
}

Lưu ý: khi dùng SipGetInfo hoặc SipSetInfo, luôn khởi tạo trường cbSize của cấu trúc SIPINFO bằng sizeof(SIPINFO) để đảm bảo tương thích.

Điều chỉnh vị trí SIP

Hàm SipSetDefaultRect cho phép đặt lại vùng mặc định của SIP, nhưng thay đổi chỉ có hiệu lực sau khi đổi phương pháp nhập hoặc gọi lại SipShowIM:

void RepositionSIP(int offsetX, int offsetY)
{
    SIPINFO info = {0};
    info.cbSize = sizeof(SIPINFO);
    if (SipGetInfo(&info))
    {
        CRect rc(info.rcSipRect);
        rc.OffsetRect(offsetX, offsetY);
        SipSetDefaultRect(&rc);

        // Áp dụng lại SIP hiện tại để cập nhật vị trí
        CLSID current;
        if (SipGetCurrentIM(&current))
            SipSetCurrentIM(&current);
    }
}

Kỹ thuật này hữu ích khi bạn cần tránh SIP che khuất các điều khiển quan trọng ở phía dưới màn hình.

Tự động bật/tắt SIP theo tiêu điểm nhập liệu

Để cải thiện trải nghiệm người dùng, bạn có thể tự động hiển thị SIP khi ô nhập liệu nhận tiêu điểm và ẩn đi khi mất tiêu điểm. Với MFC, điều này được thực hiện qua xử lý thông điệp WM_SETFOCUSWM_KILLFOCUS:

void CSmartEdit::OnSetFocus(CWnd* pOldWnd)
{
    CEdit::OnSetFocus(pOldWnd);
    SHSipPreference(m_hWnd, SIP_UP);
}

void CSmartEdit::OnKillFocus(CWnd* pNewWnd)
{
    CEdit::OnKillFocus(pNewWnd);
    SHSipPreference(m_hWnd, SIP_FORCEDOWN);
}

Phương pháp này đặc biệt hiệu quả trên các thiết bị cảm ứng nơi người dùng kỳ vọng bàn phím xuất hiện ngay khi chạm vào trường nhập.

Gợi ý khi dùng hàm Shell trên Windows Mobile

Khi xử lý thông điệp WM_SETTINGCHANGE, hãy cẩn trọng nếu gọi SHSipInfo vì có thể gây vòng lặp vô hạn hoặc làm chậm hệ thống do tương tác với tiến trình device.exe. Luôn kiểm tra giá trị lParam để xác định liệu sự thay đổi có liên quan đến SIP hay không trước khi phản hồi.

Thẻ: Windows CE SIP Win32 API MFC Windows Mobile

Đăng vào ngày 2 tháng 6 lúc 20:14