diff --git a/ports/libsimpleservo/capi/src/lib.rs b/ports/libsimpleservo/capi/src/lib.rs
index ca0f0419f34..a82ab950c32 100644
--- a/ports/libsimpleservo/capi/src/lib.rs
+++ b/ports/libsimpleservo/capi/src/lib.rs
@@ -720,30 +720,33 @@ pub extern "C" fn click(x: f32, y: f32) {
#[no_mangle]
pub extern "C" fn key_down(name: *const c_char) {
- catch_any_panic(|| {
- debug!("key_down");
- let name = unsafe { CStr::from_ptr(name) };
- let key = Key::from_str(&name.to_str().expect("Can't read string"));
- if let Ok(key) = key {
- call(|s| s.key_down(key));
- } else {
- warn!("Received unknown keys");
- }
- })
+ debug!("key_up");
+ key_event(name, false);
}
#[no_mangle]
pub extern "C" fn key_up(name: *const c_char) {
+ debug!("key_up");
+ key_event(name, true);
+}
+
+fn key_event(name: *const c_char, up: bool) {
catch_any_panic(|| {
- debug!("key_up");
let name = unsafe { CStr::from_ptr(name) };
- let key = Key::from_str(&name.to_str().expect("Can't read string"));
+ let name = match name.to_str() {
+ Ok(name) => name,
+ Err(..) => {
+ warn!("Couldn't not read str");
+ return;
+ },
+ };
+ let key = Key::from_str(&name);
if let Ok(key) = key {
- call(|s| s.key_up(key));
+ call(|s| if up { s.key_up(key) } else { s.key_down(key) });
} else {
warn!("Received unknown keys");
}
- })
+ });
}
#[no_mangle]
diff --git a/support/hololens/ServoApp/ServoApp.vcxproj b/support/hololens/ServoApp/ServoApp.vcxproj
index 0d819c3fffc..8b189190a24 100644
--- a/support/hololens/ServoApp/ServoApp.vcxproj
+++ b/support/hololens/ServoApp/ServoApp.vcxproj
@@ -120,6 +120,7 @@
+
diff --git a/support/hololens/ServoApp/ServoApp.vcxproj.filters b/support/hololens/ServoApp/ServoApp.vcxproj.filters
index 4bb5ad598a7..256c28acce5 100644
--- a/support/hololens/ServoApp/ServoApp.vcxproj.filters
+++ b/support/hololens/ServoApp/ServoApp.vcxproj.filters
@@ -43,6 +43,9 @@
Devtools
+
+ ServoControl
+
diff --git a/support/hololens/ServoApp/ServoControl/Keys.h b/support/hololens/ServoApp/ServoControl/Keys.h
new file mode 100644
index 00000000000..8f862995f42
--- /dev/null
+++ b/support/hololens/ServoApp/ServoControl/Keys.h
@@ -0,0 +1,130 @@
+using namespace winrt::Windows::System;
+
+namespace winrt {
+std::optional KeyToString(Windows::System::VirtualKey key) {
+ switch (key) {
+ case VirtualKey::F1:
+ return "F1";
+ case VirtualKey::F2:
+ return "F2";
+ case VirtualKey::F3:
+ return "F3";
+ case VirtualKey::F4:
+ return "F4";
+ case VirtualKey::F5:
+ return "F5";
+ case VirtualKey::F6:
+ return "F6";
+ case VirtualKey::F7:
+ return "F7";
+ case VirtualKey::F8:
+ return "F8";
+ case VirtualKey::F9:
+ return "F9";
+ case VirtualKey::F10:
+ return "F10";
+ case VirtualKey::F11:
+ return "F11";
+ case VirtualKey::F12:
+ return "F12";
+ case VirtualKey::Shift:
+ return "Shift";
+ case VirtualKey::LeftShift:
+ return "Shift";
+ case VirtualKey::RightShift:
+ return "Shift";
+ case VirtualKey::Control:
+ return "Control";
+ case VirtualKey::LeftControl:
+ return "Control";
+ case VirtualKey::RightControl:
+ return "Control";
+ case VirtualKey::Escape:
+ return "Escape";
+ case VirtualKey::Enter:
+ return "Enter";
+ case VirtualKey::Tab:
+ return "Tab";
+ case VirtualKey::Delete:
+ return "Delete";
+ case VirtualKey::Back:
+ return "Backspace";
+ case VirtualKey::GoForward:
+ return "BrowserForward";
+ case VirtualKey::GoBack:
+ return "BrowserBack";
+ case VirtualKey::GoHome:
+ return "BrowserHome";
+ case VirtualKey::Favorites:
+ return "BrowserFavorites";
+ case VirtualKey::Search:
+ return "BrowserSearch";
+ case VirtualKey::Stop:
+ return "BrowserStop";
+ case VirtualKey::Menu:
+ return "Alt";
+ case VirtualKey::RightMenu:
+ return "Alt";
+ case VirtualKey::LeftMenu:
+ return "Alt";
+ case VirtualKey::CapitalLock:
+ return "CapsLock";
+ case VirtualKey::LeftWindows:
+ return "Meta";
+ case VirtualKey::RightWindows:
+ return "Meta";
+ case VirtualKey::NumberKeyLock:
+ return "NumLock";
+ case VirtualKey::Scroll:
+ return "ScrollLock";
+ case VirtualKey::Down:
+ return "ArrowDown";
+ case VirtualKey::Up:
+ return "ArrowUp";
+ case VirtualKey::Left:
+ return "ArrowLeft";
+ case VirtualKey::Right:
+ return "ArrowRight";
+ case VirtualKey::End:
+ return "End";
+ case VirtualKey::Home:
+ return "Home";
+ case VirtualKey::PageDown:
+ return "PageHome";
+ case VirtualKey::PageUp:
+ return "PageUp";
+ case VirtualKey::Clear:
+ return "Clear";
+ case VirtualKey::Insert:
+ return "Insert";
+ case VirtualKey::Accept:
+ return "Accept";
+ case VirtualKey::Cancel:
+ return "Cancel";
+ case VirtualKey::Execute:
+ return "Execute";
+ case VirtualKey::Help:
+ return "Help";
+ case VirtualKey::Pause:
+ return "Pause";
+ case VirtualKey::Select:
+ return "Select";
+ case VirtualKey::Print:
+ return "Print";
+ case VirtualKey::Convert:
+ return "Convert";
+ case VirtualKey::NonConvert:
+ return "NonConvert";
+ case VirtualKey::ModeChange:
+ return "ModeChange";
+ case VirtualKey::Hangul:
+ return "HangulMode";
+ case VirtualKey::Hanja:
+ return "HanjaMode";
+ case VirtualKey::Junja:
+ return "JunjaMode";
+ default:
+ return {};
+ }
+}
+} // namespace winrt
diff --git a/support/hololens/ServoApp/ServoControl/Servo.h b/support/hololens/ServoApp/ServoControl/Servo.h
index d662942f1da..d91d4daeffb 100644
--- a/support/hololens/ServoApp/ServoControl/Servo.h
+++ b/support/hololens/ServoApp/ServoControl/Servo.h
@@ -63,6 +63,8 @@ public:
void TouchMove(float x, float y, int32_t id) { touch_move(x, y, id); }
void TouchCancel(float x, float y, int32_t id) { touch_cancel(x, y, id); }
void MouseMove(float x, float y) { mouse_move(x, y); }
+ void KeyDown(const char *k) { key_down(k); }
+ void KeyUp(const char *k) { key_up(k); }
void Reload() { reload(); }
void Stop() { stop(); }
diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.cpp b/support/hololens/ServoApp/ServoControl/ServoControl.cpp
index 1b9fb910d6e..e430d713e7e 100644
--- a/support/hololens/ServoApp/ServoControl/ServoControl.cpp
+++ b/support/hololens/ServoApp/ServoControl/ServoControl.cpp
@@ -4,6 +4,7 @@
#include "ServoControl.g.cpp"
#include "Pref.g.cpp"
#include
+#include "Keys.h"
using namespace std::placeholders;
using namespace winrt::Windows::ApplicationModel::Resources;
@@ -11,6 +12,7 @@ using namespace winrt::Windows::Graphics::Display;
using namespace winrt::Windows::UI::Xaml;
using namespace winrt::Windows::UI::Popups;
using namespace winrt::Windows::UI::Core;
+using namespace winrt::Windows::UI::Text::Core;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::System;
using namespace winrt::Windows::Devices::Input;
@@ -66,21 +68,19 @@ void ServoControl::OnLoaded(IInspectable const &, RoutedEventArgs const &) {
std::bind(&ServoControl::OnSurfacePointerMoved, this, _1, _2));
panel.PointerWheelChanged(
std::bind(&ServoControl::OnSurfaceWheelChanged, this, _1, _2));
- panel.ManipulationStarted(
- [=](IInspectable const &,
- Input::ManipulationStartedRoutedEventArgs const &e) {
- mOnCaptureGesturesStartedEvent();
- e.Handled(true);
- });
- panel.ManipulationCompleted(
- [=](IInspectable const &,
- Input::ManipulationCompletedRoutedEventArgs const &e) {
- mOnCaptureGesturesEndedEvent();
- e.Handled(true);
- });
+ panel.ManipulationStarted([=](const auto &, const auto &e) {
+ mOnCaptureGesturesStartedEvent();
+ e.Handled(true);
+ });
+ panel.ManipulationCompleted([=](const auto &, const auto &e) {
+ mOnCaptureGesturesEndedEvent();
+ e.Handled(true);
+ });
panel.ManipulationDelta(
std::bind(&ServoControl::OnSurfaceManipulationDelta, this, _1, _2));
- Panel().SizeChanged(std::bind(&ServoControl::OnSurfaceResized, this, _1, _2));
+ panel.SizeChanged(std::bind(&ServoControl::OnSurfaceResized, this, _1, _2));
+
+ InitializeTextController();
InitializeConditionVariable(&mGLCondVar);
InitializeCriticalSection(&mGLLock);
InitializeConditionVariable(&mDialogCondVar);
@@ -89,6 +89,54 @@ void ServoControl::OnLoaded(IInspectable const &, RoutedEventArgs const &) {
StartRenderLoop();
}
+void ServoControl::InitializeTextController() {
+ mInputPane = Windows::UI::ViewManagement::InputPane::GetForCurrentView();
+ auto manager = CoreTextServicesManager::GetForCurrentView();
+ mEditContext = manager.CreateEditContext();
+ mEditContext->InputPaneDisplayPolicy(CoreTextInputPaneDisplayPolicy::Manual);
+ mEditContext->InputScope(CoreTextInputScope::Text);
+ mEditContext->TextRequested([=](const auto &, const auto &e) {
+ e.Request().Text(L"");
+ CoreTextRange sel;
+ sel.StartCaretPosition = 0;
+ sel.EndCaretPosition = 0;
+ e.Request().Range() = sel;
+ });
+
+ mEditContext->TextUpdating([=](const auto &, const auto &e) {
+ RunOnGLThread([=] {
+ auto keystr = *hstring2char((e.Text()));
+ mServo->KeyDown(keystr);
+ });
+ });
+
+ mEditContext->SelectionRequested([](const auto &, const auto &) {});
+
+ GotFocus(
+ [=](const auto &, const auto &) { mEditContext->NotifyFocusEnter(); });
+ LostFocus(
+ [=](const auto &, const auto &) { mEditContext->NotifyFocusLeave(); });
+
+ PreviewKeyDown([=](const auto &, const auto &e) {
+ auto keystr = KeyToString(e.Key());
+ if (keystr.has_value()) {
+ RunOnGLThread([=] {
+ auto keyname = *keystr;
+ mServo->KeyDown(keyname);
+ });
+ }
+ });
+ PreviewKeyUp([=](const auto &, const auto &e) {
+ auto keystr = KeyToString(e.Key());
+ if (keystr.has_value()) {
+ RunOnGLThread([=] {
+ auto keyname = *keystr;
+ mServo->KeyUp(keyname);
+ });
+ }
+ });
+}
+
Controls::SwapChainPanel ServoControl::Panel() {
return GetTemplateChild(L"swapChainPanel").as();
}
@@ -128,6 +176,7 @@ void ServoControl::OnSurfaceManipulationDelta(
void ServoControl::OnSurfaceTapped(IInspectable const &,
Input::TappedRoutedEventArgs const &e) {
+ Focus(FocusState::Programmatic);
if (e.PointerDeviceType() == PointerDeviceType::Mouse) {
auto coords = e.GetPosition(Panel());
auto x = coords.X * mDPI;
@@ -439,9 +488,14 @@ void ServoControl::OnServoAnimatingChanged(bool animating) {
WakeConditionVariable(&mGLCondVar);
}
-void ServoControl::OnServoIMEStateChanged(bool) {
- // FIXME:
- // https://docs.microsoft.com/en-us/windows/win32/winauto/uiauto-implementingtextandtextrange
+void ServoControl::OnServoIMEStateChanged(bool focused) {
+ RunOnUIThread([=] {
+ if (focused) {
+ mInputPane->TryShow();
+ } else {
+ mInputPane->TryHide();
+ }
+ });
}
void ServoControl::OnServoMediaSessionMetadata(hstring title, hstring artist,
diff --git a/support/hololens/ServoApp/ServoControl/ServoControl.h b/support/hololens/ServoApp/ServoControl/ServoControl.h
index 56d32e2a12c..8437c7930ff 100644
--- a/support/hololens/ServoApp/ServoControl/ServoControl.h
+++ b/support/hololens/ServoApp/ServoControl/ServoControl.h
@@ -265,6 +265,7 @@ private:
void RunOnGLThread(std::function);
void TryLoadUri(hstring);
+ void InitializeTextController();
std::unique_ptr mServo;
PropertySet mNativeWindowProperties;
@@ -278,6 +279,9 @@ private:
hstring mArgs;
std::optional mPressedMouseButton = {};
std::unique_ptr mL10NStrings = nullptr;
+
+ std::optional mEditContext;
+ std::optional mInputPane;
};
} // namespace winrt::ServoApp::implementation
diff --git a/support/hololens/ServoApp/pch.h b/support/hololens/ServoApp/pch.h
index 49cffb0f3ab..66759332c62 100644
--- a/support/hololens/ServoApp/pch.h
+++ b/support/hololens/ServoApp/pch.h
@@ -60,6 +60,7 @@
#include
#include
#include
+#include
#include
#include
#include