Capture keypress in Unity when Unity doesn't have the input focus - unity3d

I need Unity to capture ALL key presses, even if Unity doesn't have the focus.
I've tried to use:
Input.KeyPress()
But this seems to only work if Unity has the focus of the user's input. I need it to work when it doesn't have the focus, such as when I'm looking at / working with another Windows program.
PS: I already turned on the "Run in Background" option in player preferences.

This is totally possible! Although, there is no way to do it by using only the tools in-built into Unity3D. You will have to use native libraries to do that.
The example below hooks the hook chain with a hook type of WH_KEYBOARD, which corresponds to a message-level keyboard hook. You can read more on SetWindowsHookEx and different types [ here][1].
You can check the parameters that are being received on hooking such a message type (WH_KEYBOARD) [here][2]
using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
public class KBHooks : MonoBehaviour
{
[DllImport("user32")]
protected static extern IntPtr SetWindowsHookEx(
HookType code, HookProc func, IntPtr hInstance, int threadID);
[DllImport("user32")]
protected static extern int UnhookWindowsHookEx(
IntPtr hhook);
[DllImport("user32")]
protected static extern int CallNextHookEx(
IntPtr hhook, int code, IntPtr wParam, IntPtr lParam);
// Hook types. To hook the keyboard we only need WH_KEYBOARD
protected enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
protected IntPtr m_hhook = IntPtr.Zero;
protected HookType m_hookType = HookType.WH_KEYBOARD;
protected delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
//We install the hook and hold on to the hook handle.
//The handle will be need to unhook.
protected bool Install(HookProc cbFunc)
{
if (m_hhook == IntPtr.Zero)
m_hhook = SetWindowsHookEx(
m_hookType,
cbFunc,
IntPtr.Zero,
(int)AppDomain.GetCurrentThreadId());
if (m_hhook == IntPtr.Zero)
return false;
return true;
}
protected void Uninstall()
{
if (m_hhook != IntPtr.Zero)
{
UnhookWindowsHookEx(m_hhook);
m_hhook = IntPtr.Zero;
}
}
protected int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
{
if (code < 0)
return CallNextHookEx(m_hhook, code, wParam, lParam);
Debug.Log(
"hook code =" + code.ToString() +
" lparam=" + lParam.ToString() +
" wparam=" + wParam.ToString());
// Yield to the next hook in the chain
return CallNextHookEx(m_hhook, code, wParam, lParam);
}
// Use this for initialization
void Start()
{
Debug.Log("install hook");
Install(CoreHookProc);
}
void OnDisable()
{
Debug.Log("Uninstall hook");
Uninstall();
}
}
This example comes from [this blog][3].
Such a way of hooking will only work on Windows systems. If you need to make a separate hook on OS X or Linux you would need to do it in a native way in that operating system.
I cannot post more than 1 link because I lack reputation on SO. I hope one of the mods will edit my post accordingly.
[1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
[2]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644984(v=vs.85).aspx
[3]: http://phardera.blogspot.com.es/2010/12/windows-hooks-in-unity3d.html

I've assembled a Unity package based on the #boris-makogonyuk answer with some usability improvements.
The package is available on GitHub (MIT license): https://github.com/Elringus/UnityRawInput
You can use it as follows:
Include package namespace.
using UnityRawInput;
Initialize the input service to start processing native input messages.
RawKeyInput.Start();
Optinally, you can specify whether input messages should be handled when the application is not in focus (disabled by default).
var workInBackground = true;
RawKeyInput.Start(workInBackground);
Add listeners for the input events.
RawKeyInput.OnKeyUp += HandleKeyUp;
RawKeyInput.OnKeyDown += HandleKeyDown;
private void HandleKeyUp (RawKey key) { ... }
private void HandleKeyDown (RawKey key) { ... }
You can also check whether specific key is currently pressed.
if (RawKeyInput.IsKeyDown(key)) { ... }
You can stop the service at any time.
RawKeyInput.Stop();
Don't forget to remove listeners when you no longer need them.
private void OnDisable ()
{
RawKeyInput.OnKeyUp -= HandleKeyUp;
RawKeyInput.OnKeyDown -= HandleKeyDown;
}

Related

Installing 'printer forms' using powershell without prnadmin.dll?

Due to the fact that the latest security updates coming from Microsoft have turned the Jet OLEDB Provider unusable I have to rewrite several elder VBScripts.
Is there a better way to install printer forms on Windows Server 2008 R2 and 2012 R2 then calling the outdated prnadmin.dll via regsvr32/COM/VBscript?
prnadmin.dll was first introduced with Windows Server 2000 Resource Kit and I would like to migrate the whole script to PowerShell.
Unfortunately I can't find any usefull PowerShell cmdlet within the module PrintManagement. So how can I add custom forms to the Printer Server using PSH?
The programmatic way to add a system form definition is to call AddForm. There is not a good wrapper for this call that I am aware of, but P/Invoking to AddForm works. I wrote a quick wrapper and posted it on GitHub.
Example using the wrapper:
Windows PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.
PS C:\Drop> Import-Module .\PowershellPrinterFormsModule.dll
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 1' -Units Inches -Size '4,5'
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 2' -Units Inches -Size '4,5' -Margin '0.25,0.5'
PS C:\Drop> Add-SystemForm -Name 'Demo User Form try 3' -Units Millimeters -Size '80,50' -Margin '10,10,0,0'
Actual P/Invoke call to AddForm:
SafePrinterHandle hServer;
if (!OpenPrinter(null, out hServer, IntPtr.Zero))
{
throw new Win32Exception();
}
using (hServer)
{
var form = new FORM_INFO_1()
{
Flags = 0,
Name = this.Name,
Size = (SIZEL)pageSize,
ImageableArea = (RECTL)imageableArea
};
if (!AddForm(hServer, 1, ref form))
{
throw new Win32Exception();
}
}
internal static class NativeMethods
{
#region Constants
internal const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
#endregion
#region winspool.drv
private const string Winspool = "winspool.drv";
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool OpenPrinter(string szPrinter, out SafePrinterHandle hPrinter, IntPtr pd);
public static SafePrinterHandle OpenPrinter(string szPrinter)
{
SafePrinterHandle hServer;
if (!OpenPrinter(null, out hServer, IntPtr.Zero))
{
throw new Win32Exception();
}
return hServer;
}
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool EnumForms(SafePrinterHandle hPrinter, int level, IntPtr pBuf, int cbBuf, out int pcbNeeded, out int pcReturned);
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool AddForm(SafePrinterHandle hPrinter, int level, [In] ref FORM_INFO_1 form);
[DllImport(Winspool, SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern bool DeleteForm(SafePrinterHandle hPrinter, string formName);
#endregion
#region Structs
[StructLayout(LayoutKind.Sequential)]
internal struct FORM_INFO_1
{
public int Flags;
[MarshalAs(UnmanagedType.LPWStr)]
public string Name;
public SIZEL Size;
public RECTL ImageableArea;
}
[StructLayout(LayoutKind.Sequential)]
internal struct SIZEL
{
public int cx;
public int cy;
public static explicit operator SIZEL(Size r)
=> new SIZEL { cx = (int)r.Width, cy = (int)r.Height };
public static explicit operator Size(SIZEL r)
=> new Size(r.cx, r.cy);
}
[StructLayout(LayoutKind.Sequential)]
internal struct RECTL
{
public int left;
public int top;
public int right;
public int bottom;
public static explicit operator RECTL(Rect r)
=> new RECTL { left = (int)r.Left, top = (int)r.Top, right = (int)r.Right, bottom = (int)r.Bottom };
public static explicit operator Rect(RECTL r)
=> new Rect(new Point(r.left, r.top), new Point(r.right, r.bottom));
}
#endregion
}
internal sealed class SafePrinterHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafePrinterHandle()
: base(true)
{
}
protected override bool ReleaseHandle()
{
return NativeMethods.ClosePrinter(handle);
}
}

How to move a window between desktops using powershell/.net on windows 10 [duplicate]

I love that Windows 10 now has support for virtual desktops built in, but I have some features that I'd like to add/modify (e.g., force a window to appear on all desktops, launch the task view with a hotkey, have per-monitor desktops, etc.)
I have searched for applications and developer references to help me customize my desktops, but I have had no luck.
Where should I start? I am looking for Windows API functions (ideally, that are callable from a C# application) that will give me programmatic access to manipulate virtual desktops and the windows therein.
The Windows SDK Support Team Blog posted a C# demo to switch Desktops via IVirtualDesktopManager:
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")]
[System.Security.SuppressUnmanagedCodeSecurity]
public interface IVirtualDesktopManager
{
[PreserveSig]
int IsWindowOnCurrentVirtualDesktop(
[In] IntPtr TopLevelWindow,
[Out] out int OnCurrentDesktop
);
[PreserveSig]
int GetWindowDesktopId(
[In] IntPtr TopLevelWindow,
[Out] out Guid CurrentDesktop
);
[PreserveSig]
int MoveWindowToDesktop(
[In] IntPtr TopLevelWindow,
[MarshalAs(UnmanagedType.LPStruct)]
[In]Guid CurrentDesktop
);
}
[ComImport, Guid("aa509086-5ca9-4c25-8f95-589d3c07b48a")]
public class CVirtualDesktopManager
{
}
public class VirtualDesktopManager
{
public VirtualDesktopManager()
{
cmanager = new CVirtualDesktopManager();
manager = (IVirtualDesktopManager)cmanager;
}
~VirtualDesktopManager()
{
manager = null;
cmanager = null;
}
private CVirtualDesktopManager cmanager = null;
private IVirtualDesktopManager manager;
public bool IsWindowOnCurrentVirtualDesktop(IntPtr TopLevelWindow)
{
int result;
int hr;
if ((hr = manager.IsWindowOnCurrentVirtualDesktop(TopLevelWindow, out result)) != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
return result != 0;
}
public Guid GetWindowDesktopId(IntPtr TopLevelWindow)
{
Guid result;
int hr;
if ((hr = manager.GetWindowDesktopId(TopLevelWindow, out result)) != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
return result;
}
public void MoveWindowToDesktop(IntPtr TopLevelWindow, Guid CurrentDesktop)
{
int hr;
if ((hr = manager.MoveWindowToDesktop(TopLevelWindow, CurrentDesktop)) != 0)
{
Marshal.ThrowExceptionForHR(hr);
}
}
}
it includes the API to detect on which desktop the Window is shown and it can switch and move a Windows the a Desktop.
Programmatic access to the virtual desktop feature is very limited, as Microsoft has only exposed the IVirtualDesktopManager COM interface. It does provide two key functions:
IVirtualDesktopManager::GetWindowDesktopId allows you to retrieve the ID of a virtual desktop, based on a window that is already assigned to that desktop.
IVirtualDesktopManager::MoveWindowToDesktop allows you to move a window to a specific virtual desktop.
Unfortunately, this is not nearly enough to accomplish anything useful. I've written some C# code based on the reverse-engineering work done by NickoTin. I can't read much of the Russian in his blog post, but his C++ code was pretty accurate.
I do need to emphasize that this code is not something you want to commit to in a product. Microsoft always feels free to change undocumented APIs whenever they feel like it. And there is a runtime risk as well: this code does not necessarily interact well when the user is tinkering with the virtual desktops. Always keep in mind that a virtual desktop can appear and disappear at any time, completely out of sync with your code.
To use the code, create a new C# class library project. I'll first post ComInterop.cs, it contains the COM interface declarations that match NickoTin's C++ declarations:
using System;
using System.Runtime.InteropServices;
namespace Windows10Interop {
internal static class Guids {
public static readonly Guid CLSID_ImmersiveShell =
new Guid(0xC2F03A33, 0x21F5, 0x47FA, 0xB4, 0xBB, 0x15, 0x63, 0x62, 0xA2, 0xF2, 0x39);
public static readonly Guid CLSID_VirtualDesktopManagerInternal =
new Guid(0xC5E0CDCA, 0x7B6E, 0x41B2, 0x9F, 0xC4, 0xD9, 0x39, 0x75, 0xCC, 0x46, 0x7B);
public static readonly Guid CLSID_VirtualDesktopManager =
new Guid("AA509086-5CA9-4C25-8F95-589D3C07B48A");
public static readonly Guid IID_IVirtualDesktopManagerInternal =
new Guid("AF8DA486-95BB-4460-B3B7-6E7A6B2962B5");
public static readonly Guid IID_IVirtualDesktop =
new Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4");
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("FF72FFDD-BE7E-43FC-9C03-AD81681E88E4")]
internal interface IVirtualDesktop {
void notimpl1(); // void IsViewVisible(IApplicationView view, out int visible);
Guid GetId();
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("AF8DA486-95BB-4460-B3B7-6E7A6B2962B5")]
internal interface IVirtualDesktopManagerInternal {
int GetCount();
void notimpl1(); // void MoveViewToDesktop(IApplicationView view, IVirtualDesktop desktop);
void notimpl2(); // void CanViewMoveDesktops(IApplicationView view, out int itcan);
IVirtualDesktop GetCurrentDesktop();
void GetDesktops(out IObjectArray desktops);
[PreserveSig]
int GetAdjacentDesktop(IVirtualDesktop from, int direction, out IVirtualDesktop desktop);
void SwitchDesktop(IVirtualDesktop desktop);
IVirtualDesktop CreateDesktop();
void RemoveDesktop(IVirtualDesktop desktop, IVirtualDesktop fallback);
IVirtualDesktop FindDesktop(ref Guid desktopid);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("a5cd92ff-29be-454c-8d04-d82879fb3f1b")]
internal interface IVirtualDesktopManager {
int IsWindowOnCurrentVirtualDesktop(IntPtr topLevelWindow);
Guid GetWindowDesktopId(IntPtr topLevelWindow);
void MoveWindowToDesktop(IntPtr topLevelWindow, ref Guid desktopId);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")]
internal interface IObjectArray {
void GetCount(out int count);
void GetAt(int index, ref Guid iid, [MarshalAs(UnmanagedType.Interface)]out object obj);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
internal interface IServiceProvider10 {
[return: MarshalAs(UnmanagedType.IUnknown)]
object QueryService(ref Guid service, ref Guid riid);
}
}
Next is Desktop.cs. It contains the friendly C# classes that you can use in your code:
using System;
using System.Runtime.InteropServices;
namespace Windows10Interop
{
public class Desktop {
public static int Count {
// Returns the number of desktops
get { return DesktopManager.Manager.GetCount(); }
}
public static Desktop Current {
// Returns current desktop
get { return new Desktop(DesktopManager.Manager.GetCurrentDesktop()); }
}
public static Desktop FromIndex(int index) {
// Create desktop object from index 0..Count-1
return new Desktop(DesktopManager.GetDesktop(index));
}
public static Desktop FromWindow(IntPtr hWnd) {
// Creates desktop object on which window <hWnd> is displayed
Guid id = DesktopManager.WManager.GetWindowDesktopId(hWnd);
return new Desktop(DesktopManager.Manager.FindDesktop(ref id));
}
public static Desktop Create() {
// Create a new desktop
return new Desktop(DesktopManager.Manager.CreateDesktop());
}
public void Remove(Desktop fallback = null) {
// Destroy desktop and switch to <fallback>
var back = fallback == null ? DesktopManager.GetDesktop(0) : fallback.itf;
DesktopManager.Manager.RemoveDesktop(itf, back);
}
public bool IsVisible {
// Returns <true> if this desktop is the current displayed one
get { return object.ReferenceEquals(itf, DesktopManager.Manager.GetCurrentDesktop()); }
}
public void MakeVisible() {
// Make this desktop visible
DesktopManager.Manager.SwitchDesktop(itf);
}
public Desktop Left {
// Returns desktop at the left of this one, null if none
get {
IVirtualDesktop desktop;
int hr = DesktopManager.Manager.GetAdjacentDesktop(itf, 3, out desktop);
if (hr == 0) return new Desktop(desktop);
else return null;
}
}
public Desktop Right {
// Returns desktop at the right of this one, null if none
get {
IVirtualDesktop desktop;
int hr = DesktopManager.Manager.GetAdjacentDesktop(itf, 4, out desktop);
if (hr == 0) return new Desktop(desktop);
else return null;
}
}
public void MoveWindow(IntPtr handle) {
// Move window <handle> to this desktop
DesktopManager.WManager.MoveWindowToDesktop(handle, itf.GetId());
}
public bool HasWindow(IntPtr handle) {
// Returns true if window <handle> is on this desktop
return itf.GetId() == DesktopManager.WManager.GetWindowDesktopId(handle);
}
public override int GetHashCode() {
return itf.GetHashCode();
}
public override bool Equals(object obj) {
var desk = obj as Desktop;
return desk != null && object.ReferenceEquals(this.itf, desk.itf);
}
private IVirtualDesktop itf;
private Desktop(IVirtualDesktop itf) { this.itf = itf; }
}
internal static class DesktopManager {
static DesktopManager() {
var shell = (IServiceProvider10)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_ImmersiveShell));
Manager = (IVirtualDesktopManagerInternal)shell.QueryService(Guids.CLSID_VirtualDesktopManagerInternal, Guids.IID_IVirtualDesktopManagerInternal);
WManager = (IVirtualDesktopManager)Activator.CreateInstance(Type.GetTypeFromCLSID(Guids.CLSID_VirtualDesktopManager));
}
internal static IVirtualDesktop GetDesktop(int index) {
int count = Manager.GetCount();
if (index < 0 || index >= count) throw new ArgumentOutOfRangeException("index");
IObjectArray desktops;
Manager.GetDesktops(out desktops);
object objdesk;
desktops.GetAt(index, Guids.IID_IVirtualDesktop, out objdesk);
Marshal.ReleaseComObject(desktops);
return (IVirtualDesktop)objdesk;
}
internal static IVirtualDesktopManagerInternal Manager;
internal static IVirtualDesktopManager WManager;
}
}
And finally a little test WinForms project that I used to test the code. Just drop 4 buttons on a form and name them buttonLeft/Right/Create/Destroy:
using Windows10Interop;
using System.Diagnostics;
...
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void buttonRight_Click(object sender, EventArgs e) {
var curr = Desktop.FromWindow(this.Handle);
Debug.Assert(curr.Equals(Desktop.Current));
var right = curr.Right;
if (right == null) right = Desktop.FromIndex(0);
if (right != null) {
right.MoveWindow(this.Handle);
right.MakeVisible();
this.BringToFront();
Debug.Assert(right.IsVisible);
}
}
private void buttonLeft_Click(object sender, EventArgs e) {
var curr = Desktop.FromWindow(this.Handle);
Debug.Assert(curr.Equals(Desktop.Current));
var left = curr.Left;
if (left == null) left = Desktop.FromIndex(Desktop.Count - 1);
if (left != null) {
left.MoveWindow(this.Handle);
left.MakeVisible();
this.BringToFront();
Debug.Assert(left.IsVisible);
}
}
private void buttonCreate_Click(object sender, EventArgs e) {
var desk = Desktop.Create();
desk.MoveWindow(this.Handle);
desk.MakeVisible();
Debug.Assert(desk.IsVisible);
Debug.Assert(desk.Equals(Desktop.Current));
}
private void buttonDestroy_Click(object sender, EventArgs e) {
var curr = Desktop.FromWindow(this.Handle);
var next = curr.Left;
if (next == null) next = curr.Right;
if (next != null && next != curr) {
next.MoveWindow(this.Handle);
curr.Remove(next);
Debug.Assert(next.IsVisible);
}
}
}
The only real quirk I noticed while testing this is that moving a window from one desktop to another can move it to the bottom of the Z-order when you first switch the desktop, then move the window. No such problem if you do it the other way around.
There is this guy that made a application to map keyboard shorcut to move a window between virtual desktop.
https://github.com/Grabacr07/SylphyHorn
(I use it every day )
He has a blog where he explain what he did
http://grabacr.net/archives/5701 ( you can use google translate it is in japanese)
He in fact used the same api mantionned in the Alberto Tostado response.
http://www.cyberforum.ru/blogs/105416/blog3671.html
and the api can be found on his github https://github.com/Grabacr07/VirtualDesktop
The api is really simple to use BUT it seems impossible to move a window from another process.
public static bool MoveToDesktop(IntPtr hWnd, VirtualDesktop virtualDesktop)
{
ThrowIfNotSupported();
int processId;
NativeMethods.GetWindowThreadProcessId(hWnd, out processId);
if (Process.GetCurrentProcess().Id == processId) // THAT LINE
{
var guid = virtualDesktop.Id;
VirtualDesktop.ComManager.MoveWindowToDesktop(hWnd, ref guid);
return true;
}
return false;
}
To workaround this problem they made another implementation that they use alongside the one in the russian blog
if (VirtualDesktopHelper.MoveToDesktop(hWnd, right) //<- the one in the russian blog
|| this.helper.MoveWindowToDesktop(hWnd, right.Id)) <- the second implementation
The second implementation can be found here: https://github.com/tmyt/VDMHelper
This one can move a window from another process to another desktop. BUT it is buggy right now. For exemple when i try to move some window like google chrome it crash.
So this is the result of my research. I m rigth now trying to make a StickyWindow feature with these api.
I fear that all about "Virtual desktops" in Windows 10 is undocumented, but in a Russian page I've seen documented the interfaces. I don't speak Russian but seems that they have used reversed engineering. Anyway, the code is very clear (Thanks to them!).
Keep an eye here:
http://www.cyberforum.ru/blogs/105416/blog3671.html
I've been trying to see if the old API's CreateDesktop, OpenDesktop, etc... is linked to the new Virtual-Desktops, but no way...
The interfaces work with the final production release of Windows 10 (2015-05-08), but you shouldn't use them in a real wide distributed application until Microsoft documents them. Too much risk.
Regards.

How to mute an application with PowerShell

I'm new to PowerShell and have been playing around with it lately.
My question is, how do you mute an specific application with PowerShell? For example, if I am watching a youtube video in chrome, I can mute chrome only by going into the volume mixer and muting chrome out of the list of apps. Is there a way to do this in PowerShell?
I found an article concerning how to mute everything but not a specific app.
Change audio level from powershell?
I wrapped the example-application posted here in a small powershell-script, so it can be used easily from Powershell, using the static methods. This should be what you are looking for, as long as you specify the correct app-name.
E.g:
[SetAppVolume.AppMuter]::Mute("Mozilla Firefox");
Sample code:
$def = #"
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
namespace SetAppVolume
{
public class AppMuter
{
public static void Mute(string app)
{
foreach (string name in EnumerateApplications())
{
Console.WriteLine("name:" + name);
if (name == app)
{
// display mute state & volume level (% of master)
Console.WriteLine("Mute:" + GetApplicationMute(app));
Console.WriteLine("Volume:" + GetApplicationVolume(app));
// mute the application
SetApplicationMute(app, true);
// set the volume to half of master volume (50%)
SetApplicationVolume(app, 50);
}
}
}
public static float? GetApplicationVolume(string name)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return null;
float level;
volume.GetMasterVolume(out level);
return level * 100;
}
public static bool? GetApplicationMute(string name)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return null;
bool mute;
volume.GetMute(out mute);
return mute;
}
public static void SetApplicationVolume(string name, float level)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return;
Guid guid = Guid.Empty;
volume.SetMasterVolume(level / 100, ref guid);
}
public static void SetApplicationMute(string name, bool mute)
{
ISimpleAudioVolume volume = GetVolumeObject(name);
if (volume == null)
return;
Guid guid = Guid.Empty;
volume.SetMute(mute, ref guid);
}
public static IEnumerable<string> EnumerateApplications()
{
// get the speakers (1st render + multimedia) device
IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
IMMDevice speakers;
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);
// activate the session manager. we need the enumerator
Guid IID_IAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
object o;
speakers.Activate(ref IID_IAudioSessionManager2, 0, IntPtr.Zero, out o);
IAudioSessionManager2 mgr = (IAudioSessionManager2)o;
// enumerate sessions for on this device
IAudioSessionEnumerator sessionEnumerator;
mgr.GetSessionEnumerator(out sessionEnumerator);
int count;
sessionEnumerator.GetCount(out count);
for (int i = 0; i < count; i++)
{
IAudioSessionControl ctl;
sessionEnumerator.GetSession(i, out ctl);
string dn;
ctl.GetDisplayName(out dn);
yield return dn;
Marshal.ReleaseComObject(ctl);
}
Marshal.ReleaseComObject(sessionEnumerator);
Marshal.ReleaseComObject(mgr);
Marshal.ReleaseComObject(speakers);
Marshal.ReleaseComObject(deviceEnumerator);
}
private static ISimpleAudioVolume GetVolumeObject(string name)
{
// get the speakers (1st render + multimedia) device
IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
IMMDevice speakers;
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);
// activate the session manager. we need the enumerator
Guid IID_IAudioSessionManager2 = typeof(IAudioSessionManager2).GUID;
object o;
speakers.Activate(ref IID_IAudioSessionManager2, 0, IntPtr.Zero, out o);
IAudioSessionManager2 mgr = (IAudioSessionManager2)o;
// enumerate sessions for on this device
IAudioSessionEnumerator sessionEnumerator;
mgr.GetSessionEnumerator(out sessionEnumerator);
int count;
sessionEnumerator.GetCount(out count);
// search for an audio session with the required name
// NOTE: we could also use the process id instead of the app name (with IAudioSessionControl2)
ISimpleAudioVolume volumeControl = null;
for (int i = 0; i < count; i++)
{
IAudioSessionControl ctl;
sessionEnumerator.GetSession(i, out ctl);
string dn;
ctl.GetDisplayName(out dn);
if (string.Compare(name, dn, StringComparison.OrdinalIgnoreCase) == 0)
{
volumeControl = ctl as ISimpleAudioVolume;
break;
}
Marshal.ReleaseComObject(ctl);
}
Marshal.ReleaseComObject(sessionEnumerator);
Marshal.ReleaseComObject(mgr);
Marshal.ReleaseComObject(speakers);
Marshal.ReleaseComObject(deviceEnumerator);
return volumeControl;
}
}
[ComImport]
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
internal class MMDeviceEnumerator
{
}
internal enum EDataFlow
{
eRender,
eCapture,
eAll,
EDataFlow_enum_count
}
internal enum ERole
{
eConsole,
eMultimedia,
eCommunications,
ERole_enum_count
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMMDeviceEnumerator
{
int NotImpl1();
[PreserveSig]
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice);
// the rest is not implemented
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IMMDevice
{
[PreserveSig]
int Activate(ref Guid iid, int dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
// the rest is not implemented
}
[Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAudioSessionManager2
{
int NotImpl1();
int NotImpl2();
[PreserveSig]
int GetSessionEnumerator(out IAudioSessionEnumerator SessionEnum);
// the rest is not implemented
}
[Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAudioSessionEnumerator
{
[PreserveSig]
int GetCount(out int SessionCount);
[PreserveSig]
int GetSession(int SessionCount, out IAudioSessionControl Session);
}
[Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAudioSessionControl
{
int NotImpl1();
[PreserveSig]
int GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] out string pRetVal);
// the rest is not implemented
}
[Guid("87CE5498-68D6-44E5-9215-6DA47EF883D8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ISimpleAudioVolume
{
[PreserveSig]
int SetMasterVolume(float fLevel, ref Guid EventContext);
[PreserveSig]
int GetMasterVolume(out float pfLevel);
[PreserveSig]
int SetMute(bool bMute, ref Guid EventContext);
[PreserveSig]
int GetMute(out bool pbMute);
}
}
"#;
Add-Type -TypeDefinition $def -Language CSharpVersion3
# Example usage
[SetAppVolume.AppMuter]::Mute("Mozilla Firefox");
I have recently enjoyed reading Feature Flags as a Service: The Only Way You Want Feature Flags that expresses my opinion neetly (I have no connection whatsoever to the team of rollout.io)
One of the great debates in the software world is that of build vs. buy. Anyone with a background in software development will tell you that the temptation to reinvent wheels is strong. Sure, any language’s standard libraries have optimized list sort functionality. But what’s the fun in that? Writing your own would be interesting and fun, and you wouldn’t have to rely on some other guy’s approach...When you build software for a living, you tend to react to obstacles by, well, building software. You do what you’re good at. This applies to individuals, and it applies to groups as a whole. But it’s important to overcome this tendency and make business decisions rather than emotional ones.
I would therefore suggest to use NirCmd's muteappvolume feature and build a small Powershell wrapper around it to suit your purposes. In my case, I have a long rain.mp3 playing with VLC without UI as a soundscape of my focus-hours — but I need to toggle mute/unmute for just this process for zooms or just listening to Annie Mac when doing mundane stuff. I toggle the mute/unmute just by pressing r in the terminal with this piece of code living in PowerShell's $profile. Again, it's not just muting, but toggling mute/unmute so I unmute doing exactly the same. No need to reinvent the wheel when such a cool tool as nircmd is readily available.
function toggleRain {
$commandLineProperty = '"C:\Program Files\VideoLAN\VLC\vlc.exe" --intf dummy c:\Users\Admin\Music\rain.mp3'
$rainPid = (Get-Process vlc | Where-Object {$_.CommandLine -eq $commandLineProperty}).Id
nircmd muteappvolume /$rainPid 2
}
Set-Alias r toggleRain

How to know that function in Tapi32.dll is executing from the c# code

Hello Everyone!!!
I am novice in Telephony Application and trying to make a very simple Panasonic telephone application to change class of service (COS) using Windows Tapi32.dll and panasonic TSP.I have made a function which will change the class of service in PBX ..But on running the application class of service is not changing in the PBX neither is my code giving me any type of error...Below is my code...
[DllImport("Tapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern int lineDevSpecific(IntPtr hLine,uint dwAddressID,uint hCall, IntPtr lpParams,uint dwSize);
[StructLayout(LayoutKind.Sequential)]
public struct UserRec
{
public int dwMode
{
get
{
return dwMode;
}
set
{
dwMode = 4;
}
}
public int dwParam1
{
get
{
return dwParam1;
}
set
{
dwParam1 = 18;
}
}
}
public static void Main(string[] args)
{
uint add = 0;
uint call = 0;
uint size = 0;
string vline = "125";
//IntPtr hline = &vline;
IntPtr hline = Marshal.StringToHGlobalUni(vline);
var sizeUserRec = Marshal.SizeOf(typeof(UserRec));
var userRec = Marshal.AllocHGlobal(sizeUserRec);
lineDevSpecific(hline, add, call, userRec, size);
var x = (UserRec)Marshal.PtrToStructure(userRec, typeof(UserRec));
Marshal.FreeHGlobal(userRec);
Console.WriteLine("Hii");
}
Plz help me or direct me in the write direction to get the things done.Thanx in advance...
lineDevSpecific() exposes error conditions through its return value, not SetLastError(), so:
You probably should remove SetLastError=true from the [DllImport] attribute,
You should test the return value of the function against the error constants listed in the documentation:
int result = lineDevSpecific(hline, add, call, userRec, size);
if (result < 0) {
// Handle error, depending on the value of 'result'.
}

Drag n Drop Operations across MDI Child Forms

I am trying to perform a simple drag-n-drop operation starting from one button in one MDI child form to another button in a different MDI child form. For some reason however the DragDrop event never gets fired when I attempt to drag one button to the other. It may be worth noting that when I drag the button my cursor becomes the black-cancel icon.
My code:
#region ActivatesDragDropControl
[DllImport ("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
private const int WM_NCACTIVATE = 0x0086;
#endregion
private void button1_MouseDown(object sender, MouseEventArgs e)
{
DoDragDrop(LocationNode, DragDropEffects.Link);
// to deactivate
SendMessage(Handle, WM_NCACTIVATE, 0, 0);
}
private void button1_DragDrop(object sender, DragEventArgs e)
{
//never gets here...
}
private void button1_DragEnter(object sender, DragEventArgs e)
{
// to activate
SendMessage(Handle, WM_NCACTIVATE, 1, 0);
}
OK so I played around a bit more and using DragEnter isn't enough; I had to set the DragEventArgs' Event value. In my case:
e.Effect = DragDropEffects.Link;