From f57cfabe1f663016b24ee8ff5c611ec1509dca08 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Mon, 9 Oct 2023 10:54:21 +0800 Subject: [PATCH 01/12] Add UnhandledKeyPressed.md This is an API spec review for the UnhandledKeyPressed API. --- specs/UnhandledKeyPressed.md | 229 +++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 specs/UnhandledKeyPressed.md diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md new file mode 100644 index 000000000..4972eace4 --- /dev/null +++ b/specs/UnhandledKeyPressed.md @@ -0,0 +1,229 @@ + +# Background +Consumers of the old [WebBrowser](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.webbrowser?view=windowsdesktop-7.0) control that relied on the [OnKeyDown](https://learn.microsoft.com/previous-versions/aa752133(v=vs.85)) API that allowed them to receive and handle key events not handled by the browser, [requested](https://github.com/MicrosoftEdge/WebViewFeedback/issues/468) same ability in WebView2. + +# Description +The `UnhandledKeyPressed` event allows developers to subscribe event handlers +to be run when a key event is not handled by the browser (including DOM and browser accelerators). It can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. + +`UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use UnhandledKeyPressedEventArgs::GetKeyState() +instead to verify whether Ctrl or Alt is down in this situation. + +# Examples + +```cpp + auto controller5 = m_controller.try_query(); + if (controller5) + { + CHECK_FAILURE(m_controller->add_UnhandledKeyPressed( + Callback( + [this]( + ICoreWebView2Controller* sender, + ICoreWebView2UnhandledKeyPressedEventArgs* args) -> HRESULT + { + COREWEBVIEW2_KEY_EVENT_KIND kind; + CHECK_FAILURE(args->get_KeyEventKind(&kind)); + + // We only care about key down events. + if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN || + kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN) + { + COREWEBVIEW2_KEY_PRESSED_FLAG_KIND flag; + CHECK_FAILURE(args->get_Modifiers(&flag)); + if (flag & COREWEBVIEW2_KEY_EVENT_FLAG_CONTROL_DOWN) + { + UINT key; + CHECK_FAILURE(args->get_VirtualKey(&key)); + // Check if the key is one we want to handle. + if (key == 'Z') + { + MessageBox( + nullptr, + L"Key combination Ctrl + Z unhandled by browser is " + L"triggered.", + L"", MB_OK); + } + else if (key >= 'A' && key <= 'Z') + { + OutputDebugString((std::wstring(L"Ctrl +") + (wchar_t)key + + L" not handled by browser is triggered.") + .c_str()); + } + } + } + return S_OK; + }) + .Get(), + &m_unhandledKeyPressedToken)); + } +``` + +```csharp +private CoreWebView2Controller controller; +void RegisterKeyEventHandlers() +{ + // Disable external drop while navigating. + if (controller != null) + { + controller.UnhandledKeyPressed += CoreWebView2Controller_UnhandledKeyPressed; + } +} +void CoreWebView2Controller_UnhandledKeyPressed(object sender, CoreWebView2UnhandledKeyPressedEventArgs e) +{ + if (e.KeyEventKind == CoreWebView2KeyEventKind.KeyDown &&(e.Modifiers & CoreWebView2KeyEventFlagControlDown)){ + if (e.VirtualKey == 'z') { + Debug.WriteLine($"Key combination Ctrl + Z unhandled by browser is triggered."); + } + } +} +``` + +# API Details +```idl +/// Flag bits representing the state of keyboard when a "UnhandledKeyPressed" Event happens. +[v1_enum] +typedef enum COREWEBVIEW2_KEY_PRESSED_FLAG_KIND { + + /// No additional keys pressed. + COREWEBVIEW2_KEY_EVENT_FLAG_NONE = 0, + + /// SHIFT is down, VK_SHIFT. + COREWEBVIEW2_KEY_EVENT_FLAG_SHIFT_DOWN = 1 << 1, + + /// Control is down, VK_CONTROL. + COREWEBVIEW2_KEY_EVENT_FLAG_CONTROL_DOWN = 1 << 2, + + /// ALT is down, VK_MENU. + /// This bit is 0 when COREWEBVIEW2_KEY_EVENT_FLAG_ALTGR_DOWN bit is 1. + COREWEBVIEW2_KEY_EVENT_FLAG_ALT_DOWN = 1 << 3, + + /// Windows key is down. VK_LWIN | VK_RWIN + COREWEBVIEW2_KEY_EVENT_FLAG_COMMAND_DOWN = 1 << 4, + + /// Right ALT is down and AltGraph is enabled. + COREWEBVIEW2_KEY_EVENT_FLAG_ALTGR_DOWN = 1 << 6, + + /// NUMLOCK is on. VK_NUMLOCK. + COREWEBVIEW2_KEY_EVENT_FLAG_NUM_LOCK_ON = 1 << 8, + + /// CapsLock is on. VK_CAPITAL. + COREWEBVIEW2_KEY_EVENT_FLAG_CAPS_LOCK_ON = 1 << 9, + + /// ScrollLock is On. VK_SCROLL. + COREWEBVIEW2_KEY_EVENT_FLAG_SCROLL_LOCK_ON = 1 << 10, +} COREWEBVIEW2_KEY_PRESSED_FLAG_KIND; + +[uuid(dd30e20c-d1b3-4e51-9bb6-1be7aaa3ce90), object, pointer_default(unique)] +interface ICoreWebView2UnhandledKeyPressedEventArgs : IUnknown { + + /// The key event type that caused the event to run. + + [propget] HRESULT KeyEventKind([out, retval] COREWEBVIEW2_KEY_EVENT_KIND* keyEventKind); + + /// The Win32 virtual key code of the key that was pressed or released. It + /// is one of the Win32 virtual key constants such as `VK_RETURN` or an + /// (uppercase) ASCII value such as `A`. + /// use ICoreWebView2UnhandledKeyPressedEventArgs::GetKeyState() + /// instead of Win32 API ::GetKeyState() to verify whether Ctrl or Alt + /// is pressed. + + [propget] HRESULT VirtualKey([out, retval] UINT* virtualKey); + + /// The `LPARAM` value that accompanied the window message. For more + /// information, navigate to [WM_KEYDOWN](/windows/win32/inputdev/wm-keydown) + /// and [WM_KEYUP](/windows/win32/inputdev/wm-keyup). + /// For visual hosting, only scan code and extended key (16-24bit) are provided. + /// For other bits, check out the origin message from ::GetMessage(). + + [propget] HRESULT KeyEventLParam([out, retval] INT* lParam); + + /// A structure representing the information passed in the `LPARAM` of the + /// window message. + + [propget] HRESULT PhysicalKeyStatus( + [out, retval] COREWEBVIEW2_PHYSICAL_KEY_STATUS* physicalKeyStatus); + + /// The `Handled` property will not influence the future WebView + /// action. It can be used with other UnhandledKeyPressed + /// Event handlers. + + [propget] HRESULT Handled([out, retval] BOOL* handled); + + /// Sets the `Handled` property. + + [propput] HRESULT Handled([in] BOOL handled); + + /// Retrieves the status of the keyboard when the key event is triggered. + /// Use this instead of ::GetKeyState(). + /// See COREWEBVIEW2_KEY_PRESSED_FLAG_KIND for details. + [propget] HRESULT Modifiers([out, retval] COREWEBVIEW2_KEY_PRESSED_FLAG_KIND* modifiers); +} + +/// Receives `KeyPressed` events. + +[uuid(dc83113b-ce7a-47bb-9661-16b03ff8aac1), object, pointer_default(unique)] +interface ICoreWebView2UnhandledKeyPressedEventHandler : IUnknown { + + /// Provides the event args for the corresponding event. + + HRESULT Invoke( + [in] ICoreWebView2Controller* sender, + [in] ICoreWebView2UnhandledKeyPressedEventArgs* args); +} + +[uuid(053b9a5d-7033-4515-9898-912977d2fde8), object, pointer_default(unique)] +interface ICoreWebView2Controller : IUnknown { + /// Adds an event handler for the `UnhandledKeyPressed` event. + /// `UnhandledKeyPressed` runs when an key is not handled in + /// the DOM. + + HRESULT add_UnhandledKeyPressed( + [in] ICoreWebView2UnhandledKeyPressedEventHandler* eventHandler, + [out] EventRegistrationToken* token); + + /// Removes an event handler previously added with + /// `add_UnhandledKeyPressed`. + + HRESULT remove_UnhandledKeyPressed( + [in] EventRegistrationToken token); +} +``` + +```c# +namespace Microsoft.Web.WebView2.Core +{ + public class CoreWebView2Controller + { + event EventHandler UnhandledKeyPressed; + } + + [Flags] enum CoreWebView2KeyPressedFlagKind + { + CoreWebView2KeyEventFlagNone = 0, + CoreWebView2KeyEventFlagShiftDown = 2, + CoreWebView2KeyEventFlagControlDown = 4, + CoreWebView2KeyEventFlagAltDown = 8, + CoreWebView2KeyEventFlagCommandDown = 16, + CoreWebView2KeyEventFlagAltgrDown = 64, + CoreWebView2KeyEventFlagNumLockOn = 256, + CoreWebView2KeyEventFlagCapsLockOn = 512, + CoreWebView2KeyEventFlagScrollLockOn = 1024, + } + + /// Event args for the `CoreWebView2Controller.UnhandledKeyPressed` event. + runtimeclass CoreWebView2UnhandledKeyPressedEventArgs + { + CoreWebView2KeyEventKind KeyEventKind { get; }; + + uint VirtualKey { get; }; + + int KeyEventLParam { get; }; + + CoreWebView2PhysicalKeyStatus PhysicalKeyStatus { get; }; + + bool Handled { get; set; }; + + CoreWebView2KeyPressedFlagKind Modifiers { get; }; + } +} +``` From 510f895d9c435df63b0b2b0ccfef13bc2406aa3f Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:03:34 +0800 Subject: [PATCH 02/12] fix typo --- specs/UnhandledKeyPressed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 4972eace4..f9c2ef203 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -15,7 +15,7 @@ instead to verify whether Ctrl or Alt is down in this situation. auto controller5 = m_controller.try_query(); if (controller5) { - CHECK_FAILURE(m_controller->add_UnhandledKeyPressed( + CHECK_FAILURE(controller5->add_UnhandledKeyPressed( Callback( [this]( ICoreWebView2Controller* sender, From 7cbe5513d386c802afd1b9eb39deee6e654434a4 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:18:13 +0800 Subject: [PATCH 03/12] reorganize --- specs/UnhandledKeyPressed.md | 136 ++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 67 deletions(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index f9c2ef203..47d4d59c8 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -6,10 +6,10 @@ Consumers of the old [WebBrowser](https://learn.microsoft.com/en-us/dotnet/api/s The `UnhandledKeyPressed` event allows developers to subscribe event handlers to be run when a key event is not handled by the browser (including DOM and browser accelerators). It can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. -`UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use UnhandledKeyPressedEventArgs::GetKeyState() -instead to verify whether Ctrl or Alt is down in this situation. +`UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use UnhandledKeyPressedEventArgs.Modifiers instead to verify whether Ctrl or Alt is down in this situation. # Examples +## C++ ```cpp auto controller5 = m_controller.try_query(); @@ -58,6 +58,8 @@ instead to verify whether Ctrl or Alt is down in this situation. } ``` +## C# + ```csharp private CoreWebView2Controller controller; void RegisterKeyEventHandlers() @@ -70,48 +72,44 @@ void RegisterKeyEventHandlers() } void CoreWebView2Controller_UnhandledKeyPressed(object sender, CoreWebView2UnhandledKeyPressedEventArgs e) { - if (e.KeyEventKind == CoreWebView2KeyEventKind.KeyDown &&(e.Modifiers & CoreWebView2KeyEventFlagControlDown)){ - if (e.VirtualKey == 'z') { - Debug.WriteLine($"Key combination Ctrl + Z unhandled by browser is triggered."); + if ((e.KeyEventKind == CoreWebView2KeyEventKind.KeyDown) && (e.Modifiers & CoreWebView2KeyPressedFlagKind.CoreWebView2KeyEventFlagControlDown) != 0) + { + if (e.VirtualKey == 'z') + { + Debug.WriteLine($"Key combination Ctrl + Z unhandled by browser is triggered."); + } } - } } ``` # API Details ```idl -/// Flag bits representing the state of keyboard when a "UnhandledKeyPressed" Event happens. -[v1_enum] -typedef enum COREWEBVIEW2_KEY_PRESSED_FLAG_KIND { - - /// No additional keys pressed. - COREWEBVIEW2_KEY_EVENT_FLAG_NONE = 0, - - /// SHIFT is down, VK_SHIFT. - COREWEBVIEW2_KEY_EVENT_FLAG_SHIFT_DOWN = 1 << 1, - - /// Control is down, VK_CONTROL. - COREWEBVIEW2_KEY_EVENT_FLAG_CONTROL_DOWN = 1 << 2, +[uuid(053b9a5d-7033-4515-9898-912977d2fde8), object, pointer_default(unique)] +interface ICoreWebView2Controller : IUnknown { + /// Adds an event handler for the `UnhandledKeyPressed` event. + /// `UnhandledKeyPressed` runs when an key is not handled in + /// the DOM. - /// ALT is down, VK_MENU. - /// This bit is 0 when COREWEBVIEW2_KEY_EVENT_FLAG_ALTGR_DOWN bit is 1. - COREWEBVIEW2_KEY_EVENT_FLAG_ALT_DOWN = 1 << 3, + HRESULT add_UnhandledKeyPressed( + [in] ICoreWebView2UnhandledKeyPressedEventHandler* eventHandler, + [out] EventRegistrationToken* token); - /// Windows key is down. VK_LWIN | VK_RWIN - COREWEBVIEW2_KEY_EVENT_FLAG_COMMAND_DOWN = 1 << 4, + /// Removes an event handler previously added with + /// `add_UnhandledKeyPressed`. - /// Right ALT is down and AltGraph is enabled. - COREWEBVIEW2_KEY_EVENT_FLAG_ALTGR_DOWN = 1 << 6, + HRESULT remove_UnhandledKeyPressed( + [in] EventRegistrationToken token); +} - /// NUMLOCK is on. VK_NUMLOCK. - COREWEBVIEW2_KEY_EVENT_FLAG_NUM_LOCK_ON = 1 << 8, +[uuid(dc83113b-ce7a-47bb-9661-16b03ff8aac1), object, pointer_default(unique)] +interface ICoreWebView2UnhandledKeyPressedEventHandler : IUnknown { - /// CapsLock is on. VK_CAPITAL. - COREWEBVIEW2_KEY_EVENT_FLAG_CAPS_LOCK_ON = 1 << 9, + /// Provides the event args for the corresponding event. - /// ScrollLock is On. VK_SCROLL. - COREWEBVIEW2_KEY_EVENT_FLAG_SCROLL_LOCK_ON = 1 << 10, -} COREWEBVIEW2_KEY_PRESSED_FLAG_KIND; + HRESULT Invoke( + [in] ICoreWebView2Controller* sender, + [in] ICoreWebView2UnhandledKeyPressedEventArgs* args); +} [uuid(dd30e20c-d1b3-4e51-9bb6-1be7aaa3ce90), object, pointer_default(unique)] interface ICoreWebView2UnhandledKeyPressedEventArgs : IUnknown { @@ -123,7 +121,7 @@ interface ICoreWebView2UnhandledKeyPressedEventArgs : IUnknown { /// The Win32 virtual key code of the key that was pressed or released. It /// is one of the Win32 virtual key constants such as `VK_RETURN` or an /// (uppercase) ASCII value such as `A`. - /// use ICoreWebView2UnhandledKeyPressedEventArgs::GetKeyState() + /// use ICoreWebView2UnhandledKeyPressedEventArgs::get_Modifiers() /// instead of Win32 API ::GetKeyState() to verify whether Ctrl or Alt /// is pressed. @@ -159,34 +157,38 @@ interface ICoreWebView2UnhandledKeyPressedEventArgs : IUnknown { [propget] HRESULT Modifiers([out, retval] COREWEBVIEW2_KEY_PRESSED_FLAG_KIND* modifiers); } -/// Receives `KeyPressed` events. +/// Flag bits representing the state of keyboard when a "UnhandledKeyPressed" Event happens. +[v1_enum] +typedef enum COREWEBVIEW2_KEY_PRESSED_FLAG_KIND { + + /// No additional keys pressed. + COREWEBVIEW2_KEY_EVENT_FLAG_NONE = 0, -[uuid(dc83113b-ce7a-47bb-9661-16b03ff8aac1), object, pointer_default(unique)] -interface ICoreWebView2UnhandledKeyPressedEventHandler : IUnknown { + /// SHIFT is down, VK_SHIFT. + COREWEBVIEW2_KEY_EVENT_FLAG_SHIFT_DOWN = 1 << 1, - /// Provides the event args for the corresponding event. + /// Control is down, VK_CONTROL. + COREWEBVIEW2_KEY_EVENT_FLAG_CONTROL_DOWN = 1 << 2, - HRESULT Invoke( - [in] ICoreWebView2Controller* sender, - [in] ICoreWebView2UnhandledKeyPressedEventArgs* args); -} + /// ALT is down, VK_MENU. + /// This bit is 0 when COREWEBVIEW2_KEY_EVENT_FLAG_ALTGR_DOWN bit is 1. + COREWEBVIEW2_KEY_EVENT_FLAG_ALT_DOWN = 1 << 3, -[uuid(053b9a5d-7033-4515-9898-912977d2fde8), object, pointer_default(unique)] -interface ICoreWebView2Controller : IUnknown { - /// Adds an event handler for the `UnhandledKeyPressed` event. - /// `UnhandledKeyPressed` runs when an key is not handled in - /// the DOM. + /// Windows key is down. VK_LWIN | VK_RWIN + COREWEBVIEW2_KEY_EVENT_FLAG_COMMAND_DOWN = 1 << 4, - HRESULT add_UnhandledKeyPressed( - [in] ICoreWebView2UnhandledKeyPressedEventHandler* eventHandler, - [out] EventRegistrationToken* token); + /// Right ALT is down and AltGraph is enabled. + COREWEBVIEW2_KEY_EVENT_FLAG_ALTGR_DOWN = 1 << 6, - /// Removes an event handler previously added with - /// `add_UnhandledKeyPressed`. + /// NUMLOCK is on. VK_NUMLOCK. + COREWEBVIEW2_KEY_EVENT_FLAG_NUM_LOCK_ON = 1 << 8, - HRESULT remove_UnhandledKeyPressed( - [in] EventRegistrationToken token); -} + /// CapsLock is on. VK_CAPITAL. + COREWEBVIEW2_KEY_EVENT_FLAG_CAPS_LOCK_ON = 1 << 9, + + /// ScrollLock is On. VK_SCROLL. + COREWEBVIEW2_KEY_EVENT_FLAG_SCROLL_LOCK_ON = 1 << 10, +} COREWEBVIEW2_KEY_PRESSED_FLAG_KIND; ``` ```c# @@ -197,19 +199,6 @@ namespace Microsoft.Web.WebView2.Core event EventHandler UnhandledKeyPressed; } - [Flags] enum CoreWebView2KeyPressedFlagKind - { - CoreWebView2KeyEventFlagNone = 0, - CoreWebView2KeyEventFlagShiftDown = 2, - CoreWebView2KeyEventFlagControlDown = 4, - CoreWebView2KeyEventFlagAltDown = 8, - CoreWebView2KeyEventFlagCommandDown = 16, - CoreWebView2KeyEventFlagAltgrDown = 64, - CoreWebView2KeyEventFlagNumLockOn = 256, - CoreWebView2KeyEventFlagCapsLockOn = 512, - CoreWebView2KeyEventFlagScrollLockOn = 1024, - } - /// Event args for the `CoreWebView2Controller.UnhandledKeyPressed` event. runtimeclass CoreWebView2UnhandledKeyPressedEventArgs { @@ -225,5 +214,18 @@ namespace Microsoft.Web.WebView2.Core CoreWebView2KeyPressedFlagKind Modifiers { get; }; } + + [Flags] enum CoreWebView2KeyPressedFlagKind + { + CoreWebView2KeyEventFlagNone = 0, + CoreWebView2KeyEventFlagShiftDown = 2, + CoreWebView2KeyEventFlagControlDown = 4, + CoreWebView2KeyEventFlagAltDown = 8, + CoreWebView2KeyEventFlagCommandDown = 16, + CoreWebView2KeyEventFlagAltgrDown = 64, + CoreWebView2KeyEventFlagNumLockOn = 256, + CoreWebView2KeyEventFlagCapsLockOn = 512, + CoreWebView2KeyEventFlagScrollLockOn = 1024, + } } ``` From 4536ed6fb5f33589f3fbb7249db6302c0feb01da Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Mon, 9 Oct 2023 11:18:56 +0800 Subject: [PATCH 04/12] fix typo --- specs/UnhandledKeyPressed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 47d4d59c8..91eca28a5 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -6,7 +6,7 @@ Consumers of the old [WebBrowser](https://learn.microsoft.com/en-us/dotnet/api/s The `UnhandledKeyPressed` event allows developers to subscribe event handlers to be run when a key event is not handled by the browser (including DOM and browser accelerators). It can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. -`UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use UnhandledKeyPressedEventArgs.Modifiers instead to verify whether Ctrl or Alt is down in this situation. +`UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. # Examples ## C++ From f2131a32163ec637fb0251627597c3b33792c743 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:20:35 +0800 Subject: [PATCH 05/12] fix typo --- specs/UnhandledKeyPressed.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 91eca28a5..e9e659b10 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -3,8 +3,9 @@ Consumers of the old [WebBrowser](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.webbrowser?view=windowsdesktop-7.0) control that relied on the [OnKeyDown](https://learn.microsoft.com/previous-versions/aa752133(v=vs.85)) API that allowed them to receive and handle key events not handled by the browser, [requested](https://github.com/MicrosoftEdge/WebViewFeedback/issues/468) same ability in WebView2. # Description -The `UnhandledKeyPressed` event allows developers to subscribe event handlers -to be run when a key event is not handled by the browser (including DOM and browser accelerators). It can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. +The `UnhandledKeyPressed` event allows developers to subscribe event handlers to be run when a key event is not handled by the browser (including DOM and browser accelerators). + +`UnhandledKeyPressed` event can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. `UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. @@ -83,6 +84,8 @@ void CoreWebView2Controller_UnhandledKeyPressed(object sender, CoreWebView2Unhan ``` # API Details + +## Win32 C++ ```idl [uuid(053b9a5d-7033-4515-9898-912977d2fde8), object, pointer_default(unique)] interface ICoreWebView2Controller : IUnknown { @@ -191,6 +194,7 @@ typedef enum COREWEBVIEW2_KEY_PRESSED_FLAG_KIND { } COREWEBVIEW2_KEY_PRESSED_FLAG_KIND; ``` +## .NET and WinRT ```c# namespace Microsoft.Web.WebView2.Core { From 5ebd58794071e9c87bff5204d2811594b0ed1015 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:21:53 +0800 Subject: [PATCH 06/12] add ref --- specs/UnhandledKeyPressed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index e9e659b10..0c098562c 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -7,7 +7,7 @@ The `UnhandledKeyPressed` event allows developers to subscribe event handlers to `UnhandledKeyPressed` event can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. -`UnhandledKeyPressed` event is async, which means 'GetKeyStates' does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. +`UnhandledKeyPressed` event is async, which means [GetKeyStates](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate) does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. # Examples ## C++ From fa80d922891478e5a1d32c73483cf5e13c2d3b37 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:22:57 +0800 Subject: [PATCH 07/12] fix typo --- specs/UnhandledKeyPressed.md | 90 ++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 0c098562c..04af67474 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -7,56 +7,56 @@ The `UnhandledKeyPressed` event allows developers to subscribe event handlers to `UnhandledKeyPressed` event can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. -`UnhandledKeyPressed` event is async, which means [GetKeyStates](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate) does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. +`UnhandledKeyPressed` event is async, which means [GetKeyState](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate) does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. # Examples ## C++ ```cpp - auto controller5 = m_controller.try_query(); - if (controller5) - { - CHECK_FAILURE(controller5->add_UnhandledKeyPressed( - Callback( - [this]( - ICoreWebView2Controller* sender, - ICoreWebView2UnhandledKeyPressedEventArgs* args) -> HRESULT - { - COREWEBVIEW2_KEY_EVENT_KIND kind; - CHECK_FAILURE(args->get_KeyEventKind(&kind)); - - // We only care about key down events. - if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN || - kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN) - { - COREWEBVIEW2_KEY_PRESSED_FLAG_KIND flag; - CHECK_FAILURE(args->get_Modifiers(&flag)); - if (flag & COREWEBVIEW2_KEY_EVENT_FLAG_CONTROL_DOWN) - { - UINT key; - CHECK_FAILURE(args->get_VirtualKey(&key)); - // Check if the key is one we want to handle. - if (key == 'Z') - { - MessageBox( - nullptr, - L"Key combination Ctrl + Z unhandled by browser is " - L"triggered.", - L"", MB_OK); - } - else if (key >= 'A' && key <= 'Z') - { - OutputDebugString((std::wstring(L"Ctrl +") + (wchar_t)key + - L" not handled by browser is triggered.") - .c_str()); - } - } - } - return S_OK; - }) - .Get(), - &m_unhandledKeyPressedToken)); - } +auto controller5 = m_controller.try_query(); +if (controller5) +{ + CHECK_FAILURE(controller5->add_UnhandledKeyPressed( + Callback( + [this]( + ICoreWebView2Controller* sender, + ICoreWebView2UnhandledKeyPressedEventArgs* args) -> HRESULT + { + COREWEBVIEW2_KEY_EVENT_KIND kind; + CHECK_FAILURE(args->get_KeyEventKind(&kind)); + + // We only care about key down events. + if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN || + kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN) + { + COREWEBVIEW2_KEY_PRESSED_FLAG_KIND flag; + CHECK_FAILURE(args->get_Modifiers(&flag)); + if (flag & COREWEBVIEW2_KEY_EVENT_FLAG_CONTROL_DOWN) + { + UINT key; + CHECK_FAILURE(args->get_VirtualKey(&key)); + // Check if the key is one we want to handle. + if (key == 'Z') + { + MessageBox( + nullptr, + L"Key combination Ctrl + Z unhandled by browser is " + L"triggered.", + L"", MB_OK); + } + else if (key >= 'A' && key <= 'Z') + { + OutputDebugString((std::wstring(L"Ctrl +") + (wchar_t)key + + L" not handled by browser is triggered.") + .c_str()); + } + } + } + return S_OK; + }) + .Get(), + &m_unhandledKeyPressedToken)); +} ``` ## C# From 4014578f432771f2863e56db661bde1f3e5f10d0 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:55:53 +0800 Subject: [PATCH 08/12] fix typo --- specs/UnhandledKeyPressed.md | 1 - 1 file changed, 1 deletion(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 04af67474..283dd9dc6 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -65,7 +65,6 @@ if (controller5) private CoreWebView2Controller controller; void RegisterKeyEventHandlers() { - // Disable external drop while navigating. if (controller != null) { controller.UnhandledKeyPressed += CoreWebView2Controller_UnhandledKeyPressed; From a35bc78341ab5f534f1ec995483c31be0438cd5f Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:18:09 +0800 Subject: [PATCH 09/12] resolve comments --- specs/UnhandledKeyPressed.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 283dd9dc6..7a71f503c 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -1,6 +1,10 @@ # Background -Consumers of the old [WebBrowser](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.webbrowser?view=windowsdesktop-7.0) control that relied on the [OnKeyDown](https://learn.microsoft.com/previous-versions/aa752133(v=vs.85)) API that allowed them to receive and handle key events not handled by the browser, [requested](https://github.com/MicrosoftEdge/WebViewFeedback/issues/468) same ability in WebView2. +Consumers of the old [WebBrowser](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.webbrowser?view=windowsdesktop-7.0) +control that relied on the [OnKeyDown](https://learn.microsoft.com/previous-versions/aa752133(v=vs.85)) API that allowed +them to receive and handle key events not handled by the browser, +[requested](https://github.com/MicrosoftEdge/WebViewFeedback/issues/468) +same ability in WebView2. # Description The `UnhandledKeyPressed` event allows developers to subscribe event handlers to be run when a key event is not handled by the browser (including DOM and browser accelerators). @@ -26,8 +30,7 @@ if (controller5) CHECK_FAILURE(args->get_KeyEventKind(&kind)); // We only care about key down events. - if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN || - kind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN) + if (kind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN) { COREWEBVIEW2_KEY_PRESSED_FLAG_KIND flag; CHECK_FAILURE(args->get_Modifiers(&flag)); @@ -38,6 +41,8 @@ if (controller5) // Check if the key is one we want to handle. if (key == 'Z') { + // Raised when not focused in an edit control, or + // there is nothing to undo in an edit control. MessageBox( nullptr, L"Key combination Ctrl + Z unhandled by browser is " @@ -72,11 +77,18 @@ void RegisterKeyEventHandlers() } void CoreWebView2Controller_UnhandledKeyPressed(object sender, CoreWebView2UnhandledKeyPressedEventArgs e) { - if ((e.KeyEventKind == CoreWebView2KeyEventKind.KeyDown) && (e.Modifiers & CoreWebView2KeyPressedFlagKind.CoreWebView2KeyEventFlagControlDown) != 0) + if ((e.KeyEventKind == CoreWebView2KeyEventKind.KeyDown) && + (e.Modifiers & CoreWebView2KeyPressedFlagKind.CoreWebView2KeyEventFlagControlDown) != 0) { - if (e.VirtualKey == 'z') + if (e.VirtualKey == 'Z') { - Debug.WriteLine($"Key combination Ctrl + Z unhandled by browser is triggered."); + // Raised when not focused in an edit control, or + // there is nothing to undo in an edit control. + MessageBox.Show("Key combination Ctrl + Z unhandled by browser is triggered."); + } + else if (e.VirtualKey >= 'A' && e.VirtualKey <= 'Z') + { + Debug.WriteLine($"Ctrl + {(char)e.VirtualKey} not handled by browser is triggered."); } } } @@ -89,8 +101,10 @@ void CoreWebView2Controller_UnhandledKeyPressed(object sender, CoreWebView2Unhan [uuid(053b9a5d-7033-4515-9898-912977d2fde8), object, pointer_default(unique)] interface ICoreWebView2Controller : IUnknown { /// Adds an event handler for the `UnhandledKeyPressed` event. - /// `UnhandledKeyPressed` runs when an key is not handled in - /// the DOM. + /// `UnhandledKeyPressed` will be raised ONLY IF ALL of the following conditions are met: + /// 1. The key event has not been marked as handled in the 'AcceleratorKeyPressed' event. + /// 2. The key event is not consumed in the DOM (e.g., through calling event.preventDefault()). + /// 3. The event is not recognized or taken over by standard browser shortcuts (like ctrl + F, ctrl + P, etc). HRESULT add_UnhandledKeyPressed( [in] ICoreWebView2UnhandledKeyPressedEventHandler* eventHandler, From 8a6f2f088deed2af4d0984aed3de23831b3e450c Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:00:31 +0800 Subject: [PATCH 10/12] Update specs/UnhandledKeyPressed.md Co-authored-by: David Risney --- specs/UnhandledKeyPressed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index 7a71f503c..eb49757b7 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -103,7 +103,7 @@ interface ICoreWebView2Controller : IUnknown { /// Adds an event handler for the `UnhandledKeyPressed` event. /// `UnhandledKeyPressed` will be raised ONLY IF ALL of the following conditions are met: /// 1. The key event has not been marked as handled in the 'AcceleratorKeyPressed' event. - /// 2. The key event is not consumed in the DOM (e.g., through calling event.preventDefault()). + /// 2. The key press is not consumed in the DOM. For example, a JavaScript handler for the document's keydown event calling `event.preventDefault()` would handle the key press and the `UnhandledKeyPressed` event will not be raised. /// 3. The event is not recognized or taken over by standard browser shortcuts (like ctrl + F, ctrl + P, etc). HRESULT add_UnhandledKeyPressed( From edc9e4bd9eec28884cad0a6b166d1eea738288f0 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:00:41 +0800 Subject: [PATCH 11/12] Update specs/UnhandledKeyPressed.md Co-authored-by: David Risney --- specs/UnhandledKeyPressed.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index eb49757b7..bcde62794 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -104,7 +104,7 @@ interface ICoreWebView2Controller : IUnknown { /// `UnhandledKeyPressed` will be raised ONLY IF ALL of the following conditions are met: /// 1. The key event has not been marked as handled in the 'AcceleratorKeyPressed' event. /// 2. The key press is not consumed in the DOM. For example, a JavaScript handler for the document's keydown event calling `event.preventDefault()` would handle the key press and the `UnhandledKeyPressed` event will not be raised. - /// 3. The event is not recognized or taken over by standard browser shortcuts (like ctrl + F, ctrl + P, etc). + /// 3. The key press is not handled by browser accelerators like ctrl + F, ctrl + P, and so on. HRESULT add_UnhandledKeyPressed( [in] ICoreWebView2UnhandledKeyPressedEventHandler* eventHandler, From cf1683b3546a5ead0cd64b1711a197c56e8a78a7 Mon Sep 17 00:00:00 2001 From: zhuhaichao518 <54018092+zhuhaichao518@users.noreply.github.com> Date: Wed, 25 Oct 2023 12:07:15 +0800 Subject: [PATCH 12/12] formatting UnhandledKeyPressed.md --- specs/UnhandledKeyPressed.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/specs/UnhandledKeyPressed.md b/specs/UnhandledKeyPressed.md index bcde62794..d771ee39f 100644 --- a/specs/UnhandledKeyPressed.md +++ b/specs/UnhandledKeyPressed.md @@ -7,11 +7,14 @@ them to receive and handle key events not handled by the browser, same ability in WebView2. # Description -The `UnhandledKeyPressed` event allows developers to subscribe event handlers to be run when a key event is not handled by the browser (including DOM and browser accelerators). +The `UnhandledKeyPressed` event allows developers to subscribe event handlers to be run when +a key event is not handled by the browser (including DOM and browser accelerators). `UnhandledKeyPressed` event can be triggered by all keys, which is different from [AcceleratorKeyPressed](https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2acceleratorkeypressedeventargs?view=webview2-dotnet-1.0.705.50) event. -`UnhandledKeyPressed` event is async, which means [GetKeyState](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate) does not return the exact key state when the key event is fired. Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. +`UnhandledKeyPressed` event is async, which means [GetKeyState](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeystate) +does not return the exact key state when the key event is fired. +Use `UnhandledKeyPressedEventArgs.Modifiers` instead to verify whether Ctrl or Alt is down in this situation. # Examples ## C++