| File: System\Windows\Forms\Design\PbrsForward.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel.Design; namespace System.Windows.Forms.Design; internal partial class PbrsForward : IWindowTarget { private readonly Control _target; private readonly IWindowTarget _oldTarget; // We save the last key down so we can recreate the last message if we need to activate // the properties window. private Message _lastKeyDown; private List<BufferedKey>? _bufferedChars; private const int WM_PRIVATE_POSTCHAR = (int)PInvokeCore.WM_USER + 0x1598; private bool _postCharMessage; private IMenuCommandService? _menuCommandSvc; private readonly IServiceProvider _sp; private bool _ignoreMessages; public PbrsForward(Control target, IServiceProvider sp) { _target = target; _oldTarget = target.WindowTarget; _sp = sp; target.WindowTarget = this; } private IMenuCommandService? MenuCommandService { get { if (_menuCommandSvc is null && _sp is not null) { _menuCommandSvc = _sp.GetService<IMenuCommandService>(); } return _menuCommandSvc; } } private ISupportInSituService? InSituSupportService => _sp.GetService<ISupportInSituService>(); public void Dispose() => _target.WindowTarget = _oldTarget; /// <summary> /// Called when the window handle of the control has changed. /// </summary> void IWindowTarget.OnHandleChange(IntPtr newHandle) { } /// <summary> /// Called to do control-specific processing for this window. /// </summary> void IWindowTarget.OnMessage(ref Message m) { // Get the Designer for the currently selected item on the Designer... // SET STATE .. _ignoreMessages = false; // Here lets query for the ISupportInSituService. // If we find the service then ask if it has a designer which is interested // in getting the keychars by querying the IgnoreMessages. if (m.Msg is >= ((int)PInvokeCore.WM_KEYFIRST) and <= ((int)PInvokeCore.WM_KEYLAST) or >= ((int)PInvokeCore.WM_IME_STARTCOMPOSITION) and <= ((int)PInvokeCore.WM_IME_COMPOSITION)) { if (InSituSupportService is ISupportInSituService supportInSituService) { _ignoreMessages = supportInSituService.IgnoreMessages; } } switch (m.Msg) { case WM_PRIVATE_POSTCHAR: if (_bufferedChars is null) { return; } // recreate the keystroke to the newly activated window HWND hwnd; hwnd = !_ignoreMessages || InSituSupportService is not ISupportInSituService supportInSituService ? PInvoke.GetFocus() : (HWND)supportInSituService.GetEditWindow(); if (hwnd != m.HWnd) { foreach (BufferedKey bk in _bufferedChars) { if (bk.KeyChar.MsgInternal == PInvokeCore.WM_CHAR) { if (bk.KeyDown.MsgInternal != 0) { PInvokeCore.SendMessage(hwnd, PInvokeCore.WM_KEYDOWN, bk.KeyDown.WParamInternal, bk.KeyDown.LParamInternal); } PInvokeCore.SendMessage(hwnd, PInvokeCore.WM_CHAR, bk.KeyChar.WParamInternal, bk.KeyChar.LParamInternal); if (bk.KeyUp.MsgInternal != 0) { PInvokeCore.SendMessage(hwnd, PInvokeCore.WM_KEYUP, bk.KeyUp.WParamInternal, bk.KeyUp.LParamInternal); } } else { PInvokeCore.SendMessage(hwnd, bk.KeyChar.MsgInternal, bk.KeyChar.WParamInternal, bk.KeyChar.LParamInternal); } } } _bufferedChars.Clear(); return; case (int)PInvokeCore.WM_KEYDOWN: _lastKeyDown = m; break; case (int)PInvokeCore.WM_IME_ENDCOMPOSITION: case (int)PInvokeCore.WM_KEYUP: _lastKeyDown.Msg = 0; break; case (int)PInvokeCore.WM_CHAR: case (int)PInvokeCore.WM_IME_STARTCOMPOSITION: case (int)PInvokeCore.WM_IME_COMPOSITION: if ((Control.ModifierKeys & (Keys.Control | Keys.Alt)) != 0) { break; } _bufferedChars ??= []; _bufferedChars.Add(new BufferedKey(_lastKeyDown, m, _lastKeyDown)); if (!_ignoreMessages && MenuCommandService is not null) { // throw the properties window command, we will redo the keystroke when we actually // lose focus _postCharMessage = true; MenuCommandService.GlobalInvoke(StandardCommands.PropertiesWindow); } else if (_ignoreMessages && m.Msg != (int)PInvokeCore.WM_IME_COMPOSITION) { if (InSituSupportService is ISupportInSituService anotherSupportInSituService) { _postCharMessage = true; anotherSupportInSituService.HandleKeyChar(); } } if (_postCharMessage) { // If copy of message has been buffered for forwarding, eat the original now return; } break; case (int)PInvokeCore.WM_KILLFOCUS: if (_postCharMessage) { // Now that we've actually lost focus, post this message to the queue. This allows any activity // that's in the queue to settle down before our characters are posted to the queue. // // We post because we need to allow the focus to actually happen before we send our strokes so we // know where to send them. // // We can't use the wParam here because it may not be the actual window that needs to pick up // the strokes. PInvokeCore.PostMessage(_target, (MessageId)WM_PRIVATE_POSTCHAR); _postCharMessage = false; } break; } _oldTarget?.OnMessage(ref m); } }