QWERTY implementation of a virtual keyboard.

pull/615/head
Mads Buvik Sandvei 4 years ago
parent 3158a2510e
commit 3e581571f4

@ -249,7 +249,7 @@ if(BUILD_OPENMW_VR)
add_openmw_dir (mwvr
openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrswapchain openxrswapchainimpl
realisticcombat
vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrmetamenu vrsession vrshadow vrtypes vrview vrviewer
vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrmetamenu vrsession vrshadow vrtypes vrview vrviewer vrvirtualkeyboard
)
openmw_add_executable(openmw_vr

@ -107,6 +107,7 @@ namespace MWBase
/// @note This method will block until the video finishes playing
/// (and will continually update the window while doing so)
virtual void playVideo(const std::string& name, bool allowSkipping) = 0;
virtual bool isPlayingVideo(void) const = 0;
virtual void setNewGame(bool newgame) = 0;

@ -123,6 +123,7 @@
#include "../mwvr/vrmetamenu.hpp"
#include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vrgui.hpp"
#include "../mwvr/vrvirtualkeyboard.hpp"
#endif
namespace MWGui
@ -168,6 +169,8 @@ namespace MWGui
, mScreenFader(nullptr)
, mDebugWindow(nullptr)
, mJailScreen(nullptr)
, mVrMetaMenu(nullptr)
, mVirtualKeyboardManager(nullptr)
, mTranslationDataStorage (translationDataStorage)
, mCharGen(nullptr)
, mInputBlocker(nullptr)
@ -308,6 +311,14 @@ namespace MWGui
mDragAndDrop = new DragAndDrop();
#ifdef USE_OPENXR
mVrMetaMenu = new MWVR::VrMetaMenu(w, h);
mWindows.push_back(mVrMetaMenu);
mGuiModeStates[GM_VrMetaMenu] = GuiModeState(mVrMetaMenu);
mVirtualKeyboardManager = new MWVR::VirtualKeyboardManager;
#endif
Recharge* recharge = new Recharge();
mGuiModeStates[GM_Recharge] = GuiModeState(recharge);
mWindows.push_back(recharge);
@ -448,12 +459,6 @@ namespace MWGui
mWindows.push_back(mJailScreen);
mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen);
#ifdef USE_OPENXR
mVrMetaMenu = new MWVR::VrMetaMenu(w, h);
mWindows.push_back(mVrMetaMenu);
mGuiModeStates[GM_VrMetaMenu] = GuiModeState(mVrMetaMenu);
#endif
std::string werewolfFaderTex = "textures\\werewolfoverlay.dds";
if (mResourceSystem->getVFS()->exists(werewolfFaderTex))
{
@ -1835,6 +1840,11 @@ namespace MWGui
mVideoEnabled = false;
}
bool WindowManager::isPlayingVideo(void) const
{
return mVideoEnabled;
}
void WindowManager::sizeVideo(int screenWidth, int screenHeight)
{
// Use black bars to correct aspect ratio

@ -81,6 +81,7 @@ namespace osgMyGUI
namespace Gui
{
class FontLoader;
class VirtualKeyboardManager;
}
namespace MWRender
@ -153,6 +154,7 @@ namespace MWGui
/// @note This method will block until the video finishes playing
/// (and will continually update the window while doing so)
void playVideo(const std::string& name, bool allowSkipping) override;
bool isPlayingVideo(void) const override;
/// Warning: do not use MyGUI::InputManager::setKeyFocusWidget directly. Instead use this.
void setKeyFocusWidget (MyGUI::Widget* widget) override;
@ -447,6 +449,8 @@ namespace MWGui
JailScreen* mJailScreen;
MWVR::VrMetaMenu* mVrMetaMenu;
Gui::VirtualKeyboardManager* mVirtualKeyboardManager;
std::vector<WindowBase*> mWindows;
Translation::Storage& mTranslationDataStorage;

@ -480,6 +480,22 @@ namespace MWVR
LayerConfig gMessageBoxConfig = createDefaultConfig(6, false, SizingMode::Auto);;
LayerConfig gNotificationConfig = createDefaultConfig(7, false, SizingMode::Fixed);
//LayerConfig gVirtualKeyboardConfig = createDefaultConfig(50);
LayerConfig gVirtualKeyboardConfig = LayerConfig{
10,
false,
osg::Vec4{0.f,0.f,0.f,.75f},
osg::Vec3(0.025f,.025f,.066f), // offset (meters)
osg::Vec2(0.f,0.5f), // center (model space)
osg::Vec2(.25f, .25f), // extent (meters)
2048, // Spatial resolution (pixels per meter)
osg::Vec2i(2048,2048), // Texture resolution
osg::Vec2(1,1),
SizingMode::Auto,
TrackingMode::HudLeftHand,
""
};
static const float sSideBySideRadius = 1.f;
static const float sSideBySideAzimuthInterval = -osg::PI_4;
static const LayerConfig createSideBySideConfig(int priority)
@ -559,6 +575,7 @@ namespace MWVR
{"InputBlocker", gVideoPlayerConfig},
{"Menu", gVideoPlayerConfig},
{"LoadingScreen", gLoadingScreenConfig},
{"VirtualKeyboard", gVirtualKeyboardConfig},
};
static std::set<std::string> layerBlacklist =
@ -806,6 +823,30 @@ namespace MWVR
}
}
void VRGUIManager::setFocusWidget(MyGUI::Widget* widget)
{
// TODO: This relies on MyGUI internal functions and may break on any future version.
if (widget == mFocusWidget)
return;
if (mFocusWidget)
mFocusWidget->_riseMouseLostFocus(widget);
if (widget)
widget->_riseMouseSetFocus(mFocusWidget);
mFocusWidget = widget;
}
bool VRGUIManager::injectMouseClick(bool onPress)
{
// TODO: This relies on MyGUI internal functions and may break on any future version.
if (mFocusWidget)
{
if(onPress)
mFocusWidget->_riseMouseButtonClick();
return true;
}
return false;
}
void VRGUIManager::computeGuiCursor(osg::Vec3 hitPoint)
{
float x = 0;
@ -830,6 +871,21 @@ namespace MWVR
MyGUI::InputManager::getInstance().injectMouseMove((int)x, (int)y, 0);
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
// The virtual keyboard must be interactive regardless of modals
// This could be generalized with another config entry, but i don't think any other
// widgets/layers need it so i'm hardcoding it for the VirtualKeyboard for now.
if (
mFocusLayer
&& mFocusLayer->mLayerName == "VirtualKeyboard"
&& MyGUI::InputManager::getInstance().isModalAny())
{
auto* widget = MyGUI::LayerManager::getInstance().getWidgetFromPoint((int)x, (int)y);
setFocusWidget(widget);
}
else
setFocusWidget(nullptr);
}
}

@ -159,12 +159,16 @@ namespace MWVR
/// Gui cursor coordinates to use to simulate a mouse press/move if the player is currently pointing at a vr gui layer
osg::Vec2i guiCursor() { return mGuiCursor; };
/// Inject mouse click if applicable
bool injectMouseClick(bool onPress);
private:
void computeGuiCursor(osg::Vec3 hitPoint);
void updateSideBySideLayers();
void insertWidget(MWGui::Layout* widget);
void removeWidget(MWGui::Layout* widget);
void setFocusLayer(VRGUILayer* layer);
void setFocusWidget(MyGUI::Widget* widget);
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
@ -178,6 +182,7 @@ namespace MWVR
Pose mHeadPose{};
osg::Vec2i mGuiCursor{};
VRGUILayer* mFocusLayer{ nullptr };
MyGUI::Widget* mFocusWidget{ nullptr };
osg::observer_ptr<osg::Camera> mCamera{ nullptr };
};
}

@ -141,6 +141,9 @@ namespace MWVR
void VRInputManager::injectMousePress(int sdlButton, bool onPress)
{
if (Environment::get().getGUIManager()->injectMouseClick(onPress))
return;
SDL_MouseButtonEvent arg;
if (onPress)
mMouseManager->mousePressed(arg, sdlButton);
@ -212,19 +215,15 @@ namespace MWVR
{MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"},
{MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"},
{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"},
//{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"},
{MWInput::A_Jump, "/user/hand/left/input/trigger/value"},
{MWInput::A_ToggleSpell, "/user/hand/left/input/x/click"},
//{MWInput::A_QuickSave, "/user/hand/left/input/y/click"},
{MWInput::A_Rest, "/user/hand/left/input/y/click"},
{MWInput::A_ToggleWeapon, "/user/hand/right/input/a/click"},
{MWInput::A_Inventory, "/user/hand/right/input/b/click"},
//{MWInput::A_Journal, "/user/hand/right/input/b/click"},
{A_ActivateTouch, "/user/hand/right/input/squeeze/value"},
{MWInput::A_Activate, "/user/hand/right/input/squeeze/value"},
{MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"},
{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"},
{MWInput::A_Use, "/user/hand/right/input/trigger/value"},
};
@ -255,17 +254,13 @@ namespace MWVR
{MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"},
{MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"},
{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"},
//{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"},
{MWInput::A_Jump, "/user/hand/left/input/trigger/value"},
{MWInput::A_ToggleSpell, "/user/hand/left/input/x/click"},
//{MWInput::A_QuickSave, "/user/hand/left/input/y/click"},
{MWInput::A_Rest, "/user/hand/left/input/y/click"},
{MWInput::A_ToggleWeapon, "/user/hand/right/input/a/click"},
{MWInput::A_Inventory, "/user/hand/right/input/b/click"},
//{MWInput::A_Journal, "/user/hand/right/input/b/click"},
{MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"},
{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"},
{MWInput::A_Use, "/user/hand/right/input/trigger/value"},
{A_ActivateTouch, "/user/hand/right/input/squeeze/value"},
{MWInput::A_Activate, "/user/hand/right/input/squeeze/value"},
@ -294,21 +289,15 @@ namespace MWVR
// In-game character controls
SuggestedBindings gameplayBindings{
//{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"},
//{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"},
{A_Recenter, "/user/hand/left/input/menu/click"},
{A_VrMetaMenu, "/user/hand/left/input/menu/click"},
{MWInput::A_Jump, "/user/hand/left/input/trigger/value"},
{MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"},
{MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"},
//{MWInput::A_QuickSave, "/user/hand/left/input/thumbstick/click"},
{MWInput::A_Rest, "/user/hand/left/input/thumbstick/click"},
{MWInput::A_ToggleSpell, "/user/hand/left/input/trackpad/click"},
{MWInput::A_Sneak, "/user/hand/left/input/squeeze/click"},
{MWInput::A_Inventory, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_Journal, "/user/hand/right/input/thumbstick/click"},
{MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"},
{MWInput::A_ToggleWeapon, "/user/hand/right/input/trackpad/click"},
{MWInput::A_Use, "/user/hand/right/input/trigger/value"},
@ -336,23 +325,17 @@ namespace MWVR
std::string controllerProfilePath = "/interaction_profiles/valve/index_controller";
// In-game character controls
SuggestedBindings gameplayBindings{
//{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"},
{MWInput::A_ToggleSpell, "/user/hand/left/input/a/click"},
{MWInput::A_Rest, "/user/hand/left/input/b/click"},
//{MWInput::A_QuickSave, "/user/hand/left/input/b/click"},
{MWInput::A_MoveForwardBackward,"/user/hand/left/input/thumbstick/y"},
{MWInput::A_MoveLeftRight, "/user/hand/left/input/thumbstick/x"},
//{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"},
{A_Recenter, "/user/hand/left/input/trackpad/force"},
{A_VrMetaMenu, "/user/hand/left/input/trackpad/force"},
{MWInput::A_Jump, "/user/hand/left/input/trigger/value"},
{MWInput::A_Sneak, "/user/hand/left/input/squeeze/force"},
{MWInput::A_ToggleWeapon, "/user/hand/right/input/a/click"},
{MWInput::A_Inventory, "/user/hand/right/input/b/click"},
//{MWInput::A_Journal, "/user/hand/right/input/b/click"},
//{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"},
{MWInput::A_LookLeftRight, "/user/hand/right/input/thumbstick/x"},
//{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"},
{MWInput::A_Use, "/user/hand/right/input/trigger/value"},
{A_ActivateTouch, "/user/hand/right/input/squeeze/force"},
{MWInput::A_Activate, "/user/hand/right/input/squeeze/force"},
@ -377,18 +360,8 @@ namespace MWVR
{
std::string controllerProfilePath = "/interaction_profiles/htc/vive_controller";
// TODO: I Didn't realize the vive wands were so bad. We don't have NEARLY enough actions available.
// In-game character controls
SuggestedBindings gameplayBindings{
//{MWInput::A_AlwaysRun, "/user/hand/left/input/thumbstick/click"},
//{MWInput::A_AutoMove, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_Inventory, "/user/hand/right/input/b/click"},
//{MWInput::A_Journal, "/user/hand/right/input/b/click"},
//{MWInput::A_QuickSave, "/user/hand/left/input/b/click"},
//{MWInput::A_Rest, "/user/hand/left/input/b/click"},
//{MWInput::A_ToggleDebug, "/user/hand/right/input/thumbstick/click"},
//{MWInput::A_ToggleHUD, "/user/hand/left/input/thumbstick/click"},
{A_Recenter, "/user/hand/left/input/menu/click"},
{A_VrMetaMenu, "/user/hand/left/input/menu/click"},
{A_VrMetaMenu, "/user/hand/right/input/squeeze/click"},
@ -556,19 +529,23 @@ namespace MWVR
{
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
auto* vrGuiManager = Environment::get().getGUIManager();
auto* wm = MWBase::Environment::get().getWindowManager();
// OpenMW does not currently provide any way to directly request skipping a video.
// This is copied from the controller manager and is used to skip videos,
// and works because mygui only consumes the escape press if a video is currently playing.
auto kc = MWInput::sdlKeyToMyGUI(SDLK_ESCAPE);
if (action->onActivate())
{
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(kc, 0));
}
else if (action->onDeactivate())
if (wm->isPlayingVideo())
{
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc));
auto kc = MWInput::sdlKeyToMyGUI(SDLK_ESCAPE);
if (action->onActivate())
{
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(kc, 0));
}
else if (action->onDeactivate())
{
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc));
}
}
if (disableControls)
@ -623,14 +600,14 @@ namespace MWVR
vrGuiManager->updateTracking();
break;
case A_MenuSelect:
if (!MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Space, 0, 0))
if (!wm->injectKeyPress(MyGUI::KeyCode::Return, 0, false))
executeAction(MWInput::A_Activate);
break;
case A_MenuBack:
if (MyGUI::InputManager::getInstance().isModalAny())
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
wm->exitCurrentModal();
else
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
wm->exitCurrentGuiMode();
break;
case MWInput::A_Use:
pointActivation(true);

@ -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

@ -3966,7 +3966,7 @@ namespace MWWorld
if (windowManager->isGuiMode() && windowManager->isConsoleMode())
{
return getTargetObject(result, pointer, getMaxActivationDistance() * 50, false);
return getTargetObject(result, pointer, getMaxActivationDistance() * 50, true);
}
else
{

@ -131,7 +131,7 @@ add_component_dir (myguiplatform
)
add_component_dir (widgets
box fontwrapper imagebutton tags list numericeditbox sharedstatebutton windowcaption widgets
box fontwrapper imagebutton tags list numericeditbox sharedstatebutton virtualkeyboardmanager windowcaption widgets
)
add_component_dir (fontloader

@ -1,4 +1,5 @@
#include "box.hpp"
#include "virtualkeyboardmanager.hpp"
#include <MyGUI_EditText.h>
@ -486,4 +487,36 @@ namespace Gui
setUserString("VStretch", "true");
}
EditBox::EditBox(bool shouldSupportVirtualKeyboard)
: mVirtualKeyboardRegistered(false)
{
if (shouldSupportVirtualKeyboard)
registerVirtualKeyboard();
}
EditBox::~EditBox()
{
unregisterVirtualKeyboard();
}
void EditBox::registerVirtualKeyboard()
{
if (!mVirtualKeyboardRegistered)
{
auto* vkm = Gui::VirtualKeyboardManager::getInstancePtr();
if (vkm)
{
vkm->registerEditBox(this);
mVirtualKeyboardRegistered = true;
}
}
}
void EditBox::unregisterVirtualKeyboard()
{
if (mVirtualKeyboardRegistered)
{
// No need to check here
Gui::VirtualKeyboardManager::getInstance().unregisterEditBox(this);
mVirtualKeyboardRegistered = false;
}
}
}

@ -23,7 +23,17 @@ namespace Gui
class EditBox : public FontWrapper<MyGUI::EditBox>
{
MYGUI_RTTI_DERIVED( EditBox )
MYGUI_RTTI_DERIVED( EditBox );
/// @param supportsVirtualKeyboard If true, VR mode will spawn a virtual keyboard whenever this widget is focused.
EditBox(bool shouldSupportVirtualKeyboard = true);
~EditBox();
private:
void registerVirtualKeyboard();
void unregisterVirtualKeyboard();
bool mVirtualKeyboardRegistered;
};
class AutoSizedWidget

@ -3,7 +3,7 @@
#include <MyGUI_EditBox.h>
#include "fontwrapper.hpp"
#include "box.hpp"
namespace Gui
{
@ -11,7 +11,7 @@ namespace Gui
/**
* @brief A variant of the EditBox that only allows integer inputs
*/
class NumericEditBox final : public FontWrapper<MyGUI::EditBox>
class NumericEditBox final : public Gui::EditBox
{
MYGUI_RTTI_DERIVED(NumericEditBox)

@ -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

@ -98,6 +98,7 @@ set(MYGUI_FILES
openmw_trade_window_vr.layout
openmw_trainingwindow.layout
openmw_travel_window.layout
openmw_vr_virtual_keyboard.layout
openmw_wait_dialog.layout
openmw_wait_dialog_progressbar.layout
openmw_windows.skin.xml

@ -27,5 +27,6 @@
<Layer name="MessageBox" overlapped="false" pick="true"/>
<Layer name="InputBlocker" overlapped="false" pick="true"/>
<Layer name="VideoPlayer" overlapped="false" pick="true"/>
<Layer name="VirtualKeyboard" overlapped="false" pick="true"/>
<Layer name="Pointer" overlapped="false" pick="false"/>
</MyGUI>

@ -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…
Cancel
Save