diff --git a/change/react-native-windows-2019-10-28-10-44-55-keyboard.json b/change/react-native-windows-2019-10-28-10-44-55-keyboard.json new file mode 100644 index 00000000000..1e22476be3b --- /dev/null +++ b/change/react-native-windows-2019-10-28-10-44-55-keyboard.json @@ -0,0 +1,9 @@ +{ + "type": "prerelease", + "comment": "Support Keyboard events", + "packageName": "react-native-windows", + "email": "dida@ntdev.microsoft.com", + "commit": "45a2fb84e8cbe53ad7ea190efab3919124ffb90b", + "date": "2019-10-28T17:44:55.590Z", + "file": "D:\\react2\\react-native-windows\\change\\react-native-windows-2019-10-28-10-44-55-keyboard.json" +} \ No newline at end of file diff --git a/packages/playground/Samples/textinput.tsx b/packages/playground/Samples/textinput.tsx index 595cd757a39..53ac5cb107a 100644 --- a/packages/playground/Samples/textinput.tsx +++ b/packages/playground/Samples/textinput.tsx @@ -5,9 +5,37 @@ */ import * as React from 'react'; -import {AppRegistry, Button, StyleSheet, TextInput, View} from 'react-native'; +import { + AppRegistry, + Button, + StyleSheet, + TextInput, + Keyboard, + View, + KeyboardAvoidingView, +} from 'react-native'; export default class Bootstrap extends React.Component<{}, any> { + componentDidMount() { + Keyboard.addListener('keyboardDidShow', this.keyboardDidShow); + + Keyboard.addListener('keyboardDidHide', this.keyboardDidHide); + } + + keyboardDidShow = () => { + console.log('keyboardDidShow'); + }; + + keyboardDidHide = () => { + console.log('keyboardDidHide'); + }; + + componentWillUnmount() { + Keyboard.removeListener('keyboardDidShow', this.keyboardDidShow); + + Keyboard.removeListener('keyboardDidHide', this.keyboardDidHide); + } + state = { passwordHidden: true, text: '', @@ -82,6 +110,15 @@ export default class Bootstrap extends React.Component<{}, any> { } onPress={this.onPressShowPassword} /> + + + ); } diff --git a/vnext/ReactUWP/ReactUWP.vcxproj b/vnext/ReactUWP/ReactUWP.vcxproj index 5bfbd4d2a76..43b2c9bba20 100644 --- a/vnext/ReactUWP/ReactUWP.vcxproj +++ b/vnext/ReactUWP/ReactUWP.vcxproj @@ -252,6 +252,7 @@ + @@ -353,6 +354,7 @@ + diff --git a/vnext/ReactUWP/Views/ReactControl.cpp b/vnext/ReactUWP/Views/ReactControl.cpp index fd979a9c61d..74ef6ce672d 100644 --- a/vnext/ReactUWP/Views/ReactControl.cpp +++ b/vnext/ReactUWP/Views/ReactControl.cpp @@ -172,6 +172,9 @@ void ReactControl::AttachRoot() noexcept { if (!m_touchEventHandler) m_touchEventHandler = std::make_shared(m_reactInstance); + if (!m_SIPEventHandler) + m_SIPEventHandler = std::make_shared(m_reactInstance); + m_previewKeyboardEventHandlerOnRoot = std::make_shared(m_reactInstance); // Register callback from instance for errors @@ -268,6 +271,8 @@ void ReactControl::DetachInstance() { // Clear members with a dependency on the reactInstance m_touchEventHandler.reset(); + + m_SIPEventHandler.reset(); } } diff --git a/vnext/ReactUWP/Views/ReactControl.h b/vnext/ReactUWP/Views/ReactControl.h index 03db192607e..e6bd45f17e9 100644 --- a/vnext/ReactUWP/Views/ReactControl.h +++ b/vnext/ReactUWP/Views/ReactControl.h @@ -9,6 +9,7 @@ #include #include #include "IXamlRootView.h" +#include "SIPEventHandler.h" #include "TouchEventHandler.h" #include "Views/KeyboardEventHandler.h" @@ -75,6 +76,7 @@ class ReactControl : public std::enable_shared_from_this, public I std::shared_ptr m_moduleProvider; folly::dynamic m_initialProps; std::shared_ptr m_touchEventHandler; + std::shared_ptr m_SIPEventHandler; std::shared_ptr m_previewKeyboardEventHandlerOnRoot; int64_t m_rootTag = -1; diff --git a/vnext/ReactUWP/Views/SIPEventHandler.cpp b/vnext/ReactUWP/Views/SIPEventHandler.cpp new file mode 100644 index 00000000000..f3c7ec7c4b3 --- /dev/null +++ b/vnext/ReactUWP/Views/SIPEventHandler.cpp @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "SIPEventHandler.h" + +#include + +#include +#include + +namespace winrt { +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::ViewManagement::Core; +using namespace Windows::UI::Xaml; +} // namespace winrt +namespace react { +namespace uwp { + +SIPEventHandler::SIPEventHandler(const std::weak_ptr &reactInstance) + : m_wkReactInstance(reactInstance) { + auto coreInputView = winrt::CoreInputView::GetForCurrentView(); + if (coreInputView) { + m_occlusionsChanged_revoker = coreInputView.OcclusionsChanged( + winrt::auto_revoke, [=](auto &&, const winrt::CoreInputViewOcclusionsChangedEventArgs &e) { + if (!e.Handled()) { + winrt::Rect finalRect = winrt::RectHelper::Empty(); + winrt::IVectorView occlusions = e.Occlusions(); + for (uint32_t i = 0; i < occlusions.Size(); i++) { + winrt::CoreInputViewOcclusion occlusion = occlusions.GetAt(i); + if (occlusion.OcclusionKind() == winrt::CoreInputViewOcclusionKind::Docked) { + finalRect = winrt::RectHelper::Union(finalRect, occlusion.OccludingRect()); + } + } + + if (winrt::RectHelper::GetIsEmpty(finalRect)) { + folly::dynamic params = folly::dynamic::object("screenY", 0)("screenX", 0)("width", 0)("height", 0); + SendEvent("keyboardDidHide", std::move(params)); + } else { + folly::dynamic params = folly::dynamic::object( + "endCoordinates", + folly::dynamic::object("screenY", finalRect.Y)("screenX", finalRect.X)("width", finalRect.Width)( + "height", finalRect.Height)); + SendEvent("keyboardDidShow", std::move(params)); + } + } + }); + } +} + +SIPEventHandler::~SIPEventHandler() { + m_occlusionsChanged_revoker = {}; +} + +void SIPEventHandler::SendEvent(std::string &&eventName, folly::dynamic &¶meters) { + if (auto instance = m_wkReactInstance.lock()) { + instance->CallJsFunction( + "RCTDeviceEventEmitter", "emit", folly::dynamic::array(std::move(eventName), std::move(parameters))); + } +} +} // namespace uwp +} // namespace react diff --git a/vnext/ReactUWP/Views/SIPEventHandler.h b/vnext/ReactUWP/Views/SIPEventHandler.h new file mode 100644 index 00000000000..142bd258f55 --- /dev/null +++ b/vnext/ReactUWP/Views/SIPEventHandler.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once +#include + +#include +#include + +namespace winrt { +using namespace Windows::Foundation; +using namespace Windows::UI::ViewManagement::Core; +} // namespace winrt + +namespace react { +namespace uwp { + +class SIPEventHandler { + public: + SIPEventHandler(const std::weak_ptr &reactInstance); + virtual ~SIPEventHandler(); + + private: + void SendEvent(std::string &&eventName, folly::dynamic &¶meters); + std::weak_ptr m_wkReactInstance; + winrt::CoreInputView::OcclusionsChanged_revoker m_occlusionsChanged_revoker; +}; + +} // namespace uwp +} // namespace react