Created
May 13, 2012 22:20
-
-
Save TinkerWorX/2690490 to your computer and use it in GitHub Desktop.
An XNA compatible Awesomium component.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
JCPM_MWX.Awesomium.Xna | |
{ | |
public class AwesomiumComponent : DrawableGameComponent | |
{ | |
private delegate Int32 ProcessMessagesDelegate(Int32 code, Int32 wParam, ref Message lParam); | |
private static class User32 | |
{ | |
[DllImport("user32.dll", SetLastError = true)] | |
internal static extern IntPtr SetWindowsHookEx(Int32 windowsHookId, ProcessMessagesDelegate function, IntPtr mod, Int32 threadId); | |
[DllImport("user32.dll", SetLastError = true)] | |
internal static extern Int32 UnhookWindowsHookEx(IntPtr hook); | |
[DllImport("user32.dll", SetLastError = true)] | |
internal static extern Int32 CallNextHookEx(IntPtr hook, Int32 code, Int32 wParam, ref Message lParam); | |
[DllImport("user32.dll", SetLastError = true)] | |
internal static extern Boolean TranslateMessage(ref Message message); | |
[DllImport("user32.dll", CharSet = CharSet.Auto)] | |
internal static extern IntPtr FindWindow(String className, String windowName); | |
[DllImport("user32.dll", CharSet = CharSet.Auto)] | |
internal static extern int RegisterWindowMessage(String msg); | |
[DllImport("user32.dll", CharSet = CharSet.Auto)] | |
internal static extern IntPtr SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam); | |
[DllImport("user32.dll", CharSet = CharSet.Auto)] | |
internal static extern bool SystemParametersInfo(Int32 nAction, Int32 nParam, ref Int32 value, Int32 ignore); | |
[DllImport("user32.dll", CharSet = CharSet.Auto)] | |
internal static extern int GetSystemMetrics(Int32 nIndex); | |
} | |
private static class Kernel32 | |
{ | |
[DllImport("kernel32.dll", SetLastError = true)] | |
internal static extern Int32 GetCurrentThreadId(); | |
} | |
private static class SystemMetrics | |
{ | |
internal static Int32 MouseWheelScrollDelta | |
{ | |
get | |
{ | |
return 120; | |
} | |
} | |
internal static Int32 MouseWheelScrollLines | |
{ | |
get | |
{ | |
var scrollLines = 0; | |
if (User32.GetSystemMetrics(75) == 0) | |
{ | |
var hwnd = User32.FindWindow("MouseZ", "Magellan MSWHEEL"); | |
if (hwnd != IntPtr.Zero) | |
{ | |
var windowMessage = User32.RegisterWindowMessage("MSH_SCROLL_LINES_MSG"); | |
scrollLines = (Int32)User32.SendMessage(new HandleRef(null, hwnd), windowMessage, 0, 0); | |
if (scrollLines != 0) | |
{ | |
return scrollLines; | |
} | |
} | |
return 3; | |
} | |
User32.SystemParametersInfo(104, 0, ref scrollLines, 0); | |
return scrollLines; | |
} | |
} | |
} | |
private enum WindowsMessage | |
{ | |
KeyDown = 0x0100, | |
KeyUp = 0x0101, | |
Char = 0x0102, | |
MouseMove = 0x0200, | |
LeftButtonDown = 0x0201, | |
LeftButtonUp = 0x0202, | |
LeftButtonDoubleClick = 0x0203, | |
RightButtonDown = 0x0204, | |
RightButtonUp = 0x0205, | |
RightButtonDoubleClick = 0x0206, | |
MiddleButtonDown = 0x0207, | |
MiddleButtonUp = 0x0208, | |
MiddleButtonDoubleClick = 0x0209, | |
MouseWheel = 0x020A, | |
} | |
private struct Message | |
{ | |
internal IntPtr HWnd; | |
internal Int32 Msg; | |
internal IntPtr WParam; | |
internal IntPtr LParam; | |
internal IntPtr Result; | |
} | |
private readonly IntPtr hookHandle; | |
private readonly ProcessMessagesDelegate processMessages; | |
private Byte[] imageBytes; | |
private Rectangle area; | |
private Rectangle? newArea; | |
private Boolean resizing; | |
public AwesomiumComponent(Game game, Rectangle area) | |
: base(game) | |
{ | |
this.area = area; | |
this.WebView = WebCore.CreateWebView(this.area.Width, this.area.Height); | |
this.WebView.ResizeComplete += this.WebView_ResizeComplete; | |
this.WebView.FlushAlpha = false; | |
this.WebView.IsTransparent = true; | |
this.processMessages = this.ProcessMessages; | |
// Create the message hook. | |
this.hookHandle = User32.SetWindowsHookEx(3, this.processMessages, IntPtr.Zero, Kernel32.GetCurrentThreadId()); | |
} | |
public AwesomiumComponent(Game game) | |
: base(game) | |
{ | |
this.area = Rectangle.Empty; | |
this.WebView = WebCore.CreateWebView(this.area.Width, this.area.Height); | |
this.WebView.ResizeComplete += this.WebView_ResizeComplete; | |
this.WebView.FlushAlpha = false; | |
this.WebView.IsTransparent = true; | |
this.processMessages = this.ProcessMessages; | |
// Create the message hook. | |
this.hookHandle = User32.SetWindowsHookEx(3, this.processMessages, IntPtr.Zero, Kernel32.GetCurrentThreadId()); | |
} | |
~AwesomiumComponent() | |
{ | |
// Remove the message hook. | |
if (this.hookHandle != IntPtr.Zero) | |
User32.UnhookWindowsHookEx(this.hookHandle); | |
} | |
public Texture2D WebViewTexture { get; private set; } | |
public WebView WebView { get; private set; } | |
public Rectangle Area | |
{ | |
get { return this.area; } | |
set | |
{ | |
this.newArea = value; | |
} | |
} | |
private Int32 ProcessMessages(Int32 code, Int32 wParam, ref Message lParam) | |
{ | |
if (code == 0 && wParam == 1) | |
{ | |
switch ((WindowsMessage)lParam.Msg) | |
{ | |
case WindowsMessage.KeyDown: | |
case WindowsMessage.KeyUp: | |
case WindowsMessage.Char: | |
this.WebView.InjectKeyboardEventWin(lParam.Msg, (Int32)lParam.WParam, (Int32)lParam.LParam); | |
break; | |
case WindowsMessage.MouseMove: | |
var mouse = Mouse.GetState(); | |
this.WebView.InjectMouseMove(mouse.X - this.area.X, mouse.Y - this.area.Y); | |
break; | |
case WindowsMessage.LeftButtonDown: this.WebView.InjectMouseDown(MouseButton.Left); break; | |
case WindowsMessage.LeftButtonUp: this.WebView.InjectMouseUp(MouseButton.Left); break; | |
case WindowsMessage.LeftButtonDoubleClick: this.WebView.InjectMouseDown(MouseButton.Left); break; | |
case WindowsMessage.RightButtonDown: this.WebView.InjectMouseDown(MouseButton.Right); break; | |
case WindowsMessage.RightButtonUp: this.WebView.InjectMouseUp(MouseButton.Right); break; | |
case WindowsMessage.RightButtonDoubleClick: this.WebView.InjectMouseDown(MouseButton.Right); break; | |
case WindowsMessage.MiddleButtonDown: this.WebView.InjectMouseDown(MouseButton.Middle); break; | |
case WindowsMessage.MiddleButtonUp: this.WebView.InjectMouseUp(MouseButton.Middle); break; | |
case WindowsMessage.MiddleButtonDoubleClick: this.WebView.InjectMouseDown(MouseButton.Middle); break; | |
case WindowsMessage.MouseWheel: | |
var delta = (((Int32)lParam.WParam) >> 16); | |
this.WebView.InjectMouseWheel(delta / SystemMetrics.MouseWheelScrollDelta * 16 * SystemMetrics.MouseWheelScrollLines); | |
break; | |
//case (WindowsMessage)0xC328: break; | |
//default: | |
// Console.WriteLine("{{default}}: {0}", lParam); | |
// break; | |
} | |
User32.TranslateMessage(ref lParam); | |
} | |
return User32.CallNextHookEx(IntPtr.Zero, code, wParam, ref lParam); | |
} | |
private void WebView_ResizeComplete(Object sender, ResizeEventArgs e) | |
{ | |
this.resizing = false; | |
} | |
protected override void LoadContent() | |
{ | |
if (this.area.IsEmpty) | |
{ | |
this.area = this.GraphicsDevice.Viewport.Bounds; | |
this.newArea = this.GraphicsDevice.Viewport.Bounds; | |
} | |
this.WebViewTexture = new Texture2D(this.Game.GraphicsDevice, this.area.Width, this.area.Height, false, SurfaceFormat.Color); | |
this.imageBytes = new Byte[this.area.Width * 4 * this.area.Height]; | |
} | |
public override void Update(GameTime gameTime) | |
{ | |
if (this.newArea.HasValue && !this.resizing && gameTime.TotalGameTime.TotalSeconds > 0.10f) | |
{ | |
this.area = this.newArea.Value; | |
if (this.area.IsEmpty) | |
this.area = this.GraphicsDevice.Viewport.Bounds; | |
this.WebView.Resize(this.area.Width, this.area.Height); | |
this.WebViewTexture = new Texture2D(this.Game.GraphicsDevice, this.area.Width, this.area.Height, false, SurfaceFormat.Color); | |
this.imageBytes = new Byte[this.area.Width * 4 * this.area.Height]; | |
this.resizing = true; | |
this.newArea = null; | |
} | |
base.Update(gameTime); | |
} | |
public override void Draw(GameTime gameTime) | |
{ | |
if (this.WebView.IsDirty) | |
{ | |
var renderBuffer = this.WebView.Render(); | |
unsafe | |
{ | |
// This part saves us from double copying everything. | |
fixed (Byte* imagePtr = this.imageBytes) | |
{ | |
renderBuffer.CopyTo((IntPtr)imagePtr, renderBuffer.Width * 4, 4, true); | |
} | |
} | |
this.WebViewTexture.SetData(this.imageBytes); | |
} | |
base.Draw(gameTime); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment