2018-09-10 02:41:13 +02:00
|
|
|
using System;
|
2015-06-09 23:29:09 -04:00
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
2015-08-03 17:57:01 +10:00
|
|
|
namespace CefSharp.WinForms.Example.Handlers
|
2015-06-09 23:29:09 -04:00
|
|
|
{
|
|
|
|
|
public class KeyboardHandler : IKeyboardHandler
|
|
|
|
|
{
|
|
|
|
|
/// <inheritdoc/>>
|
2019-07-20 16:26:25 +10:00
|
|
|
public bool OnPreKeyEvent(IWebBrowser chromiumWebBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
|
2015-06-09 23:29:09 -04:00
|
|
|
{
|
|
|
|
|
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;
|
2016-04-21 07:03:19 +10:00
|
|
|
const int VK_LEFT = 0x25;
|
|
|
|
|
const int VK_UP = 0x26;
|
|
|
|
|
const int VK_RIGHT = 0x27;
|
|
|
|
|
const int VK_DOWN = 0x28;
|
2015-06-09 23:29:09 -04:00
|
|
|
|
|
|
|
|
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...?
|
2016-04-21 07:03:19 +10:00
|
|
|
if (windowsKeyCode == VK_TAB || windowsKeyCode == VK_LEFT || windowsKeyCode == VK_UP || windowsKeyCode == VK_DOWN || windowsKeyCode == VK_RIGHT)
|
2015-06-09 23:29:09 -04:00
|
|
|
{
|
2016-04-21 07:03:19 +10:00
|
|
|
return false;
|
2015-06-09 23:29:09 -04:00
|
|
|
}
|
|
|
|
|
|
2016-04-21 07:03:19 +10:00
|
|
|
var result = false;
|
|
|
|
|
|
2019-07-20 16:26:25 +10:00
|
|
|
var control = chromiumWebBrowser as Control;
|
2016-04-21 07:03:19 +10:00
|
|
|
var msgType = 0;
|
2015-06-09 23:29:09 -04:00
|
|
|
switch (type)
|
|
|
|
|
{
|
2018-09-10 02:41:13 +02:00
|
|
|
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;
|
2015-06-09 23:29:09 -04:00
|
|
|
}
|
2015-06-09 23:41:05 -04:00
|
|
|
// 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:
|
2016-04-21 07:03:19 +10:00
|
|
|
var state = PreProcessControlState.MessageNotNeeded;
|
2015-06-09 23:41:05 -04:00
|
|
|
// We can't use BeginInvoke here, because we need the results for the return value
|
2015-06-09 23:46:39 -04:00
|
|
|
// and isKeyboardShortcut. In theory this shouldn't deadlock, because
|
|
|
|
|
// atm this is the only synchronous operation between the two threads.
|
2015-06-09 23:29:09 -04:00
|
|
|
control.Invoke(new Action(() =>
|
|
|
|
|
{
|
2016-04-21 07:03:19 +10:00
|
|
|
var msg = new Message
|
|
|
|
|
{
|
|
|
|
|
HWnd = control.Handle,
|
|
|
|
|
Msg = msgType,
|
|
|
|
|
WParam = new IntPtr(windowsKeyCode),
|
|
|
|
|
LParam = new IntPtr(nativeKeyCode)
|
|
|
|
|
};
|
2015-06-09 23:41:05 -04:00
|
|
|
|
|
|
|
|
// First comes Application.AddMessageFilter related processing:
|
|
|
|
|
// 99.9% of the time in WinForms this doesn't do anything interesting.
|
2016-04-21 07:03:19 +10:00
|
|
|
var processed = Application.FilterMessage(ref msg);
|
2015-06-09 23:29:09 -04:00
|
|
|
if (processed)
|
|
|
|
|
{
|
|
|
|
|
state = PreProcessControlState.MessageProcessed;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-06-09 23:41:05 -04:00
|
|
|
// 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...
|
2015-06-09 23:29:09 -04:00
|
|
|
state = control.PreProcessControlMessage(ref msg);
|
|
|
|
|
}
|
|
|
|
|
}));
|
2016-04-21 07:03:19 +10:00
|
|
|
|
2015-06-09 23:29:09 -04:00
|
|
|
if (state == PreProcessControlState.MessageNeeded)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Determine how to track MessageNeeded for OnKeyEvent.
|
|
|
|
|
isKeyboardShortcut = true;
|
|
|
|
|
}
|
|
|
|
|
else if (state == PreProcessControlState.MessageProcessed)
|
|
|
|
|
{
|
2015-06-09 23:41:05 -04:00
|
|
|
// Most of the interesting cases get processed by PreProcessControlMessage.
|
2015-06-09 23:29:09 -04:00
|
|
|
result = true;
|
|
|
|
|
}
|
2016-04-21 07:03:19 +10:00
|
|
|
|
|
|
|
|
Debug.WriteLine("OnPreKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers);
|
|
|
|
|
Debug.WriteLine("OnPreKeyEvent PreProcessControlState: {0}", state);
|
|
|
|
|
|
2015-06-09 23:29:09 -04:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc/>>
|
2019-07-20 16:26:25 +10:00
|
|
|
public bool OnKeyEvent(IWebBrowser chromiumWebBrowser, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
2015-06-09 23:29:09 -04:00
|
|
|
{
|
2016-04-21 07:03:19 +10:00
|
|
|
var result = false;
|
|
|
|
|
Debug.WriteLine("OnKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers);
|
2015-06-09 23:41:05 -04:00
|
|
|
// TODO: Handle MessageNeeded cases here somehow.
|
2015-06-09 23:29:09 -04:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|