QWERTY implementation of a virtual keyboard.
parent
3158a2510e
commit
3e581571f4
@ -0,0 +1,273 @@
|
||||
#include "vrvirtualkeyboard.hpp"
|
||||
|
||||
#include <MyGUI_InputManager.h>
|
||||
#include <MyGUI_LayerManager.h>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/statemanager.hpp"
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
VirtualKeyboardManager::VirtualKeyboardManager()
|
||||
: mVk(new VrVirtualKeyboard)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VirtualKeyboardManager::registerEditBox(MyGUI::EditBox* editBox)
|
||||
{
|
||||
IDelegate* onSetFocusDelegate = newDelegate(mVk.get(), &VrVirtualKeyboard::delegateOnSetFocus);
|
||||
IDelegate* onLostFocusDelegate = newDelegate(mVk.get(), &VrVirtualKeyboard::delegateOnLostFocus);
|
||||
editBox->eventKeySetFocus += onSetFocusDelegate;
|
||||
editBox->eventKeyLostFocus += onLostFocusDelegate;
|
||||
|
||||
mDelegates[editBox] = Delegates(onSetFocusDelegate, onLostFocusDelegate);
|
||||
}
|
||||
|
||||
void VirtualKeyboardManager::unregisterEditBox(MyGUI::EditBox* editBox)
|
||||
{
|
||||
auto it = mDelegates.find(editBox);
|
||||
if (it != mDelegates.end())
|
||||
{
|
||||
editBox->eventKeySetFocus -= it->second.first;
|
||||
editBox->eventKeyLostFocus -= it->second.second;
|
||||
mDelegates.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const char* mClassTypeName;
|
||||
|
||||
VrVirtualKeyboard::VrVirtualKeyboard()
|
||||
: WindowBase("openmw_vr_virtual_keyboard.layout")
|
||||
, mButtonBox(nullptr)
|
||||
, mTarget(nullptr)
|
||||
, mButtons()
|
||||
, mShift(false)
|
||||
, mCaps(false)
|
||||
{
|
||||
getWidget(mButtonBox, "ButtonBox");
|
||||
mMainWidget->setNeedKeyFocus(false);
|
||||
mButtonBox->setNeedKeyFocus(false);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
VrVirtualKeyboard::~VrVirtualKeyboard()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onResChange(int w, int h)
|
||||
{
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onFrame(float dt)
|
||||
{
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::open(MyGUI::EditBox* target)
|
||||
{
|
||||
updateMenu();
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(target);
|
||||
mTarget = target;
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::close()
|
||||
{
|
||||
setVisible(false);
|
||||
mTarget = nullptr;
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::delegateOnSetFocus(MyGUI::Widget* _sender, MyGUI::Widget* _old)
|
||||
{
|
||||
open(static_cast<MyGUI::EditBox*>(_sender));
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::delegateOnLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onButtonClicked(MyGUI::Widget* sender)
|
||||
{
|
||||
assert(mTarget);
|
||||
MyGUI::InputManager::getInstance().setKeyFocusWidget(mTarget);
|
||||
|
||||
std::string name = *sender->getUserData<std::string>();
|
||||
|
||||
if (name == "Esc")
|
||||
onEsc();
|
||||
if (name == "Tab")
|
||||
onTab();
|
||||
if (name == "Caps")
|
||||
onCaps();
|
||||
if (name == "Shift")
|
||||
onShift();
|
||||
else
|
||||
mShift = false;
|
||||
if (name == "Back")
|
||||
onBackspace();
|
||||
if (name == "Return")
|
||||
onReturn();
|
||||
if (name == "Space")
|
||||
textInput(" ");
|
||||
if (name == "->")
|
||||
textInput("->");
|
||||
if (name.length() == 1)
|
||||
textInput(name);
|
||||
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::textInput(const std::string& symbol)
|
||||
{
|
||||
MyGUI::UString ustring(symbol);
|
||||
MyGUI::UString::utf32string utf32string = ustring.asUTF32();
|
||||
for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it)
|
||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onEsc()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onTab()
|
||||
{
|
||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Tab);
|
||||
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Tab);
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onCaps()
|
||||
{
|
||||
mCaps = !mCaps;
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onShift()
|
||||
{
|
||||
mShift = !mShift;
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onBackspace()
|
||||
{
|
||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Backspace);
|
||||
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Backspace);
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::onReturn()
|
||||
{
|
||||
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Return);
|
||||
MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Return);
|
||||
}
|
||||
|
||||
bool VrVirtualKeyboard::exit()
|
||||
{
|
||||
close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void VrVirtualKeyboard::updateMenu()
|
||||
{
|
||||
// TODO: Localization?
|
||||
static std::vector<std::string> row1{ "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "Back" };
|
||||
static std::vector<std::string> row2{ "Tab", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "Return" };
|
||||
static std::vector<std::string> row3{ "Caps", "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "\\", "->" };
|
||||
static std::vector<std::string> row4{ "Shift", "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "Space" };
|
||||
std::map<std::string, std::string> shiftMap;
|
||||
shiftMap["1"] = "!";
|
||||
shiftMap["2"] = "@";
|
||||
shiftMap["3"] = "#";
|
||||
shiftMap["4"] = "$";
|
||||
shiftMap["5"] = "%";
|
||||
shiftMap["6"] = "^";
|
||||
shiftMap["7"] = "&";
|
||||
shiftMap["8"] = "*";
|
||||
shiftMap["9"] = "(";
|
||||
shiftMap["0"] = ")";
|
||||
shiftMap["-"] = "_";
|
||||
shiftMap["="] = "+";
|
||||
shiftMap["\\"] = "|";
|
||||
shiftMap[","] = "<";
|
||||
shiftMap["."] = ">";
|
||||
shiftMap["/"] = "?";
|
||||
shiftMap[";"] = ":";
|
||||
shiftMap["'"] = "\"";
|
||||
shiftMap["["] = "{";
|
||||
shiftMap["]"] = "}";
|
||||
shiftMap["`"] = "~";
|
||||
|
||||
std::vector< std::vector< std::string > > rows{ row1, row2, row3, row4 };
|
||||
|
||||
int sideSize = 50;
|
||||
int margin = 10;
|
||||
int xmax = 0;
|
||||
int ymax = 0;
|
||||
|
||||
if (mButtons.empty())
|
||||
{
|
||||
int y = margin;
|
||||
for (auto& row : rows)
|
||||
{
|
||||
int x = margin;
|
||||
for (std::string& buttonId : row)
|
||||
{
|
||||
int width = sideSize + 10 * (buttonId.length() - 1);
|
||||
MyGUI::Button* button = mButtonBox->createWidget<MyGUI::Button>(
|
||||
"MW_Button", MyGUI::IntCoord(x, y, width, sideSize), MyGUI::Align::Default, buttonId);
|
||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &VrVirtualKeyboard::onButtonClicked);
|
||||
button->setUserData(std::string(buttonId));
|
||||
button->setVisible(true);
|
||||
button->setFontHeight(32);
|
||||
button->setCaption(buttonId);
|
||||
button->setNeedKeyFocus(false);
|
||||
mButtons[buttonId] = button;
|
||||
x += width + margin;
|
||||
}
|
||||
y += sideSize + margin;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& row : rows)
|
||||
{
|
||||
for (std::string& buttonId : row)
|
||||
{
|
||||
auto* button = mButtons[buttonId];
|
||||
xmax = std::max(xmax, button->getAbsoluteRect().right);
|
||||
ymax = std::max(ymax, button->getAbsoluteRect().bottom);
|
||||
|
||||
if (buttonId.length() == 1)
|
||||
{
|
||||
auto caption = buttonId;
|
||||
if (mShift ^ mCaps)
|
||||
caption[0] = std::toupper(caption[0]);
|
||||
else
|
||||
caption[0] = std::tolower(caption[0]);
|
||||
button->setCaption(caption);
|
||||
button->setUserData(caption);
|
||||
}
|
||||
|
||||
if (mShift)
|
||||
{
|
||||
auto it = shiftMap.find(buttonId);
|
||||
if (it != shiftMap.end())
|
||||
{
|
||||
button->setCaption(it->second);
|
||||
button->setUserData(it->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << xmax << ", " << ymax << std::endl;
|
||||
|
||||
setCoord(0, 0, xmax + margin, ymax + margin);
|
||||
mButtonBox->setCoord(0, 0, xmax + margin, ymax + margin);
|
||||
//mButtonBox->setCoord (margin, margin, width, height);
|
||||
mButtonBox->setVisible(true);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
#ifndef OPENMW_GAME_MWVR_VRVIRTUALKEYBOARD_H
|
||||
#define OPENMW_GAME_MWVR_VRVIRTUALKEYBOARD_H
|
||||
|
||||
#include "../mwgui/windowbase.hpp"
|
||||
|
||||
#include <MyGUI_Button.h>
|
||||
#include "components/widgets/virtualkeyboardmanager.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
class VirtualKeyboardManager;
|
||||
}
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
class VrVirtualKeyboard : public MWGui::WindowBase
|
||||
{
|
||||
public:
|
||||
|
||||
VrVirtualKeyboard();
|
||||
~VrVirtualKeyboard();
|
||||
|
||||
void onResChange(int w, int h) override;
|
||||
|
||||
void onFrame(float dt) override;
|
||||
|
||||
bool exit() override;
|
||||
|
||||
void open(MyGUI::EditBox* target);
|
||||
|
||||
void close();
|
||||
|
||||
void delegateOnSetFocus(MyGUI::Widget* _sender, MyGUI::Widget* _old);
|
||||
void delegateOnLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _old);
|
||||
|
||||
private:
|
||||
void onButtonClicked(MyGUI::Widget* sender);
|
||||
void textInput(const std::string& symbol);
|
||||
void onEsc();
|
||||
void onTab();
|
||||
void onCaps();
|
||||
void onShift();
|
||||
void onBackspace();
|
||||
void onReturn();
|
||||
void updateMenu();
|
||||
|
||||
MyGUI::Widget* mButtonBox;
|
||||
MyGUI::EditBox* mTarget;
|
||||
std::map<std::string, MyGUI::Button*> mButtons;
|
||||
bool mShift;
|
||||
bool mCaps;
|
||||
};
|
||||
|
||||
class VirtualKeyboardManager : public Gui::VirtualKeyboardManager
|
||||
{
|
||||
public:
|
||||
VirtualKeyboardManager();
|
||||
|
||||
void registerEditBox(MyGUI::EditBox* editBox) override;
|
||||
void unregisterEditBox(MyGUI::EditBox* editBox) override;
|
||||
VrVirtualKeyboard& virtualKeyboard() { return *mVk; };
|
||||
|
||||
private:
|
||||
std::unique_ptr<VrVirtualKeyboard> mVk;
|
||||
|
||||
// MyGUI deletes delegates when you remove them from an event.
|
||||
// Therefore i need one pair of delegates per box instead of being able to reuse one pair.
|
||||
// And i have to set them aside myself to know what to remove from each event.
|
||||
// There is an IDelegateUnlink type that might simplify this, but it is poorly documented.
|
||||
using IDelegate = MyGUI::EventHandle_WidgetWidget::IDelegate;
|
||||
// .first = onSetFocus, .second = onLostFocus
|
||||
using Delegates = std::pair<IDelegate*, IDelegate*>;
|
||||
std::map<MyGUI::EditBox*, Delegates> mDelegates;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,4 @@
|
||||
#include "virtualkeyboardmanager.hpp"
|
||||
|
||||
Gui::VirtualKeyboardManager* MyGUI::Singleton<Gui::VirtualKeyboardManager>::msInstance = nullptr;
|
||||
const char* MyGUI::Singleton<Gui::VirtualKeyboardManager>::mClassTypeName = "Gui::VirtualKeyboardManager";
|
@ -0,0 +1,18 @@
|
||||
#ifndef OPENMW_WIDGETS_VIRTUALKEYBOARDMANAGER_H
|
||||
#define OPENMW_WIDGETS_VIRTUALKEYBOARDMANAGER_H
|
||||
|
||||
#include <MyGUI_EditBox.h>
|
||||
#include "MyGUI_Singleton.h"
|
||||
|
||||
namespace Gui
|
||||
{
|
||||
class VirtualKeyboardManager :
|
||||
public MyGUI::Singleton<VirtualKeyboardManager>
|
||||
{
|
||||
public:
|
||||
virtual void registerEditBox(MyGUI::EditBox* editBox) = 0;
|
||||
virtual void unregisterEditBox(MyGUI::EditBox* editBox) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<MyGUI type="Layout">
|
||||
<Widget type="Widget" layer="VirtualKeyboard" position="0 0 900 500" name="_Main" align="Center">
|
||||
<Widget type="Widget" position="25 25 850 400" name="ButtonBox">
|
||||
</Widget>
|
||||
</Widget>
|
||||
</MyGUI>
|
Loading…
Reference in New Issue