diff --git a/Logic/ApplicationSettings.cs b/Logic/ApplicationSettings.cs index 7f10264d..192ce7c8 100644 --- a/Logic/ApplicationSettings.cs +++ b/Logic/ApplicationSettings.cs @@ -37,9 +37,9 @@ public class ApplicationSettings private static string _default = "default"; // Application Specific Settings we want to protect - private string _clientVersion = "1.7.1"; + private string _clientVersion = "1.7.2"; private string _version = "4"; - private int _clientCodeVersion = 105; + private int _clientCodeVersion = 106; public string ClientVersion { get { return _clientVersion; } } public string Version { get { return _version; } } diff --git a/Logic/KeyInterceptor.cs b/Logic/KeyInterceptor.cs new file mode 100644 index 00000000..514bcb85 --- /dev/null +++ b/Logic/KeyInterceptor.cs @@ -0,0 +1,59 @@ +using System; +using System.Diagnostics; +using System.Windows.Forms; +using System.Runtime.InteropServices; + +namespace XiboClient +{ + /// + /// Adapted from: http://blogs.msdn.com/b/toub/archive/2006/05/03/589423.aspx + /// + class KeyInterceptor + { + private const int WH_KEYBOARD_LL = 13; + private const int WM_KEYDOWN = 0x0100; + private static LowLevelKeyboardProc _proc = HookCallback; + private static IntPtr _hookId = IntPtr.Zero; + + public static void SetHook() + { + using (Process curProcess = Process.GetCurrentProcess()) + { + using (ProcessModule curModule = curProcess.MainModule) + { + SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle(curModule.ModuleName), 0); + } + } + } + + public static void UnsetHook() + { + UnhookWindowsHookEx(_hookId); + } + + private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam); + + private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) + { + if (nCode >= 0) + { + KeyStore.Instance.HandleRawKey(wParam, lParam); + } + + return CallNextHookEx(_hookId, nCode, wParam, lParam); + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + } +} \ No newline at end of file diff --git a/Logic/KeyStore.cs b/Logic/KeyStore.cs index 0795d53a..b5e67891 100644 --- a/Logic/KeyStore.cs +++ b/Logic/KeyStore.cs @@ -83,6 +83,34 @@ public bool PreFilterMessage(ref Message m) return handled; } + /// + /// Handle Raw Keypresses + /// + /// + /// + public void HandleRawKey(IntPtr wParam, IntPtr lParam) + { + bool handled = false; + Keys key = Keys.None; + + if (wParam == (IntPtr)WM_KEYDOWN) + { + key = (Keys)Marshal.ReadInt32(lParam); + handled = HandleModifier(key, false); + } + else if (wParam == (IntPtr)WM_KEYUP) + { + key = (Keys)Marshal.ReadInt32(lParam); + handled = HandleModifier(key, true); + if (false == handled) + { + // If one of the defined keys was pressed then we + // raise an event. + handled = HandleDefinedKey(key); + } + } + } + /// /// Compares a key against the definitions, and raises an event /// if there is a match. diff --git a/Logic/MouseInterceptor.cs b/Logic/MouseInterceptor.cs new file mode 100644 index 00000000..843c6c29 --- /dev/null +++ b/Logic/MouseInterceptor.cs @@ -0,0 +1,122 @@ +using System; +using System.Diagnostics; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.Drawing; + +namespace XiboClient.Logic +{ + public delegate void MouseInterceptorEventHandler(); + + /// + /// Adapted From: http://blogs.msdn.com/b/toub/archive/2006/05/03/589468.aspx + /// + class MouseInterceptor + { + private static LowLevelMouseProc _proc = HookCallback; + private static IntPtr _hookID = IntPtr.Zero; + + private static MouseInterceptor s_instance = null; + // The KeyPressed Event + public event MouseInterceptorEventHandler MouseEvent; + + private static Point _mouseLocation; + + public static IntPtr SetHook() + { + using (Process curProcess = Process.GetCurrentProcess()) + using (ProcessModule curModule = curProcess.MainModule) + { + return SetWindowsHookEx(WH_MOUSE_LL, _proc, GetModuleHandle(curModule.ModuleName), 0); + } + } + + public static void UnsetHook() + { + UnhookWindowsHookEx(_hookID); + } + + private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam); + + private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) + { + if (nCode >= 0) + { + if (MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam || MouseMessages.WM_MOUSEMOVE == (MouseMessages)wParam) + { + MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT)); + Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y); + + if (Math.Abs(_mouseLocation.X - hookStruct.pt.x) > 5 || Math.Abs(_mouseLocation.Y - hookStruct.pt.y) > 5) + { + if (MouseInterceptor.s_instance != null && MouseInterceptor.s_instance.MouseEvent != null) + MouseInterceptor.s_instance.MouseEvent(); + } + + _mouseLocation = new Point(hookStruct.pt.x, hookStruct.pt.y); + } + } + + return CallNextHookEx(_hookID, nCode, wParam, lParam); + } + + /// + /// Returns the singleton instance. + /// + public static MouseInterceptor Instance + { + get + { + if (null == s_instance) + s_instance = new MouseInterceptor(); + + return s_instance; + } + } + + private const int WH_MOUSE_LL = 14; + + private enum MouseMessages + { + WM_LBUTTONDOWN = 0x0201, + WM_LBUTTONUP = 0x0202, + WM_MOUSEMOVE = 0x0200, + WM_MOUSEWHEEL = 0x020A, + WM_RBUTTONDOWN = 0x0204, + WM_RBUTTONUP = 0x0205 + } + + [StructLayout(LayoutKind.Sequential)] + private struct POINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + private struct MSLLHOOKSTRUCT + { + public POINT pt; + public uint mouseData; + public uint flags; + public uint time; + public IntPtr dwExtraInfo; + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr SetWindowsHookEx(int idHook, + LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, + IntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr GetModuleHandle(string lpModuleName); + + } +} diff --git a/MainForm.cs b/MainForm.cs index d9d04a14..af7a416a 100644 --- a/MainForm.cs +++ b/MainForm.cs @@ -38,6 +38,7 @@ using System.Runtime.InteropServices; using System.Globalization; using Xilium.CefGlue; +using XiboClient.Logic; namespace XiboClient { @@ -49,7 +50,6 @@ public partial class MainForm : Form private int _scheduleId; private int _layoutId; private bool _screenSaver = false; - private Point _mouseLocation; double _layoutWidth; double _layoutHeight; @@ -95,7 +95,6 @@ enum EXECUTION_STATE : uint public MainForm(IntPtr previewHandle) { InitializeComponent(); - InitializeCommon(); // Set the preview window of the screen saver selection // dialog in Windows as the parent of this form. @@ -122,7 +121,6 @@ public MainForm(IntPtr previewHandle) public MainForm(bool screenSaver) { InitializeComponent(); - InitializeCommon(); if (screenSaver) InitializeScreenSaver(false); @@ -133,16 +131,9 @@ public MainForm(bool screenSaver) public MainForm() { InitializeComponent(); - InitializeCommon(); InitializeXibo(); } - private void InitializeCommon() - { - // Add a message filter - Application.AddMessageFilter(KeyStore.Instance); - } - private void InitializeXibo() { Thread.CurrentThread.Name = "UI Thread"; @@ -220,35 +211,14 @@ private void InitializeScreenSaver(bool preview) // Configure some listeners for the mouse (to quit) if (!preview) { - MouseMove += ScreenSaverForm_MouseMove; - MouseDown += ScreenSaverForm_MouseClick; - KeyStore.Instance.ScreenSaver = true; - } - } - - private void ScreenSaverForm_MouseMove(object sender, MouseEventArgs e) - { - if (!_screenSaver) - return; - if (!_mouseLocation.IsEmpty) - { - // Terminate if mouse is moved a significant distance - if (Math.Abs(_mouseLocation.X - e.X) > 5 || - Math.Abs(_mouseLocation.Y - e.Y) > 5) - Application.Exit(); + MouseInterceptor.Instance.MouseEvent += Instance_MouseEvent; } - - // Update current mouse location - _mouseLocation = e.Location; } - private void ScreenSaverForm_MouseClick(object sender, MouseEventArgs e) + void Instance_MouseEvent() { - if (!_screenSaver) - return; - Close(); } @@ -258,6 +228,7 @@ private void ScreenSaverForm_MouseClick(object sender, MouseEventArgs e) /// void Instance_KeyPress(string name) { + Debug.WriteLine("KeyPress " + name); if (name == "ClientInfo") { // Toggle @@ -271,6 +242,7 @@ void Instance_KeyPress(string name) } else if (name == "ScreenSaver") { + Debug.WriteLine("Closing due to ScreenSaver key press"); if (!_screenSaver) return; @@ -328,7 +300,8 @@ private void MainForm_Load(object sender, EventArgs e) Cursor.Hide(); // Move the cursor to the starting place - SetCursorStartPosition(); + if (!_screenSaver) + SetCursorStartPosition(); // Show the splash screen ShowSplashScreen(); diff --git a/Program.cs b/Program.cs index c5779161..9600d8e4 100644 --- a/Program.cs +++ b/Program.cs @@ -23,6 +23,7 @@ using System.Runtime.InteropServices; using System.Diagnostics; using Xilium.CefGlue; +using XiboClient.Logic; namespace XiboClient { @@ -91,12 +92,20 @@ static int Main(string[] args) // Preview the screen saver case "/p": // args[1] is the handle to the preview window + KeyInterceptor.SetHook(); + MouseInterceptor.SetHook(); RunClient(new IntPtr(long.Parse(args[1]))); + KeyInterceptor.UnsetHook(); + MouseInterceptor.UnsetHook(); break; // Show the screen saver case "/s": + KeyInterceptor.SetHook(); + MouseInterceptor.SetHook(); RunClient(true); + KeyInterceptor.UnsetHook(); + MouseInterceptor.UnsetHook(); break; // Configure the screesaver's settings @@ -107,13 +116,20 @@ static int Main(string[] args) // Show the screen saver default: + KeyInterceptor.SetHook(); + MouseInterceptor.SetHook(); RunClient(true); + KeyInterceptor.UnsetHook(); + MouseInterceptor.UnsetHook(); break; } } } else { + // Add a message filter + Application.AddMessageFilter(KeyStore.Instance); + // No arguments were passed - we run the usual client RunClient(); } diff --git a/XiboClient.csproj b/XiboClient.csproj index 0fec522d..ca96c04b 100644 --- a/XiboClient.csproj +++ b/XiboClient.csproj @@ -114,7 +114,9 @@ + + diff --git a/XiboClient.v11.suo b/XiboClient.v11.suo index 713c8791..16ab26eb 100644 Binary files a/XiboClient.v11.suo and b/XiboClient.v11.suo differ diff --git a/bin/x86/Release/Xibo.scr b/bin/x86/Release/Xibo.scr index aeb4b0ae..48614be5 100644 Binary files a/bin/x86/Release/Xibo.scr and b/bin/x86/Release/Xibo.scr differ diff --git a/bin/x86/Release/XiboClient.XmlSerializers.dll b/bin/x86/Release/XiboClient.XmlSerializers.dll index 6a573388..e5c38891 100644 Binary files a/bin/x86/Release/XiboClient.XmlSerializers.dll and b/bin/x86/Release/XiboClient.XmlSerializers.dll differ diff --git a/bin/x86/Release/XiboClient.exe b/bin/x86/Release/XiboClient.exe index aeb4b0ae..13519de0 100644 Binary files a/bin/x86/Release/XiboClient.exe and b/bin/x86/Release/XiboClient.exe differ diff --git a/bin/x86/Release/XiboClient.pdb b/bin/x86/Release/XiboClient.pdb index c14ebe60..55f5e965 100644 Binary files a/bin/x86/Release/XiboClient.pdb and b/bin/x86/Release/XiboClient.pdb differ