【问题标题】:Simulate keyboard input inside app in C++ MFC app在 C++ MFC 应用程序中模拟应用程序内的键盘输入
【发布时间】:2017-06-14 13:37:06
【问题描述】:

我创建了一个对话框MainDialog.cpp,其中包含2 个编辑控件,其ID 为IDC_EDITCONTROL_A 和IDC_EDITCONTROL_B,变量分别定义为m_editControlA 和m_editControlB。

另外,我有 2 个按钮,它们的 ID 分别是 IDC_MFCBUTTON_KEY_X 和 IDC_MFCBUTTON_KEY_Y,变量分别是 m_buttonKeyX 和 m_buttonKeyY。

以下是源文件中的代码

#include "afxdialogex.h" 

IMPLEMENT_DYNAMIC(CMainDialog, CDialogEx)

CMainDialog::CMainDialog(CWnd* pParent): CDialogEx(IDD_MAIN_DIALOG, pParent)
{
}

CMainDialog::~CMainDialog()
{
}

void CMainDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_EDITCONTROL_A, m_editControlA);
    DDX_Control(pDX, IDC_EDITCONTROL_B, m_editControlB);
    DDX(Control(pDX, IDC_MFCBUTTON_KEY_X, m_buttonKeyX);
    DDX(Control(pDX, IDC_MFCBUTTON_KEY_Y, m_buttonKeyY);
}

BEGIN_MESSAGE_MAP(CMainDialog, CDialogEx)
    ON_EN_CHANGE(IDC_EDITCONTROL, &CMainDialog::OnEnChangeEditA)
    ON_BN_CLICKED(IDC_MFCBUTTON_KEY_X, &CMainDialog::OnBnClickedButtonX)
    ON_BN_CLICKED(IDC_MFCBUTTON_KEY_Y, &CMainDialog::OnBnClickedButtonY)
END_MESSAGE_MAP()

void CMainDialog::OnBnClickedButtonX()
{
    m_editControlA.SetWindowTextW(_T("X"));  // test
}

void CMainDialog::OnBnClickedButtonX()
{
    m_editControlA.SetWindowTextW(_T("Y"));  // test
}

我试图了解如何让每个按钮发送它们各自的字符(即在此示例中为X 或Y)到选定的编辑控件如果选择了一个。本质上,我想模拟键盘输入。

我已阅读有关 how to simulate keyboard events 和 sendMessage 的文档,但由于我的 C++ 知识非常基础,我无法理解如何实现它。另外,按照我的previous question,我发现GetFocus 会很有用,但我目前的主要问题仍然是发送输入。

任何示例代码或有用的链接都可能对我了解如何在应用程序中模拟键盘输入非常有用。

【问题讨论】:

  • 问题是当按钮被按下时编辑控件会失去焦点。您上一个问题的评论者已经提出了一些如何解决这个问题的建议。另一个想法:用具有SS_NOTIFY 样式的静态控件替换按钮。默认情况下静态不接收焦点。
  • 模拟键盘事件可能是错误的方法。您实际上试图解决哪个问题?这看起来像 XY Problem

标签: c++ visual-studio-2015 mfc


【解决方案1】:

使用 WM_CHAR 消息将字符从操作系统发送到编辑控件。

实际上它比这要复杂一些,但是您不需要模拟整个 WM_KEYUP WM_KEYDOWN 消息序列,因为它的最终结果是生成 WM_CHAR 消息。

您可以使用 CWnd::PostMessage 将字符直接发送到您的编辑控件,即使它们没有焦点。

您可能已经在此处找到了 WM_CHAR 的文档:https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms646276(v=vs.85).aspx

哎呀..对不起,我的法语,英文文档在这里 https://msdn.microsoft.com/en-us/library/windows/desktop/ms646276(v=vs.85).aspx

(只需将 fr-fr 更改为 en-us 就可以了,它可能适用于所有其他语言,整洁!

  • wParam 包含您要发送的字符。可以是纯 ASCII 字符,也可以是 VK_ 常量之一……我建议您使用 unicode 版本的 WM_CHARW,因为现在大多数 Windows 软件都使用 unicode。宽字符的表示法是 L'X' 或 _T('X'),unicode (UTF-16) 字符类型是 wchar_t。

  • lParam 包含其他击键细节,0 应该可以满足您的需求。

要发送 X,只需调用

 m_editControlA.PostMessage(WM_CHAR, _T('X'));  

使用 _T() 表示法时,括号之间的字符(或字符串)文字将自动转换为您应用的 unicode 设置的正确字符宽度(您应该将其设置为 UNICODE,因为这是操作系统使用的,并且也是 Windows CE 的唯一有效编码,例如,您应该习惯于操作这种类型。

几乎所有对字符串进行操作的 C 库函数的 _T() 宏和 _t* 覆盖都在 tchar.h 中定义,Visual Studio 将其包含在 stdafx.h 中。在 MFC 下,您将主要使用 CString,但最好知道这些东西在哪里。

[EDIT] 当你开始运行时,你应该开始使用 WM_KEYDOWN。您会发现 PostMessage(WM_CHAR, VK_ESCAPE) 直接发送到您的对话框不会关闭它,而 PostMessage(WM_KEYDOWN, VK_ESCAPE) 可以。并且 m_editBox.PostMessage(WM_KEYDOWN, _T('X')) 将向您的编辑框发送一个较低的键 'x'。但这是另一个需要调查的话题。

玩得开心!

最后一个问题:

当然,但它会变得有点复杂,因为你的按钮会在你点击它时获得焦点。您必须为每个编辑框创建 EN_SETFOCUS 处理程序,并添加一个 CWnd* 数据成员来跟踪最后一个具有焦点的编辑框。

您的 EN_SETFOCUS 处理程序应如下所示

void CdlgDlg::OnEnSetfocusEdit1()
{ 
    m_pWndLastFocus = &m_edit1;
}

不要忘记在构造函数中将指针设置为 NULL,并在调用 m_pWndLastFocus->PostMessage() 之前检查它是否有效。

【讨论】:

  • 我忘了说windows headers会根据你应用的UNICODE设置选择正确的WM_CHAR版本,WM_CHARA或WM_CHARW。
  • 感谢您的详细回复!有没有办法实现您的 PostMessage 方法,但不一定将其绑定到特定的编辑控件?换句话说,当我按下 X 键时,我只想将X 发送到恰好处于焦点的那个编辑控件。
  • 当然,但它变得有点复杂,因为你的按钮将获得焦点,只要你点击它。您必须为每个编辑框创建 EN_SETFOCUS 处理程序,并添加一个 CWnd* 数据成员来跟踪最后一个具有焦点的编辑框。
  • 查看答案了解详情。
  • 所以,如果我理解正确,我会将最后一个焦点对话框存储在 m_pWndLastFocus 中,当按下 X 键时,我会让它获取 m_pWndLastFocus 以便它可以写入,对吗?
【解决方案2】:

在 MFC 中合成输入的方法是使用SendInput 方法。

【讨论】:

    猜你喜欢
    • 2012-02-04
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    相关资源
    最近更新 更多