Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recognize new names for Xbox Console Companion #170

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions XboxKeyboardMouse/UWPUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace XboxKeyboardMouse
{
internal struct WINDOWINFO
{
public uint ownerpid;
public uint childpid;
}

public class UWPUtils
{
#region User32
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

/// <summary>
/// Delegate for the EnumChildWindows method
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
/// <returns>True to continue enumerating, false to bail.</returns>
public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);

[DllImport("user32", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr hWndParent, EnumWindowProc lpEnumFunc, IntPtr lParam);
#endregion

#region Kernel32
public const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
public const UInt32 PROCESS_VM_READ = 0x010;

[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);

[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
UInt32 dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)]
Boolean bInheritHandle,
Int32 dwProcessId
);
#endregion

/// <summary>
/// Gets the path of application running in foreground
/// </summary>
/// <param name="hWnd">Window handle</param>
/// <returns>Path of the application</returns>
public static string GetProcessName(IntPtr hWnd)
{
string processName = null;

hWnd = GetForegroundWindow();

if (hWnd == IntPtr.Zero)
return null;

uint pID;
GetWindowThreadProcessId(hWnd, out pID);

IntPtr proc;
if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, (int)pID)) == IntPtr.Zero)
return null;

int capacity = 2000;
StringBuilder sb = new StringBuilder(capacity);
QueryFullProcessImageName(proc, 0, sb, ref capacity);

processName = sb.ToString(0, capacity);

// UWP apps are wrapped in another app called, if this has focus then try and find the child UWP process
if (Path.GetFileName(processName).Equals("ApplicationFrameHost.exe"))
{
processName = UWP_AppName(hWnd, pID);
}

return processName;
}

#region Get UWP Application Name

/// <summary>
/// Find child process for uwp apps, edge, mail, etc.
/// </summary>
/// <param name="hWnd">hWnd</param>
/// <param name="pID">pID</param>
/// <returns>The application name of the UWP.</returns>
private static string UWP_AppName(IntPtr hWnd, uint pID)
{
WINDOWINFO windowinfo = new WINDOWINFO();
windowinfo.ownerpid = pID;
windowinfo.childpid = windowinfo.ownerpid;

IntPtr pWindowinfo = Marshal.AllocHGlobal(Marshal.SizeOf(windowinfo));

Marshal.StructureToPtr(windowinfo, pWindowinfo, false);

EnumWindowProc lpEnumFunc = new EnumWindowProc(EnumChildWindowsCallback);
EnumChildWindows(hWnd, lpEnumFunc, pWindowinfo);

windowinfo = (WINDOWINFO)Marshal.PtrToStructure(pWindowinfo, typeof(WINDOWINFO));

IntPtr proc;
if ((proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, (int)windowinfo.childpid)) == IntPtr.Zero)
return null;

int capacity = 2000;
StringBuilder sb = new StringBuilder(capacity);
QueryFullProcessImageName(proc, 0, sb, ref capacity);

Marshal.FreeHGlobal(pWindowinfo);

return sb.ToString(0, capacity);
}

/// <summary>
/// Callback for enumerating the child windows.
/// </summary>
/// <param name="hWnd">hWnd</param>
/// <param name="lParam">lParam</param>
/// <returns>always <c>true</c>.</returns>
private static bool EnumChildWindowsCallback(IntPtr hWnd, IntPtr lParam)
{
WINDOWINFO info = (WINDOWINFO)Marshal.PtrToStructure(lParam, typeof(WINDOWINFO));

uint pID;
GetWindowThreadProcessId(hWnd, out pID);

if (pID != info.ownerpid)
info.childpid = pID;

Marshal.StructureToPtr(info, lParam, true);

return true;
}
#endregion
}
}
97 changes: 27 additions & 70 deletions XboxKeyboardMouse/XboxController/Emulation/XboxStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@

namespace XboxKeyboardMouse
{
class XboxStream {
class XboxStream
{
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out RECT Rect);

[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public struct RECT
{
public int X; //left
public int Y; //top
public int Width; //right
Expand All @@ -29,54 +28,8 @@ public struct RECT {

public static Thread tMouseMovement;

private static readonly string[] defaultAppNames = {
"Xbox",
"Xbox Console Companion",
"Xbox Console Companion - Beta",
"Xbox Companion-console",
"Xbox Companion-console - bèta",
"Xbox-konsol Companion",
"Xbox-konsol Companion - beta",
"Xbox konsoles palīgs",
"Xbox Konsolu Yardımcısı",
"Xbox Konsolu Yardımcısı - Beta",
"Xbox 主機小幫手",
"Xbox 主機小幫手 - beta 搶鮮版",
"Xbox 本体コンパニオン",
"Xbox 本体コンパニオン - ベータ",
"Xbox 본체 도우미",
"Xbox 본체 도우미 - 베타 버전",
"Xboxi konsooliabiline",
"Xboxi konsooliabiline - beetaversioon",
"„Xbox“ konsolės pagalbinė priemonė",
"„Xbox“ konsolės pagalbinė priemonė - beta versija",
"Compagnon de la console Xbox",
"Compagnon de la console Xbox - bêta",
"Compañero de la consola Xbox",
"Compañero de la consola Xbox - beta",
"Complemento da Consola Xbox",
"Complemento da Consola Xbox - beta",
"Companion console Xbox",
"Companion console Xbox - beta",
"Компаньон консоли Xbox",
"Компаньон консоли Xbox - бета-версия",
"Pomoćnik konzole Xbox",
"Pomoćnik konzole Xbox - beta-verzija",
"Pomocnik konsoli Xbox",
"Pomocnik konsoli Xbox - wersja Beta",
"Spremljevalec za konzolo Xbox",
"Spremljevalec za konzolo Xbox - beta",
"Teman Konsol Xbox",
"Teman Konsol Xbox - beta",
"Ứng dụng Đồng hành Bảng điều khiển Xbox",
"Ứng dụng Đồng hành Bảng điều khiển Xbox - beta",
"مصاحب وحدة تحكم Xbox",
"مصاحب وحدة تحكم Xbox - إصدار تجريبي",
"מסייע קונסולת Xbox",
"מסייע קונסולת Xbox - בתא",
};

public static void XboxAppDetector() {
public static void XboxAppDetector()
{
bool started = false;

const int count = 512;
Expand All @@ -88,20 +41,20 @@ public static void XboxAppDetector() {
Thread.Sleep(500);

IntPtr handle = GetForegroundWindow();
if (GetWindowText(handle, text, count) > 0)

var name = UWPUtils.GetProcessName(handle);

if (!name.EndsWith("XboxApp.exe") && started)
Copy link
Collaborator

@DavidRieman DavidRieman Jun 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes, while switching between applications/windows, GetForegroundWindow can return a handle of 0. GetProcessName then returns null, and the following null.EndsWith crashes the application. We need null safety on name, and should probably skip the GetProcessName work when handle is 0 as well.

{
if (!defaultAppNames.Contains(text.ToString()))
{
ShowAndFreeCursor();
started = false;
Program.MainForm.StatusWaiting();
}
else if (!started)
{
LockAndHideCursor();
started = true;
Program.MainForm.StatusRunning();
}
ShowAndFreeCursor();
started = false;
Program.MainForm.StatusWaiting();
}
if (name.EndsWith("XboxApp.exe") && !started)
{
LockAndHideCursor();
started = true;
Program.MainForm.StatusRunning();
}
}
}
Expand All @@ -111,7 +64,8 @@ public static void XboxAppDetector() {
}
}

private static void LockAndHideCursor() {
private static void LockAndHideCursor()
{
if (Program.HideCursor)
CursorView.CursorHide();

Expand All @@ -121,22 +75,25 @@ private static void LockAndHideCursor() {
tMouseMovement.Start();
}

private static void ShowAndFreeCursor() {
private static void ShowAndFreeCursor()
{
CursorView.CursorShow();

if (tMouseMovement != null)
tMouseMovement.Abort();
}

private static bool IsFullscreen(IntPtr handle) {
private static bool IsFullscreen(IntPtr handle)
{
bool runningFullScreen = false;
RECT appBounds;
Rectangle screenBounds;

GetWindowRect(handle, out appBounds);

screenBounds = Screen.FromHandle(handle).Bounds;
if ((appBounds.Height - appBounds.Y) == screenBounds.Height && (appBounds.Width - appBounds.X) == screenBounds.Width) {
if ((appBounds.Height - appBounds.Y) == screenBounds.Height && (appBounds.Width - appBounds.X) == screenBounds.Width)
{
runningFullScreen = true;
}

Expand Down
1 change: 1 addition & 0 deletions XboxKeyboardMouse/XboxKeyboardMouse.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="UWPUtils.cs" />
<Compile Include="XboxController\CursorView.cs" />
<Compile Include="Forms\ControllerPreview.cs">
<SubType>Form</SubType>
Expand Down