/// <summary> /// process meassage and handles if for /// .NET controls and its children /// </summary> /// <param name="m"></param> /// <param name="mapData"></param> /// <param name="ancestorControl"></param> /// <param name="control"></param> /// <returns></returns> private static PreProcessControlState ProcessAndHandleDotNetControlMessage(Message m, MapData mapData, Control ancestorControl, Control control) { MgPanel navigationKeyDialogPanel = null; if (IsTabbingMessage(m)) { navigationKeyDialogPanel = GuiUtils.getContainerPanel(control) as MgPanel; } if (navigationKeyDialogPanel != null) { //install DialogKeyReceived key handler on the parent panel //this will be our indication if we need to handle the message navigationKeyDialogPanel.DialogKeyReceived += new EventHandler(panel_DialogKeyReceived); } keyShouldBeHandledByMagic = false; PreProcessControlState state = control.PreProcessControlMessage(ref m); //first let control process the message if (navigationKeyDialogPanel != null) { navigationKeyDialogPanel.DialogKeyReceived -= new EventHandler(panel_DialogKeyReceived); } handleMessage(m, mapData, control, state); //then handle it in magic return(state); }
/// <inheritdoc/>> public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut) { const int WM_SYSKEYDOWN = 0x104; const int WM_KEYDOWN = 0x100; const int WM_KEYUP = 0x101; const int WM_SYSKEYUP = 0x105; const int WM_CHAR = 0x102; const int WM_SYSCHAR = 0x106; const int VK_TAB = 0x9; bool result = false; isKeyboardShortcut = false; // Don't deal with TABs by default: // TODO: Are there any additional ones we need to be careful of? // i.e. Escape, Return, etc...? if (windowsKeyCode == VK_TAB) { return(result); } Control control = browserControl as Control; int msgType = 0; switch (type) { case KeyType.RawKeyDown: if (isSystemKey) { msgType = WM_SYSKEYDOWN; } else { msgType = WM_KEYDOWN; } break; case KeyType.KeyUp: if (isSystemKey) { msgType = WM_SYSKEYUP; } else { msgType = WM_KEYUP; } break; case KeyType.Char: if (isSystemKey) { msgType = WM_SYSCHAR; } else { msgType = WM_CHAR; } break; default: Trace.Assert(false); break; } // We have to adapt from CEF's UI thread message loop to our fronting WinForm control here. // So, we have to make some calls that Application.Run usually ends up handling for us: PreProcessControlState state = PreProcessControlState.MessageNotNeeded; // We can't use BeginInvoke here, because we need the results for the return value // and isKeyboardShortcut. In theory this shouldn't deadlock, because // atm this is the only synchronous operation between the two threads. control.Invoke(new Action(() => { Message msg = new Message() { HWnd = control.Handle, Msg = msgType, WParam = new IntPtr(windowsKeyCode), LParam = new IntPtr(nativeKeyCode) }; // First comes Application.AddMessageFilter related processing: // 99.9% of the time in WinForms this doesn't do anything interesting. bool processed = Application.FilterMessage(ref msg); if (processed) { state = PreProcessControlState.MessageProcessed; } else { // Next we see if our control (or one of its parents) // wants first crack at the message via several possible Control methods. // This includes things like Mnemonics/Accelerators/Menu Shortcuts/etc... state = control.PreProcessControlMessage(ref msg); } })); if (state == PreProcessControlState.MessageNeeded) { // TODO: Determine how to track MessageNeeded for OnKeyEvent. isKeyboardShortcut = true; } else if (state == PreProcessControlState.MessageProcessed) { // Most of the interesting cases get processed by PreProcessControlMessage. result = true; } Debug.WriteLine(String.Format("OnPreKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers)); Debug.WriteLine(String.Format("OnPreKeyEvent PreProcessControlState: {0}", state)); return(result); }
/// <summary> /// handle message of child of .NET control /// create event according to message and handle it in usual manner /// </summary> /// <param name = "m"> message </param> /// <param name = "mapData"> map data of .NET control</param> /// <param name = "control">control which receive message - the child of .NET control</param> /// <param name="state"></param> private static void handleMessage(Message m, MapData mapData, Control control, PreProcessControlState state) { EventArgs e = null; HandlerBase.EventType eventType = HandlerBase.EventType.NONE; switch (m.Msg) { case NativeWindowCommon.WM_LBUTTONDOWN: e = createLeftMouseEventArgs(1, (int)m.LParam); eventType = HandlerBase.EventType.MOUSE_DOWN; break; case NativeWindowCommon.WM_LBUTTONUP: e = createLeftMouseEventArgs(1, (int)m.LParam); eventType = HandlerBase.EventType.MOUSE_UP; break; case NativeWindowCommon.WM_LBUTTONDBLCLK: e = createLeftMouseEventArgs(2, (int)m.LParam); eventType = HandlerBase.EventType.MOUSE_DBLCLICK; break; case NativeWindowCommon.WM_MOUSEMOVE: e = createLeftMouseEventArgs(1, (int)m.LParam); eventType = HandlerBase.EventType.MOUSE_MOVE; break; case NativeWindowCommon.WM_KEYDOWN: eventType = HandlerBase.EventType.KEY_DOWN; Keys keyCode = GetKeyCode(m); e = new KeyEventArgs(keyCode); DotNetHandler.getInstance().handleEvent("KeyDown", control, e, mapData); // we use preProcessResult only for navigation keys // if control returns preProcessResult = false for a navigation key then we do not // interfere because the control already handled the navigation internally. if (state == PreProcessControlState.MessageNeeded) { foreach (var item in _navigationKeys) { if (keyCode == item) { return; } } } if (keyCode == Keys.Tab && !keyShouldBeHandledByMagic) //QCR #728708 //special handling for a tab key, in future may be extended for othe keys as weel. { return; } break; default: Debug.Assert(false); break; } DefaultHandler.getInstance().handleEvent(eventType, control, e, mapData); }
/// <summary> /// process message /// find out if the message is from child of the .NET control and process it /// </summary> /// <param name = "m"></param> /// <returns></returns> private static bool handleChildrenOfDotNetControls(Message m) { PreProcessControlState state = PreProcessControlState.MessageNotNeeded; ControlsMap controlsMap = ControlsMap.getInstance(); MapData mapData; switch (m.Msg) { //this are common messages that we want to handle for children of .NET controls case NativeWindowCommon.WM_MOUSEMOVE: case NativeWindowCommon.WM_LBUTTONDOWN: case NativeWindowCommon.WM_LBUTTONUP: case NativeWindowCommon.WM_LBUTTONDBLCLK: case NativeWindowCommon.WM_KEYDOWN: Control c, control = c = Control.FromChildHandle(m.HWnd); if (c != null) { mapData = controlsMap.getControlMapData(c); if (mapData != null) //this is a magic control { //this is a .NET control on magic if (isDotNetControl(mapData) && m.Msg == NativeWindowCommon.WM_KEYDOWN) { state = ProcessAndHandleDotNetControlMessage(m, mapData, control, control); //then handle it in magic } else { return(false); } } else //look for magic parent of the control { while (c.Parent != null) { c = c.Parent; mapData = controlsMap.getControlMapData(c); if (mapData != null) { if (isDotNetControl(mapData)) { //FOUND! This is a child of .NET control state = ProcessAndHandleDotNetControlMessage(m, mapData, c, control); } break; } } } } break; case NativeWindowCommon.WM_KEYUP: { // Handled here because while moving between windows of windowlist using keyboard (ie. Ctrl+Tab+Tab+,...), // the list should not be sorted until we release key associated with Next/Previous window Action. Control ctrl = Control.FromHandle(m.HWnd); if (ctrl != null) { Form form = GuiUtils.FindForm(ctrl); if (form != null && ControlsMap.isMagicWidget(form)) { // Each form has a panel and panel contains all controls. mapData = controlsMap.getControlMapData(((TagData)form.Tag).ClientPanel); if (mapData != null) { Events.HandleKeyUpMessage(mapData.getForm(), (int)m.WParam); } } } } break; } return(state == PreProcessControlState.MessageProcessed); }