diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index 8d31a8a77..3cd630413 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -464,6 +464,7 @@
+
@@ -566,6 +567,7 @@
+
diff --git a/Artemis/Artemis/ArtemisBootstrapper.cs b/Artemis/Artemis/ArtemisBootstrapper.cs
index 30f3b2d3c..754eed3cc 100644
--- a/Artemis/Artemis/ArtemisBootstrapper.cs
+++ b/Artemis/Artemis/ArtemisBootstrapper.cs
@@ -90,11 +90,15 @@ namespace Artemis
ContractResolver = _kernel.Get()
};
JsonConvert.DefaultSettings = () => settings;
+
+ //TODO DarthAffe 17.12.2016: Is this the right location for this?
+ ActiveWindowHelper.Initialize();
}
protected override void OnExit(object sender, EventArgs e)
{
_kernel.Dispose();
+ ActiveWindowHelper.Dispose();
base.OnExit(sender, e);
}
diff --git a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileDataModel.cs b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileDataModel.cs
index 400bfa441..7efdf765f 100644
--- a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileDataModel.cs
+++ b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileDataModel.cs
@@ -14,6 +14,7 @@ namespace Artemis.Modules.Effects.WindowsProfile
Performance = new PerformanceDataModel();
CurrentTime = new CurrentTime();
Keyboard = new KbDataModel();
+ ActiveWindow = new ActiveWindow();
}
public CpuDataModel Cpu { get; set; }
@@ -22,6 +23,7 @@ namespace Artemis.Modules.Effects.WindowsProfile
public GooglePlayMusic GooglePlayMusic { get; set; }
public CurrentTime CurrentTime { get; set; }
public KbDataModel Keyboard { get; set; }
+ public ActiveWindow ActiveWindow { get; set; }
}
[MoonSharpUserData]
@@ -110,4 +112,11 @@ namespace Artemis.Modules.Effects.WindowsProfile
public bool CapsLock { get; set; }
public bool ScrollLock { get; set; }
}
+
+ [MoonSharpUserData]
+ public class ActiveWindow
+ {
+ public string ProcessName { get; set; }
+ public string WindowTitle { get; set; }
+ }
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs
index 724535874..7a5607c43 100644
--- a/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs
+++ b/Artemis/Artemis/Modules/Effects/WindowsProfile/WindowsProfileModel.cs
@@ -9,6 +9,7 @@ using Artemis.DAL;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Profiles.Layers.Models;
+using Artemis.Utilities;
using Newtonsoft.Json;
using SpotifyAPI.Local;
@@ -52,6 +53,7 @@ namespace Artemis.Modules.Effects.WindowsProfile
UpdateMusicPlayers(dataModel);
UpdateDay(dataModel);
UpdateKeyStates(dataModel);
+ UpdateActiveWindow(dataModel);
}
#region Current Time
@@ -66,7 +68,7 @@ namespace Artemis.Modules.Effects.WindowsProfile
}
#endregion
-
+
#region CPU
private void SetupCpu()
@@ -249,6 +251,12 @@ namespace Artemis.Modules.Effects.WindowsProfile
dataModel.Keyboard.ScrollLock = ((ushort)GetKeyState(0x91) & 0xffff) != 0;
}
+ private void UpdateActiveWindow(WindowsProfileDataModel dataModel)
+ {
+ dataModel.ActiveWindow.ProcessName = ActiveWindowHelper.ActiveWindowProcessName;
+ dataModel.ActiveWindow.WindowTitle = ActiveWindowHelper.ActiveWindowWindowTitle;
+ }
+
#endregion
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Lua/LuaActiveWindowWrapper.cs b/Artemis/Artemis/Profiles/Lua/LuaActiveWindowWrapper.cs
new file mode 100644
index 000000000..3dd2a27dc
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Lua/LuaActiveWindowWrapper.cs
@@ -0,0 +1,12 @@
+using Artemis.Utilities;
+using MoonSharp.Interpreter;
+
+namespace Artemis.Profiles.Lua
+{
+ [MoonSharpUserData]
+ public class LuaActiveWindowWrapper
+ {
+ public string ProcessName => ActiveWindowHelper.ActiveWindowProcessName;
+ public string WindowTitle => ActiveWindowHelper.ActiveWindowWindowTitle;
+ }
+}
diff --git a/Artemis/Artemis/Profiles/Lua/LuaWrapper.cs b/Artemis/Artemis/Profiles/Lua/LuaWrapper.cs
index 2b4e5f315..e8a313cb5 100644
--- a/Artemis/Artemis/Profiles/Lua/LuaWrapper.cs
+++ b/Artemis/Artemis/Profiles/Lua/LuaWrapper.cs
@@ -25,6 +25,7 @@ namespace Artemis.Profiles.Lua
public static LuaKeyboardWrapper LuaKeyboardWrapper { get; private set; }
public static LuaMouseWrapper LuaMouseWrapper { get; set; }
public static LuaEventsWrapper LuaEventsWrapper { get; private set; }
+ public static LuaActiveWindowWrapper LuaActiveWindowWrapper { get; private set; }
public static void SetupLua(ProfileModel profileModel, KeyboardProvider keyboardProvider)
{
@@ -41,6 +42,7 @@ namespace Artemis.Profiles.Lua
LuaKeyboardWrapper = new LuaKeyboardWrapper(keyboardProvider);
LuaMouseWrapper = new LuaMouseWrapper();
LuaEventsWrapper = new LuaEventsWrapper();
+ LuaActiveWindowWrapper = new LuaActiveWindowWrapper();
LuaScript.Options.DebugPrint = LuaPrint;
LuaScript.Globals["Profile"] = LuaProfileWrapper;
@@ -48,6 +50,7 @@ namespace Artemis.Profiles.Lua
LuaScript.Globals["Brushes"] = LuaBrushWrapper;
LuaScript.Globals["Keyboard"] = LuaKeyboardWrapper;
LuaScript.Globals["Mouse"] = LuaMouseWrapper;
+ LuaScript.Globals["ActiveWindow"] = LuaActiveWindowWrapper;
if (ProfileModel == null)
return;
@@ -99,6 +102,7 @@ namespace Artemis.Profiles.Lua
LuaKeyboardWrapper?.Dispose();
LuaKeyboardWrapper = null;
LuaMouseWrapper = null;
+ LuaActiveWindowWrapper = null;
try
{
diff --git a/Artemis/Artemis/Utilities/ActiveWindowHelper.cs b/Artemis/Artemis/Utilities/ActiveWindowHelper.cs
new file mode 100644
index 000000000..2b4e712f7
--- /dev/null
+++ b/Artemis/Artemis/Utilities/ActiveWindowHelper.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Artemis.Utilities
+{
+ public static class ActiveWindowHelper
+ {
+ #region DLL-Imports
+
+ private delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
+
+ [DllImport("user32.dll")]
+ private static extern bool UnhookWinEvent(IntPtr hWinEventHook);
+
+ [DllImport("user32.dll")]
+ private static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
+
+ [DllImport("user32.dll")]
+ private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
+
+ #endregion
+
+ #region Constants
+
+ private const uint WINEVENT_OUTOFCONTEXT = 0;
+ private const uint EVENT_SYSTEM_FOREGROUND = 3;
+
+ private const int MAX_TITLE_LENGTH = 256;
+
+ #endregion
+
+ #region Properties & Fields
+
+ // DarthAffe 17.12.2016: We need to keep a reference to this or it might get collected by the garbage collector and cause some random crashes afterwards.
+ private static WinEventDelegate _activeWindowChangedDelegate;
+ private static IntPtr _winEventHook;
+
+ public static string ActiveWindowProcessName { get; private set; }
+ public static string ActiveWindowWindowTitle { get; private set; }
+
+ #endregion
+
+ #region Methods
+
+ private static void ActiveWindowChanged(IntPtr hWinEventHook, uint eventType,
+ IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
+ {
+ ActiveWindowProcessName = GetActiveWindowProcessName(hwnd) ?? string.Empty;
+ ActiveWindowWindowTitle = GetActiveWindowTitle(hwnd) ?? string.Empty;
+ }
+
+ private static string GetActiveWindowProcessName(IntPtr hwnd)
+ {
+ try
+ {
+ uint pid;
+ GetWindowThreadProcessId(hwnd, out pid);
+ return System.Diagnostics.Process.GetProcessById((int)pid).ProcessName;
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ private static string GetActiveWindowTitle(IntPtr hwnd)
+ {
+ try
+ {
+ StringBuilder buffer = new StringBuilder(MAX_TITLE_LENGTH);
+ return GetWindowText(hwnd, buffer, MAX_TITLE_LENGTH) > 0 ? buffer.ToString() : null;
+ }
+ catch
+ {
+ return null;
+ }
+ }
+
+ public static void Initialize()
+ {
+ try
+ {
+ if (_winEventHook != IntPtr.Zero) return;
+
+ _activeWindowChangedDelegate = ActiveWindowChanged;
+ _winEventHook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, _activeWindowChangedDelegate, 0, 0, WINEVENT_OUTOFCONTEXT);
+ }
+ catch { /* catch'em all - I don't want it to crash here */ }
+ }
+
+ public static void Dispose()
+ {
+ try
+ {
+ if (_winEventHook == IntPtr.Zero) return;
+
+ UnhookWinEvent(_winEventHook);
+ _activeWindowChangedDelegate = null;
+ _winEventHook = IntPtr.Zero;
+ }
+ catch { /* catch'em all - I don't want it to crash here */ }
+ }
+
+ #endregion
+ }
+}