// Intercept keyboard messages for Ctrl-F4 and Ctrl-Tab handling
        private IntPtr KBHookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                Keys keys = (Keys)vkCode;

                // track key state globally for control/alt/shift is up/down
                bool isKeyDown = (wParam == (IntPtr)NativeMethods.WM_KEYDOWN || wParam == (IntPtr)NativeMethods.WM_SYSKEYDOWN);
                if (keys == Keys.LControlKey || keys == Keys.RControlKey) {  isControlDown = isKeyDown; }
                if (keys == Keys.LShiftKey || keys == Keys.RShiftKey) { isShiftDown = isKeyDown; }
                if (keys == Keys.LMenu || keys == Keys.RMenu) { isAltDown = isKeyDown; }

                if (Log.Logger.IsEnabledFor(Level.Trace))
                {
                    Log.DebugFormat("### KBHook: nCode={0}, wParam={1}, lParam={2} ({4,-4} - {3}) [{5}{6}{7}]",
                        nCode, wParam, vkCode, keys, isKeyDown ? "Down" : "Up",
                        (isControlDown ? "Ctrl" : ""), (isAltDown ? "Alt" : ""), (isAltDown ? "Shift" : ""));
                }

                if (IsForegroundWindow(this))
                {
                    // SuperPuTTY or Putty is the window in front...

                    if (keys == Keys.LControlKey || keys == Keys.RControlKey)
                    {
                        // If Ctrl-Tab has been pressed to move to an older panel then
                        // make it current panel when Ctrl key is finally released.
                        if (SuperPuTTY.Settings.EnableControlTabSwitching && !isControlDown && !isShiftDown)
                        {
                            this.tabSwitcher.CurrentDocument = (ToolWindow)this.DockPanel.ActiveDocument;
                        }
                    }

                    if (keys == Keys.LShiftKey || keys == Keys.RShiftKey)
                    {
                        // If Ctrl-Shift-Tab has been pressed to move to an older panel then
                        // make it current panel when both keys are finally released.
                        if (SuperPuTTY.Settings.EnableControlTabSwitching && !isControlDown && !isShiftDown)
                        {
                            this.tabSwitcher.CurrentDocument = (ToolWindow)this.DockPanel.ActiveDocument;
                        }
                    }

                    if (SuperPuTTY.Settings.EnableControlTabSwitching && isControlDown && !isShiftDown && keys == Keys.Tab)
                    {
                        // Operator has pressed Ctrl-Tab, make next PuTTY panel active
                        if (isKeyDown && this.DockPanel.ActiveDocument is ToolWindowDocument)
                        {
                            if (this.tabSwitcher.MoveToNextDocument())
                            {
                                // Eat the keystroke
                                return (IntPtr)1;
                            }
                        }
                    }

                    if (SuperPuTTY.Settings.EnableControlTabSwitching && isControlDown && isShiftDown && keys == Keys.Tab)
                    {
                        // Operator has pressed Ctrl-Shift-Tab, make previous PuTTY panel active
                        if (isKeyDown && this.DockPanel.ActiveDocument is ToolWindowDocument)
                        {
                            if (this.tabSwitcher.MoveToPrevDocument())
                            {
                                // Eat the keystroke
                                return (IntPtr)1;
                            }
                        }
                    }

                    if (isControlDown && !isShiftDown && keys == Keys.V)
                    {
                        if (this.DockPanel.ActiveDocument is ctlPuttyPanel)
                        {
                            ctlPuttyPanel puttyPanel = (ctlPuttyPanel)this.DockPanel.ActiveDocument;
                            string commandText = Clipboard.GetText();
                            CommandData commandData = new CommandData(commandText);
                            int handle = puttyPanel.AppPanel.AppWindowHandle.ToInt32();
                            Log.InfoFormat("SendCommand: session={0}, command=[{1}], handle={2}", puttyPanel.Session.SessionName, commandText, handle);
                            try
                            {
                                commandData.SendToTerminal(handle);
                                return (IntPtr)1;
                            }
                            catch (Exception e)
                            {
                                Log.ErrorFormat("Send command failed : {0}", e.Message);
                            }
                        }
                    }
                    // misc action handling (eat keyup and down)
                    if (SuperPuTTY.Settings.EnableKeyboadShortcuts &&
                        isKeyDown &&
                        keys != Keys.LControlKey && keys != Keys.RControlKey &&
                        keys != Keys.LMenu && keys != Keys.RMenu &&
                        keys != Keys.LShiftKey && keys != Keys.RShiftKey)
                    {
                        if (isControlDown) keys |= Keys.Control;
                        if (isShiftDown) keys |= Keys.Shift;
                        if (isAltDown) keys |= Keys.Alt;

                        if (Log.Logger.IsEnabledFor(Level.Trace))
                        {
                            Log.DebugFormat("#### TryExecute shortcut: keys={0}", keys);
                        }

                        SuperPuTTYAction action;
                        if (this.shortcuts.TryGetValue(keys, out action))
                        {
                            // post action to avoid getting errant keystrokes (e.g. allow current to be eaten)
                            this.BeginInvoke(new Action(() =>
                            {
                                ExecuteSuperPuTTYAction(action);
                            }));
                            return (IntPtr)1;
                        }
                    }
                }

            }

            return NativeMethods.CallNextHookEx(kbHookID, nCode, wParam, lParam);
        }
        int TrySendCommandsFromToolbar(CommandData command, bool saveHistory)
        {
            int sent = 0;
            //String command = this.tsSendCommandCombo.Text; //this.tbTextCommand.Text;
            if (this.DockPanel.DocumentsCount > 0)
            {
                foreach (DockContent content in this.DockPanel.Documents)
                {
                    ctlPuttyPanel puttyPanel = content as ctlPuttyPanel;
                    if (puttyPanel != null && this.sendCommandsDocumentSelector.IsDocumentSelected(puttyPanel))
                    {
                        int handle = puttyPanel.AppPanel.AppWindowHandle.ToInt32();
                        Log.InfoFormat("SendCommand: session={0}, command=[{1}], handle={2}", puttyPanel.Session.SessionName, command, handle);

                        command.SendToTerminal(handle);
                        /*
                        foreach (Char c in command.Chars)
                        {
                            NativeMethods.SendMessage(handle, NativeMethods.WM_CHAR, (int)c, 0);
                        }

                        NativeMethods.SendMessage(handle, NativeMethods.WM_CHAR, (int)Keys.Enter, 0);*/
                        //NativeMethods.SendMessage(handle, NativeMethods.WM_KEYUP, (int)Keys.Enter, 0);
                        sent++;
                    }
                }
                if (sent > 0)
                {
                    // success...clear text and save in mru
                    this.tsSendCommandCombo.Text = string.Empty;
                    if (this.tsSendCommandCombo.Items.Count >= SuperPuTTY.Settings.MaxCommandHistory)
                    {
                        this.tsSendCommandCombo.Items.RemoveAt(this.tsSendCommandCombo.Items.Count - 1);
                    }
                    if (command != null && !string.IsNullOrEmpty(command.Command) && saveHistory)

                    {
                        this.tsSendCommandCombo.Items.Insert(0, command.ToString());
                    }
                }
            }
            return sent;
        }