关于Edit控件focused状态,调用自己编写的键盘

一、涉及编写自己的自己的键盘

由于只使用英文字母跟数字等简单的字符而已,没有包括全角或者中文字符。所以直接使用跟手机的输入密码键盘一样的键盘即可。

遇到的问题:1、使用法keybd_event()的方式进行发送消息,不管发送大小写字母都是显示小写字母

                 2、键盘不能有焦点状态,否则使用的keybd_event则无法将字符发送给edit框。如果使用有焦点的状态则会导致edit控件跟我自己编写的键盘耦合性太大。

                 3、由于使用duilib的tilelayout而出现键盘的所有按键无法正常对齐。

 

解决方案:

1、使用keybd_event()则是模拟咱们在普通的键盘上的各种按键操作。要出现大写字母或者其他的"@#$%"等字符,则需要模拟键盘的输入 shift+对应的位置的字符。(这里我使用查表的方式,进行操作。当需要按shift键+其他按键才能实现的放在同一组,而另外的不许shift按键的以相同的顺序放在另一组。)(这里有一个技巧来获取每个字符对应的键值:编写一个能够获取键值的小软件,然后将每个按键的键值获取到。并通过刚才使用的查表方式对应的字符在第几个位置,从而发送该按键的键值)

 1 #pragma once
 2 
 3 namespace DuiLib {
 4 
 5     class KeyValMag
 6     {
 7     public:
 8         KeyValMag(void);
 9         ~KeyValMag(void);
10 
11         void SendMsg(int nVal);
12 
13     private:
14         int FindSiftData(char cData);
15         int FindLowData(char cData);
16     };
17 }
View Code
#include "StdAfx.h"
#include <string>
#include "KeyValMag.h"
#include <Windows.h>

#ifndef KEYEVENTF_SILENT
#define KEYEVENTF_SILENT 0
#endif

namespace DuiLib {
    KeyValMag::KeyValMag(void)
    {
    }

    KeyValMag::~KeyValMag(void)
    {
    }

    int KeyValMag::FindSiftData(char cData)
    {
        static std::string strSiftData("~!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:\"|ZXCVBNM<>?");
        for (std::string::size_type i = 0; i < strSiftData.length(); ++i)
            if (cData == strSiftData[i]) return i;
        return -1;
    }
    int KeyValMag::FindLowData(char cData)
    {
        static std::string strLowData("`1234567890-=qwertyuiop[]asdfghjkl;\'\\zxcvbnm,./ ");
        for (std::string::size_type i = 0; i < strLowData.length(); ++i)
            if (cData == strLowData[i])
                return i;
        return -1;
    }

    void KeyValMag::SendMsg( int nVal ) {
        if (nVal == 0)
            return;
        if (nVal == VK_RETURN) {
            keybd_event(VK_RETURN , 0, KEYEVENTF_SILENT, 0);
            keybd_event(VK_RETURN , 0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);
        } else if (nVal == VK_BACK) {
            keybd_event(VK_BACK , 0, KEYEVENTF_SILENT, 0);
            keybd_event(VK_BACK , 0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);
        } else {
            int nPrintIndex = FindSiftData(nVal);
            bool bUpper = false;

            if (nPrintIndex >= 0)
                bUpper = true;
            else
                nPrintIndex = FindLowData(nVal);

            if (nPrintIndex < 0)
                return;

            static unsigned char czPrintData[] = {192,49,50,51,52,53,54,55,56,57,48,189,187,81,87,69,82,84,89,85,73,79,80,219,221,65,83,68,70,71,72,74,75,76,186,222,220,90,88,67,86,66,78,77,188,190,191,32};

            if (bUpper)
                keybd_event(VK_SHIFT, 0, KEYEVENTF_SILENT, 0);
            keybd_event((UCHAR)czPrintData[nPrintIndex], 0, KEYEVENTF_SILENT, 0);
            keybd_event((UCHAR)czPrintData[nPrintIndex], 0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);
            if (bUpper)
                keybd_event(VK_SHIFT, 0, KEYEVENTF_SILENT | KEYEVENTF_KEYUP, 0);
        }
    }

}
View Code

 

2、键盘不能有焦点状态,则需要在创建这个键盘的dialog的时候设置GLW_EXSTYLE的字段WS_EX_NOACTIVATE

#pragma once
//#include <list>
/// std::list<int> MoveLst;

#include "UIlib.h"
namespace DuiLib {

    class KeyValMag;

    HWND UILIB_API ShowKeyBoard(HWND hwndParent, RECT editPos);
    void UILIB_API HideKeyBoard(HWND hwndKeyBoard);

    class UILIB_API BoardWnd : public CWindowWnd, public INotifyUI {
        friend HWND ShowKeyBoard(HWND , RECT );
    public:
        BoardWnd(HWND hwndParent, RECT editPos);
        ~BoardWnd(void);
    public:
        LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
        static RECT GetCurPos();
        //static void ShowKeyBorard(HWND hwndParent, RECT editPos);
        //static void HideKeyBoard();
    protected:
        LPCTSTR GetWindowClassName() const { return _T("KeyBoradWnd"); }
        void OnFinalMessage(HWND /*hWnd*/) {delete this;}
        void Notify(TNotifyUI& msg);
        LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
    private:
        void OnWindowInit();
        void OnBtnClose();
    private:
        void SetBtnInfo(CControlUI* pCtl, int nVal);
        void DigitCharacterKeyBoardOption();
        void AlphaDigitCharacterKeyBoardOption();
        void ShiftKeyBoardOption();
        void AlphaKeyBoard();
        void DigitKeyBoard();
        void CharacterKeyBoard();

        CControlUI* CreateOneBtn(int nWidth, int nHeight, int nVal);
        bool IsChecked(LPCTSTR strName);

    public:
        void MoveWindow2RightPos(HWND hwndParent, RECT editPos);
        void ResetWindowPos(bool bFinishBtn = false);
    private:
        //int m_lstMoveSize[3];
        //int m_nEndMoveIndex;
        //int m_nBeginMoveIndex;
        //bool m_bCloseBtnClick;
        int m_nHaveMoveUpSize;
        HWND m_hwndParent;
        RECT m_editPos;
        CPaintManagerUI m_pm;
        KeyValMag* m_pKeyValMag;

        //static BoardWnd* m_pBoardWnd;
    };
}
View Code
#include "StdAfx.h"
#include <string>
#include "BoardWnd.h"
#include "KeyValMag.h"
#include <Windows.h>

namespace DuiLib {
    int g_nShowCount = 0;

    HWND ShowKeyBoard(HWND hwndParent, RECT editPos) {
        if (g_nShowCount < 0) {
            g_nShowCount = 0;
            return NULL;
        }
        BoardWnd* pKeyBoard = new BoardWnd(hwndParent, editPos);
        pKeyBoard->Create(NULL, L"KeyBoardWnd", WS_VISIBLE, 0, BoardWnd::GetCurPos());
        pKeyBoard->ShowWindow();

        return *pKeyBoard;
    }
    void HideKeyBoard(HWND hwndKeyBoard) {
        if (hwndKeyBoard != NULL)
            ::PostMessage(hwndKeyBoard, WM_CLOSE, 0, 0);
    }

    BoardWnd::BoardWnd(HWND hwndParent, RECT editPos)
        : m_hwndParent(hwndParent), m_editPos(editPos), m_nHaveMoveUpSize(0) {
            MoveWindow2RightPos(hwndParent, editPos);
            m_pKeyValMag = new KeyValMag;
    }

    BoardWnd::~BoardWnd(void) {
        ResetWindowPos();
        delete m_pKeyValMag;
    }

    void BoardWnd::ResetWindowPos(bool bFinishBtn /*= false*/) {
        int nHaveMoveUpSize = m_nHaveMoveUpSize;
        m_nHaveMoveUpSize = 0;
        if (nHaveMoveUpSize > 0) {
            if (bFinishBtn)
                g_nShowCount = -1;
            RECT basePos;
            GetWindowRect(m_hwndParent, &basePos);

            MoveWindow(m_hwndParent, basePos.left, basePos.top+nHaveMoveUpSize, basePos.right-basePos.left, basePos.bottom-basePos.top, FALSE);

        }
    }

    LRESULT BoardWnd::OnCreate( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled ) {
        LONG styleValue = ::GetWindowLong(*this, GWL_EXSTYLE);
        styleValue &= ~WS_CAPTION;
        ::SetWindowLong(*this, GWL_EXSTYLE, styleValue | WS_EX_NOACTIVATE);

        m_pm.Init(m_hWnd);
        CDialogBuilder builder;
        std::wstring file_name = L"KeyBoard.xml";
        CControlUI* pRoot = builder.Create(file_name.c_str(), 0, NULL, &m_pm);
        ASSERT(pRoot && "Failed to parse XML");
        m_pm.AttachDialog(pRoot);
        m_pm.AddNotifier(this);

        RECT rect = BoardWnd::GetCurPos();
        SetWindowPos(m_hWnd, HWND_TOPMOST, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, SWP_SHOWWINDOW);

        return 0;

    }


    RECT BoardWnd::GetCurPos() {
        static RECT curPos = {0,272-130,480,272};
        return curPos;
    }

    void BoardWnd::Notify( TNotifyUI& msg ) {
        if (msg.sType == L"click") {
            if (msg.pSender == m_pm.FindControl(L"closebtn")) {
                OnBtnClose();
            } else {
                m_pKeyValMag->SendMsg(msg.pSender->GetTag());
            }
        } else if (msg.sType == L"windowinit") {
            OnWindowInit();
        } else if (msg.sType == L"selectchanged") {
            if (msg.pSender->GetName() == L"AlphaDigitChange")
                AlphaDigitCharacterKeyBoardOption();
            else if (msg.pSender->GetName() == L"BtnShift")
                ShiftKeyBoardOption();
            else if (msg.pSender->GetName() == L"DigitCharacterChange")
                DigitCharacterKeyBoardOption();
        }
    }

    void BoardWnd::OnWindowInit() {
        AlphaDigitCharacterKeyBoardOption();
        ShiftKeyBoardOption();
        DigitKeyBoard();
        CharacterKeyBoard();
        DigitCharacterKeyBoardOption();

        CControlUI* pCtl = m_pm.FindControl(L"BtnBackSpace");
        if (NULL != pCtl) pCtl->SetTag(VK_BACK);
        pCtl = m_pm.FindControl(L"BtnBackSpace1");
        if (pCtl!= NULL) pCtl->SetTag(VK_BACK);
        m_pm.FindControl(L"BtnReturn")->SetTag(VK_RETURN);
        m_pm.FindControl(L"BtnSpace")->SetTag(VK_SPACE);

    }

    void BoardWnd::OnBtnClose() {
        ::ShowWindow(m_hWnd, SW_HIDE);
        ResetWindowPos(true);
    }

    LRESULT BoardWnd::HandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) {
        LRESULT lRes = 0;
        BOOL bHandled = TRUE;
        switch( uMsg ) {
        case WM_CREATE:
            lRes = OnCreate(uMsg, wParam, lParam, bHandled);
            break;
        default:
            bHandled = FALSE;
            break;
        }
        if( bHandled ) return lRes;
        if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
        return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    }

    void BoardWnd::AlphaKeyBoard() {
        char alphaLine[] = {"qwertyuiopasdfghjklzxcvbnm"};
        bool bShift = IsChecked(L"BtnShift");
        int nCurAlphaIndex = 0;

        WCHAR strName[MAX_PATH];

        for (int i = 0; i < 3; ++i) {
            swprintf_s(strName, MAX_PATH, L"AlphaLine%d", i + 1);
            CHorizontalLayoutUI* pHor = (CHorizontalLayoutUI*)m_pm.FindControl(strName);
            if (NULL == pHor)
                continue;

            CControlUI* pCtl = NULL;
            int nButtonIndex = 0;
            for (int nColIndex = 0; nColIndex < pHor->GetCount(); ++nColIndex) {
                pCtl = m_pm.FindSubControlByClass(pHor, L"ButtonUI", nButtonIndex);
                if (pCtl == NULL)
                    break;
                ++nButtonIndex;
                if (!pCtl->GetName().IsEmpty())
                    continue;
                if (pCtl == NULL)
                    pHor->Add(CreateOneBtn(40, 26, alphaLine[nCurAlphaIndex++] - (bShift?('a'-'A'):0)));
                else
                    SetBtnInfo(pCtl, alphaLine[nCurAlphaIndex++] - (bShift?('a'-'A'):0));
            }
        }
    }

    void BoardWnd::SetBtnInfo(CControlUI* pCtl, int nVal) {
        WCHAR strVal[MAX_PATH];
        pCtl->SetTag(nVal);
        swprintf_s(strVal, MAX_PATH, L"%c", nVal);
        pCtl->SetText(strVal);
    }

    void BoardWnd::DigitKeyBoard() {
        char digitLine[] = {"1234567890-/:;()$&@\".,?!'"};

        int nCurDigitIndex = 0;

        WCHAR strName[MAX_PATH];

        for (int i = 0; i < 3; ++i) {
            swprintf_s(strName, MAX_PATH, L"DigitLine%d", i + 1);
            CHorizontalLayoutUI* pHor = (CHorizontalLayoutUI*)m_pm.FindControl(strName);
            if (NULL == pHor)
                continue;

            CControlUI* pCtl = NULL;
            for (int nColIndex = 0; nColIndex < pHor->GetCount(); ++nColIndex) {
                pCtl = m_pm.FindSubControlByClass(pHor, L"ButtonUI", nColIndex);
                if (pCtl == NULL)
                    pHor->Add(CreateOneBtn(i == 2?60:40, 26, digitLine[nCurDigitIndex++]));
                else
                    SetBtnInfo(pCtl, digitLine[nCurDigitIndex++]);
            }
        }
    }


    void BoardWnd::CharacterKeyBoard() {
        char characterLine[] = {"[]{}#%^*+=_\\|~<>$$$$"};

        int nCurCharacterIndex = 0;

        WCHAR strName[MAX_PATH];

        for (int i = 0; i < 2; ++i) {
            swprintf_s(strName, MAX_PATH, L"Character%d", i + 1);
            CHorizontalLayoutUI* pHor = (CHorizontalLayoutUI*)m_pm.FindControl(strName);
            if (NULL == pHor)
                continue;

            CControlUI* pCtl = NULL;
            for (int nColIndex = 0; nColIndex < pHor->GetCount(); ++nColIndex) {
                pCtl = m_pm.FindSubControlByClass(pHor, L"ButtonUI", nColIndex);
                if (pCtl == NULL)
                    pHor->Add(CreateOneBtn(40, 26, characterLine[nCurCharacterIndex++]));
                else
                    SetBtnInfo(pCtl, characterLine[nCurCharacterIndex++]);
            }
        }
    }

    CControlUI* BoardWnd::CreateOneBtn(int nWidth, int nHeight, int nVal ) {
        WCHAR strVal[MAX_PATH];
        CButtonUI* pBtn = new CButtonUI;
        pBtn->SetFixedHeight(nHeight);
        pBtn->SetFixedWidth(nWidth);
        pBtn->SetTag(nVal);
        swprintf_s(strVal, MAX_PATH, L"%c", nVal);
        pBtn->SetText(strVal);
        pBtn->SetAttribute(L"textcolor", L"#FF000000");
        pBtn->SetAttribute(L"align", L"center");
        pBtn->SetAttribute(L"normalimage", L"file='keyboardNormal.png' corner='8,8,8,8'");
        pBtn->SetAttribute(L"focusedimage", L"file='keyboardHot.png' corner='8,8,8,8'");
        pBtn->SetAttribute(L"pushedimage", L"file='keyboardPush.png' corner='8,8,8,8'");
        return pBtn;
    }

    bool BoardWnd::IsChecked( LPCTSTR strName ) {
        COptionUI* pOption = (COptionUI*)m_pm.FindControl(strName);
        return pOption->IsSelected();
    }

    void BoardWnd::DigitCharacterKeyBoardOption() {
        COptionUI* pOption = (COptionUI*)m_pm.FindControl(L"DigitCharacterChange");
        if (pOption == NULL)
            return;

        std::wstring strText = pOption->IsSelected()?L"123":L"#+=";
        pOption->SetText(strText.c_str());

        CControlUI* pCtl = m_pm.FindControl(L"DigitKeyBoard");
        pCtl->SetVisible(!pOption->IsSelected());
        pCtl = m_pm.FindControl(L"CharacterKeyBoard");
        pCtl->SetVisible(pOption->IsSelected());
    }

    void BoardWnd::AlphaDigitCharacterKeyBoardOption() {
        COptionUI* pOption = (COptionUI*)m_pm.FindControl(L"AlphaDigitChange");
        if (pOption == NULL)
            return;

        std::wstring strText = pOption->IsSelected()?L"ABC":L".?123";
        pOption->SetText(strText.c_str());

        CControlUI* pCtl = m_pm.FindControl(L"AlphaKeyBoard");
        pCtl->SetVisible(!pOption->IsSelected());
        pCtl = m_pm.FindControl(L"DigitCharacterKeyBoard");
        pCtl->SetVisible(pOption->IsSelected());
    }

    void BoardWnd::ShiftKeyBoardOption() {
        COptionUI* pOption = (COptionUI*)m_pm.FindControl(L"BtnShift");
        if (pOption == NULL)
            return;
        if (pOption->IsSelected())
            pOption->SetText(L"SHIFT");
        else
            pOption->SetText(L"shift");


        AlphaKeyBoard();
    }

    void BoardWnd::MoveWindow2RightPos(HWND hwndParent, RECT editPos) {
        RECT curKeyBoardRect = BoardWnd::GetCurPos();
        m_editPos = editPos;
        m_hwndParent = hwndParent;

        if (editPos.bottom <= curKeyBoardRect.top)
            return;

        int nWouldMoveHeight = editPos.bottom - curKeyBoardRect.top;
        if (editPos.top - nWouldMoveHeight < 30)
            nWouldMoveHeight -= 30;

        m_nHaveMoveUpSize = nWouldMoveHeight;
        if (nWouldMoveHeight < 0)
            return;

        RECT basePos;
        GetWindowRect(m_hwndParent, &basePos);

        MoveWindow(m_hwndParent, basePos.left, basePos.top-nWouldMoveHeight, basePos.right-basePos.left, basePos.bottom-basePos.top, FALSE);
    }
}
View Code

 

3、经过研究tilelayout跟horizontallayout的源码发现tilelayout的布局方式跟horizontallayout的布局计算方式不一样(SetPos函数),而导致了使用tilelayout布局方式出现无法正常对其的方式。(该计算方式应该是tilelayout的计算思路有问题导致的)。 最后使用了horizontalalyout的简单布局方式进行操作。

 

二、如何让edit控件获取到焦点的时候,调用我的键盘

我的软件使用的是duilib界面库,则当CEditUI获取到焦点的时候会创建CEditWnd,该类是创建原生态的Edit。当CEditUI失去焦点的时候就会销毁CEditWnd类,从而销毁临时创建的原生态Edit。所以很简单的思路就是在构造函数里调用我的键盘,在析构函数里面销毁我的键盘。

而在构造函数里面没有对应的CEditUI该窗口所对应的dialog句柄,所以修改了CEditWnd的源码

从 void Init(CEditUI* pOwner)该pOwner参数提到构造函数CEditWnd(CEditUI* pOwner)

从而可以简单的实现了键盘的调用跟对键盘的使用。

 

CEditWnd::CEditWnd(CEditUI* pOwner) : m_pOwner(pOwner), m_hBkBrush(NULL)//, m_nHaveMoveUpSize(0)
{
    if (!m_pOwner->IsReadOnly() && m_pOwner->IsEnabled()) {
        RECT pos = m_pOwner->GetPos();
        POINT pt = {pos.left, pos.top};
        ClientToScreen(m_pOwner->m_pManager->GetPaintWindow(), &pt);
        OffsetRect(&pos, 0, pt.y - pos.top);
        m_hwndKeyBoard = ShowKeyBoard(m_pOwner->m_pManager->GetPaintWindow(), pos);
    }
}

CEditWnd::~CEditWnd() {
    if (!m_pOwner->IsReadOnly() && m_pOwner->IsEnabled())
        HideKeyBoard(m_hwndKeyBoard);
}
View Code

 

三、因为我使用的是下位机wince的移动设备,从而导致的一个现象是:当edit在屏幕靠下的地方时,键盘会挡住edit

需要解决的第一个办法是让用户手动移动键盘,这样子就能看到对应edit控件。但是这样子用户体验不好。

所以使用了另一种方式:当键盘把edit挡住的时候,软件自动上移,以防挡住edit。(这里遇到上移时候,刚开始调试时候出现了直接失去焦点的现象,具体原因是什么,怎样解决的,突然忘记了。。。)。

四、有时候用户在获得键盘之后,输入完成了,不想让键盘失去焦点,只想让键盘消失。则我在键盘上面做了一个失去点击隐藏键盘的按钮之后使键盘消失。但是焦点还在edit上面

需要解决的是:当点击隐藏按钮之后,会出现edit也失去焦点了(因为软件下移过程中导致失去了焦点,具体原因忘记了/qiao),当移动完成之后则edit会重新获得焦点,而重新调用键盘。所以我这里做了一个小聪明的技巧:放置一个全局的计数。当点击隐藏按钮时属于异常情况所以设置该计数小于零,当程序再次进来要调用键盘按钮的时候,设回该变量的初始状态,然后直接返回而不去显示键盘。

 

ps:因为某些原因,只写出了对应的设计思路。并且前段时间比较忙而没有记录对应的出现问题,而出现断片。。。,所以有的问题的原因忘记了。

但是使用该最终的思路还是可以正常的做出键盘调用。和键盘制作。

posted @ 2015-12-16 19:55  CY_K_YC  阅读(963)  评论(0编辑  收藏  举报