此页面有用吗?
您对此内容的反馈非常重要。 请告诉我们您的想法。
更多反馈?
1500 个剩余字符
MSDN Library
信息
您所需的主题如下所示。但此主题未包含在此库中。

如何在 Windows Phone 8 的 Direct3D 应用中处理键盘输入

2014/6/18

仅适用于:Windows Phone 8 和 Windows Phone Silverlight 8.1

本主题向您演示如何实现自定义的文本框,在其中用户可以使用 Windows Phone Direct3D 应用 的软件输入面板 (SIP) 键盘输入文本。文本输入是几乎所有应用都需要的功能。借助 Windows Phone 托管的应用,您可以使用 TextBox 控件轻松地将文本输入添加到您的应用。遗憾的是,您不能在 Direct3D 应用 中使用 XAML 控件。但是,使用少许的代码,您可以创建能够导致 SIP 键盘显示且随着用户键入而进行更新的自定义文本框控件。

有两种方式可用于实现自定义文本框。您可以使用 KeyboardInputBuffer 类,该类将为您收集键击并提供包含当前文本的缓冲区,或者您也可以使用在用户按键的任意时刻触发的键事件。如果您使用键事件,您必须管理您自己的文本缓冲区。

IsKeyboardInputEnabled() 允许您打开和关闭 SIP 键盘的可见性,但是它不能可靠地确定当前是否显示了键盘。如果用户通过按“后退”按钮关闭键盘,那么不更新该属性的值。相反,您应侦听 Hiding 事件,用户用“后退”按钮关闭键盘时将引发该事件。您也可以随时检查 OccludedRect 属性,如果矩形的宽和高为 0,那么您即知道当前没有显示 SIP。在本演练结尾有这些技术的简要展示。

说明注意:

为帮助使这些程序简单化,在这些示例中已省略实际将文本呈现到屏幕所需的 Direct3D 代码。

使用 KeyboardInputBuffer 创建自定义的文本框

  1. 创建新的 Direct3D 项目。本示例假定您已命名项目“NativeTextInput”。

  2. 在 Visual Studio 中,转到“项目-添加类”以将新的类添加到项目。命名新的类“InputBufferTextBox”。

  3. 将以下代码粘贴到 InputBufferTextBox.h 标头文件。在此声明的所有方法和成员变量将在随后的步骤中进行介绍。

  4. 在 InputBufferTextBox.cpp 文件的顶部,在 #include 指令的下方,为文本框将使用的命名空间粘贴下面的 using 语句。

    
    using namespace Windows::Foundation;
    using namespace Windows::UI::Core;
    using namespace Windows::Phone::UI::Core;
    using namespace Windows::System;
    using namespace Platform;
    
    
    
  5. 将自定义构造函数的代码粘贴到 InputBufferTextBox.cpp。在此方法中,已分配 m_parentWindow 成员变量。此值将成为应用的 CoreWindow 实例。接下来,设置对文本框的位置和大小进行定义的成员变量,设置输入范围(决定在软件键盘中显示哪些按键)。然后,初始化 KeyboardInputBuffer 对象的实例。Text() 属性已设置为要在文本框中显示的初始文本。最后,将设置 TextChanged 事件的事件处理程序。

    
    InputBufferTextBox::InputBufferTextBox(CoreWindow^ parentWindow, int x, int y, int width, int height, String^ initialText)
    {
    	m_parentWindow = parentWindow;
    	m_x = x;
    	m_y = y;
    	m_width = width;
    	m_height = height;
    
    	m_inputBuffer = ref new KeyboardInputBuffer();
    	m_inputBuffer->Text = initialText;
    	m_inputBuffer->TextChanged += ref new TypedEventHandler<KeyboardInputBuffer^, CoreTextChangedEventArgs^>(this, &InputBufferTextBox::OnTextChanged);
    }
    
    
    
  6. 将定义 HitTest 方法的代码粘贴到 InputBufferTextBox.cpp。用户点按的屏幕坐标将传递到该方法。它只是检查触控点是否在文本框的边界内。

    
    bool InputBufferTextBox::HitTest(int x, int y)
    {
    	if(x >= m_x && x <= m_x + m_width && y >= m_y && y <= m_y + m_height)
    	{	
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    
    
  7. 将定义 SetFocus 方法的代码粘贴到 InputBufferTextBox.cpp。如果此方法是使用 true 值调用的,这意味着文本框具有焦点并且应该准备处理文本输入。若要执行此操作,将应用的 CoreWindowKeyboardInputBuffer 属性设置为文本框 KeyboardInputBuffer 成员变量,并且设置键盘的输入范围。然后,将 CoreWindowIsKeyboardInputEnabled() 属性设置为 true。这将导致 SIP 键盘进行显示。

    如果 SetFocus 是使用 false 值调用的,将 IsKeyboardInputEnabled() 设置为 false 会导致 SIP 键盘隐藏。

    
    void InputBufferTextBox::SetFocus(bool hasFocus)
    {
    	m_hasFocus = hasFocus;
    	
    	if(m_hasFocus)
    	{
    		m_parentWindow->KeyboardInputBuffer = m_inputBuffer;
    		m_parentWindow->IsKeyboardInputEnabled = true;
    	}
    	else
    	{
    		m_parentWindow->IsKeyboardInputEnabled = false;
    	}
    }
    
    
    
  8. TextChanged 事件处理程序的实现粘贴到 InputBufferTextBox.cpp。当修改文本缓冲区的文本时,将引发此事件。这会在用户点按 SIP 键盘上的某个键时发生,但也可能会因为其他原因而发生,例如,如果用户点按了自动更正和替换建议列表中的某个单词。通过访问 Text() 属性获取缓冲区中当前的文本。此方法将检查换行符是否出现在文本缓冲区中,以指示用户点击了 Enter 键。如果确实如此,可将文本框的焦点设置为 false。您可以将此处的逻辑添加到另一文本框的选项卡。此外,如果您正在将文本框呈现到离屏缓冲区,您可以添加警告呈现循环的代码,以在此处重新绘制控件。

    
    void InputBufferTextBox::OnTextChanged(KeyboardInputBuffer^ sender, CoreTextChangedEventArgs^ args)
    {
    	auto text = m_inputBuffer->Text;
    	if(std::find<const wchar_t*, wchar_t>(text->Begin(), text->End(), '\r') != text->End())
    	{
    		SetFocus(false);
    		// You could add logic here to tab to another control.
    	}
    
    	// Let your render loop know that this control needs to be rendered again.
    	// MyRenderLoop::IsDirty = true;
    }
    
    
    
  9. OnRender 方法粘贴到 InputBufferTextBox.cpp。在屏幕上绘制所需的 Direct3D 代码已在本示例中省略,但此简化的方法演示了典型的实现。绘制文本框容器,然后遍历文本缓冲区中每个字符并为该字符绘制位图。此方法的实际实现要更为复杂,尤其是在您要包含多行文本、剪裁或滚动时。

    
    void InputBufferTextBox::OnRender()
    {
    	// Draw the text box boundary
    	// MyDrawRectangle(m_x, m_y, m_width, m_height);
    
    	auto characters = m_inputBuffer->Text->Data();
    	for(int i = 0; i < m_inputBuffer->Text->Length(); i++)
    	{
    		// Draw each character in the buffer
    		// MyDrawCharacter(characters[i], m_x + i * characterWidth, y);
    	}
    
    }
    
    
    
  10. 修改主应用中的代码的下一步是使用文本框。在 NativeTextInput.h 的顶部,粘贴此行代码以包含文本框的标头文件。

    
    #include "InputBufferTextBox.h";
    
    
    
  11. 在 NativeTextInput.h 的私有成员变量中,粘贴此文本框的变量声明。

    
    	InputBufferTextBox^ m_inputBufferTextBox;
    
    
    
  12. 在 NativeTextInput.cpp 中,将下面的行粘贴到 OnSetWindow 方法中,它将作为项目模板的一部分进行包含在该方法中。此代码通过设置文本框的大小、位置和初始文本,然后将引用传递到应用的 CoreWindow 来初始化文本框。

    
    	m_inputBufferTextBox = ref new InputBufferTextBox(window, 0, 0, 480, 100, "Initial Text");
    
    
    
  13. 最后,在 NativeTextInput.cpp 中,将项目模板随附的 OnPointerPressed 方法替换为下面的代码。当用户点按屏幕时将调用此方法。它将调用文本框的 HitTest 方法以查看用户是否是在文本框的内部进行的点按。如果点按发生在文本框内部,文本框的焦点将被设置为 true。 如果点按发生在文本框的外部,并且文本框当前拥有焦点,该焦点将被设置为 false。谨记在文本框的 SetFocus 方法中,将 IsKeyboardInputEnabled() 切换为显示或隐藏 SIP 键盘。

    
    void NativeTextInput::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
    {
        CoreWindow^ window = CoreWindow::GetForCurrentThread();
    
    	auto position = args->CurrentPoint->Position;
    	bool isTouchInTextBox = m_inputBufferTextBox->HitTest(position.X, position.Y);
    	
    	if(isTouchInTextBox)
    	{
    		m_inputBufferTextBox->SetFocus(true);
    	}
    	else 
    	{
    		if(m_inputBufferTextBox->HasFocus)
    		{
    			// If the touch is outside of the active text box, hide the keyboard
    			m_inputBufferTextBox->SetFocus(false);
    		}
    	}
    
    }
    
    
    

使用键事件创建自定义的文本框

  1. 创建新的 Direct3D 项目。本示例假定您已命名项目“NativeTextInput”。

  2. 在 Visual Studio 中,转到“项目-添加类”以将新的类添加到项目。命名新的类“KeyEventTextBox”。

  3. 将下面的代码粘贴到 KeyEventTextBox.h 标头文件。在此声明的所有方法和成员变量将在随后的步骤中进行介绍。

    
    ref class KeyEventTextBox sealed
    {
    public:
    	KeyEventTextBox(void);
    	KeyEventTextBox(Windows::UI::Core::CoreWindow^ parentWindow, int x, int y, int width, int height, Platform::String^ initialText);
    	~KeyEventTextBox(void);
    
    	bool HitTest(int x, int y);
    	void SetFocus(bool hasFocus);
    
    	property bool HasFocus
        {
                bool get() { return m_hasFocus; }
        }
    
    protected:
    	void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
    	void OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args);
    	void OnRender();
    
    private:
    	Windows::UI::Core::CoreWindow^ m_parentWindow;
    	Windows::Phone::UI::Core::KeyboardInputBuffer^ m_inputBuffer;
    	Windows::Foundation::EventRegistrationToken m_keydownToken;
    	Windows::Foundation::EventRegistrationToken m_characterReceivedToken;
    
    	int m_x, m_y, m_width, m_height;
    	Platform::String^ m_text;
    	bool m_hasFocus;
    };
    
    
    
  4. 在 KeyEventTextBox.cpp 文件的顶部,在 #include 指令下,为文本框将使用的命名空间粘贴下面的 using 语句。

    
    #include <string>
    
    using namespace Windows::Foundation;
    using namespace Windows::UI::Core;
    using namespace Windows::Phone::UI::Core;
    using namespace Windows::System;
    using namespace Platform;
    using namespace std;
    
    
    
  5. 将自定义构造函数的代码粘贴到 KeyEventTextBox.cpp。在此方法中,已分配 m_parentWindow 成员变量。此值将成为应用的 CoreWindow 实例。接下来,设置对文本框的位置和大小进行定义的成员变量,设置输入范围(决定在软件键盘中显示哪些按键)。最后,将用作文本缓冲区的 m_text 成员变量设置为要在文本框中显示的初始文本。

    
    KeyEventTextBox::KeyEventTextBox(CoreWindow^ parentWindow, int x, int y, int width, int height, String^ initialText)
    {
    	m_parentWindow = parentWindow;
    	m_x = x;
    	m_y = y;
    	m_width = width;
    	m_height = height;
    	m_text = initialText;
    }
    
    
    
  6. 将定义 HitTest 方法的代码粘贴到 KeyEventTextBox.cpp。用户点按的屏幕坐标将传递到该方法。它只是检查触控点是否在文本框的边界内。

    
    bool KeyEventTextBox::HitTest(int x, int y)
    {
    	if(x >= m_x && x <= m_x + m_width && y >= m_y && y <= m_y + m_height)
    	{
    		return true;
    	}
    	else
    	{
    		return false;
    	}
    }
    
    
    
  7. 将定义 SetFocus 方法的代码粘贴到 KeyEventTextBox.cpp。如果此方法是使用 true 值调用的,这意味着文本框具有焦点并且应该准备处理文本输入。若要执行此操作,则设置键盘的输入范围,然后将 CoreWindowIsKeyboardInputEnabled() 属性设置为 true。这将导致 SIP 键盘进行显示。接下来,将为 KeyDownCharacterReceived 事件注册处理程序。将保存注册这些处理程序时返回的标记,以便能够在以后注销它们。

    如果 SetFocus 是使用 false 值调用的,将 IsKeyboardInputEnabled() 设置为 false 会导致 SIP 键盘隐藏。然后,将移除 KeyDownCharacterReceived 的事件处理程序。

    
    void KeyEventTextBox::SetFocus(bool hasFocus)
    {
    	m_hasFocus = hasFocus;
    
    	if(m_hasFocus)
    	{
    		m_parentWindow->IsKeyboardInputEnabled = true;
    		m_keydownToken = m_parentWindow->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &KeyEventTextBox::OnKeyDown);	
    		m_characterReceivedToken = m_parentWindow->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &KeyEventTextBox::OnCharacterReceived); 
    	}
    	else
    	{
    		m_parentWindow->IsKeyboardInputEnabled = false;
    		m_parentWindow->KeyDown -= m_keydownToken;
    		m_parentWindow->CharacterReceived -= m_characterReceivedToken;
    	}
    }
    
    
    
  8. KeyDown 事件处理程序的以下定义粘贴到 KeyEventTextBox.cpp。当用户点按 SIP 键盘上的某个键时,将在引发 CharacterReceived 事件之前引发此事件。此方法将检查按下了哪个键。如果是“后退”键,用户已点按了 Backspace 键。在这种情况下,将移除文本缓冲区的最后一个字母,并且事件参数的 Handled 属性将设置为 true。 这将防止系统引发 CharacterReceived,因此 Backspace 键击不会添加到文本缓冲区。如果点击了 Enter 键,文本框的焦点将被设置为 false,而后者又将隐藏 SIP 键盘。然后,事件参数的 Handled 属性将再次被设置为 true,以防止 CharacterReceived 被调用。

    
    void KeyEventTextBox::OnKeyDown(CoreWindow^ sender, KeyEventArgs^ args)
    {
    	if(args->VirtualKey == VirtualKey::Back)
    	{
    		if(m_text->Length() > 0)
    		{
    			wstring text = wstring(m_text->Data());
    			text.resize(text.length() - 1);
    			m_text = ref new String(text.c_str());
    		}
    		args->Handled = true;
    	}
    	else if(args->VirtualKey == VirtualKey::Enter)
    	{
    		SetFocus(false);
    		args->Handled = true;
    	}
    }
    
    
    
  9. CharacterReceived 事件处理程序的以下定义粘贴到 KeyEventTextBox.cpp。此方法只将事件参数中的字符添加到文本缓冲区的末尾。

    
    void KeyEventTextBox::OnCharacterReceived(CoreWindow^ sender, CharacterReceivedEventArgs^ args)
    {
    	wchar_t c = args->KeyCode;
     	m_text += ref new String(&c, 1);
    
    	// Let your render loop know that this control needs to be rendered again.
    	// MyRenderLoop::IsDirty = true;
    }
    
    
    
  10. OnRender 方法粘贴到 KeyEventTextBox.cpp。在屏幕上绘制所需的 Direct3D 代码已在本示例中省略,但此简化的方法演示了典型的实现。绘制文本框容器,然后遍历文本缓冲区中每个字符并为该字符绘制位图。此方法的实际实现要更为复杂,尤其是在您要包含多行文本、剪裁或滚动时。

  11. 修改主应用中的代码的下一步是使用文本框。在 NativeTextInput.h 的顶部,粘贴此行代码以包含文本框的标头文件。

    
    #include "KeyEventTextBox.h";
    
    
    
  12. 在 NativeTextInput.h 的私有成员变量中,粘贴此文本框的变量声明。

    
    	KeyEventTextBox^ m_keyEventTextBox;
    
    
    
  13. 在 NativeTextInput.cpp 中,将下面的行粘贴到 OnSetWindow 方法中,它将作为项目模板的一部分进行包含在该方法中。此代码通过设置文本框的大小、位置和初始文本,然后将引用传递到应用的 CoreWindow 来初始化文本框。

  14. 最后,在 NativeTextInput.cpp 中,使用下面的代码替换项目模板随附的 OnPointerPressed 方法。当用户点按屏幕时将调用此方法。它将调用文本框的 HitTest 方法以查看用户是否是在文本框的内部进行的点按。如果点按发生在文本框内部,文本框的焦点将被设置为 true。 如果点按发生在文本框的外部,并且文本框当前拥有焦点,该焦点将被设置为 false。谨记在文本框的 SetFocus 方法中,将 IsKeyboardInputEnabled() 切换为显示或隐藏 SIP 键盘。

    
    void NativeTextInput::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
    {
        CoreWindow^ window = CoreWindow::GetForCurrentThread();
    
    	auto position = args->CurrentPoint->Position;
    	bool isTouchInTextBox = m_keyEventTextBox->HitTest(position.X, position.Y);
    	
    	if(isTouchInTextBox)
    	{
    		m_keyEventTextBox->SetFocus(true);
    	}
    	else
    	{
    		// If the touch is outside of the active text box, hide the keyboard
    		if(m_keyEventTextBox->HasFocus)
    		{
    			m_keyEventTextBox->SetFocus(false);
    		}
    	}
    }
    
    
    

检测软件键盘何时显示

  1. 使用以上所述的其中一个示例应用,将以下代码添加到 NativeTextInput.h 文件的受保护方法区。

  2. SetWindow 处理程序结束时,添加以下代码行以获取对应用的 InputPane 的引用和挂钩 Hiding 事件。

  3. 现在添加“隐藏”事件处理程序的实现。在本例中,我们调用文本框类的 SetFocus 方法,并传入 false。当输入面板隐藏时,您可以执行其他操作,具体取决于您的应用。

  4. 最后,您可以实现 IsInputPanelShowing 方法,它检查 OccludedRect 属性以确定键盘是否封闭了屏幕。如果矩形的宽和高大于 0,则当前正在显示键盘。

Microsoft 正在进行一项网上调查,以了解您对 MSDN 网站的意见。 如果您选择参加,我们将会在您离开 MSDN 网站时向您显示该网上调查。

是否要参加?
显示:
© 2015 Microsoft