Using C# to control media en application volumes - c#

I'm trying to build my own mixer panel and got the hardware and software communication side working now all i need is to control the media on my computer using this. How do i control the media en stuff like volume on a window's computer the program i made is written en C# and communicates via serial to my mixer board based on Arduino. I searched around but i can't find a lot about controlling media using C# or volume control there seems to be nothing in the standard C# libraries about this.
I want it to be able to skip songs or go back and do the standard media control like this. I also got different sliders for volume and want to control the volume of different applications using this.

For controlling media you can use virtual keyboard inputs by hooking into the user32 DLL to virtual press the media control keys. This way you can do things like mute and skip to next track, but the Volume Control is limited to just controlling the main device volume just like a normal keyboard. Below is a simple code snipped of how to do this.
public class VirtualMediaController
{
internal enum VirtualKeyCodes
: uint
{
VOLUME_MUTE = 0xAD,
VOLUME_DOWN = 0xAE,
VOLUME_UP = 0xAF,
NEXT_TRACK = 0xB0,
PREVIOUS_TRACK = 0xB1,
STOP = 0xB2,
PLAY_PAUSE = 0xB3,
LAUNCH_MEDIA = 0xB5,
}
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
internal static extern void keybd_event(uint bVk, uint bScan, uint dwFlags, uint dwExtraInfo);
internal static void SendKey(VirtualKeyCodes virtualKeyCode)
{
keybd_event((uint)virtualKeyCode, 0, 0, 0);
}
public static void Mute()
{
SendKey(VirtualKeyCodes.VOLUME_MUTE);
}
public static void VolumeDown()
{
SendKey(VirtualKeyCodes.VOLUME_DOWN);
}
public static void VolumeUp()
{
SendKey(VirtualKeyCodes.VOLUME_UP);
}
public static void NextTrack()
{
SendKey(VirtualKeyCodes.NEXT_TRACK);
}
public static void PreviousTrack()
{
SendKey(VirtualKeyCodes.PREVIOUS_TRACK);
}
public static void Stop()
{
SendKey(VirtualKeyCodes.STOP);
}
public static void PlayPause()
{
SendKey(VirtualKeyCodes.PLAY_PAUSE);
}
public static void LaunchMedia()
{
SendKey(VirtualKeyCodes.LAUNCH_MEDIA);
}
}
For more accurate Volume Control you will have to use a library or build one that will hook into the windows mixer API. CoreAudio Github is an example of such a library and can be used as a jumping of point. It can be used to control audio output devices and gives you more fin grain control over the audio then just using a visual keyboard for the media keys (volume up, volume down and mute). This way you can also get information like current volume and mute status. But this type of library wont give you the play/pause and stop functionality so a combination of both options is best.

Related

Is it possible to call the winapi multimedia timer from a Unity3D program without crashing

Question also asked here.
I am on Windows 10, Unity Editor 2018.3.12f1
I have a requirement for very fast (500 Hz) and precise updates, "independent" from the Unity main thread. I am targeting windows desktop only, so the Multimedia Timers seemed as a good (the only?) fit. However I witness some weird crashes.
I tried this library which also includes a working example, and I also created this very simple mono behaviour to test it but with same results:
using System.Threading;
using System.Runtime.InteropServices;
using System;
public class MultimediaTimer : MonoBehaviour
{
private UInt32 userCtx = 0;
void Start()
{
Run();
//Thread r = new Thread(() => Run()); -- Ignore this
//r.Start();
}
void Run()
{
MultimediaTimerCallback Callback = new MultimediaTimerCallback(TimerCallbackMethod);
uint timerId = TimeSetEvent(100, 5, Callback, ref userCtx, 1);
Thread.Sleep(1000);
TimeKillEvent(timerId);
}
private static void TimerCallbackMethod(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2)
{
Debug.Log("Hi");
}
private delegate void MultimediaTimerCallback(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2);
[DllImport("winmm.dll", EntryPoint = "timeSetEvent")]
private static extern UInt32 TimeSetEvent(UInt32 msDelay, UInt32 msResolution, MultimediaTimerCallback callback, ref UInt32 userCtx, UInt32 eventType);
[DllImport("winmm.dll", EntryPoint = "timeKillEvent")]
private static extern UInt32 TimeKillEvent(UInt32 uTimerId);
}
When in Editor, when I press the play button, my sample game seems to be working correctly (ie prints in the Debug console, and with great precision when I used stopwatch to measure), but when i stop the game and try to run it again, the Editor hangs.
When i build and play, again everything seems normal (no debug messages there of course), but when i attempt to close the program via the 'X' button it hangs again.
My question is very simple. Is it possible to reliably call the multimedia timer from a Unity program? And if not could someone explain this behaviour I observe? I could encapsulate my timer logic in a separate process and use some form of IPC to achieve my requirement, but I would prefer for convenience to stay withing Unity. (Of course if you know any alternatives, by all means do say them)

Disable touch visual feedback on windows 8.1 (programmatically) [Desktop App]

I have a C# WPF application intended specifically for Win8.1 (a desktop app, NOT metro).
I want users to be able to use touch injections but I'm trying to disable the visualization feedback that windows creates for a Tap gesture Press Hold and Drag (like selecting multiple files on desktop) and other gestures (zooming scrolling etc).
After Searching the web for a long time I've found this post:
How do I disable Windows 8 touch contact visualizations for my application?
So I tried to do the same...
I tried this (Will put my Win32 class at the end)
public void DisableGestureVisualization()
{
const int SPI_SETCONTACTVISUALIZATION = 0x2019;
const int SPI_SETGESTUREVISUALIZATION = 0x201B;
ulong gv = 0;
Logger.Debug(!Win32.SystemParametersInfo(SPI_SETGESTUREVISUALIZATION, 0, ref gv, 0)
? #"Failed SystemParametersInfo SPI_SETGESTUREVISUALIZATION"
: #"Successfuly returned from SystemParametersInfo SPI_SETGESTUREVISUALIZATION");
Logger.Debug(!Win32.SystemParametersInfo(SPI_SETCONTACTVISUALIZATION, 0, ref gv, 0)
? #"Failed SystemParametersInfo SPI_SETCONTACTVISUALIZATION"
: #"Successfuly returned from SystemParametersInfo SPI_SETCONTACTVISUALIZATION");
}
And also this:
public void TryDisableWindowsVisualFeedback(IntPtr hWnd)
{
bool enable = false;
foreach (Win32.FEEDBACK_TYPE type in Enum.GetValues(typeof(Win32.FEEDBACK_TYPE)))
{
if (type == Win32.FEEDBACK_TYPE.FEEDBACK_MAX)
{
continue;
}
Logger.Debug(!Win32.SetWindowFeedbackSetting(hWnd, type, 0, 4, ref enable)
? #"Failed to SetWindowFeedbackSetting for " + type
: #"Successfuly returned from SetWindowFeedbackSetting for " + type);
}
}
And I call this from my WPF app like this:
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Window window = Window.GetWindow(this);
var wih = new WindowInteropHelper(window);
IntPtr hWnd = wih.Handle;
TryDisableWindowsVisualFeedback(hWnd);
}
This is my auxiliary Win32 class:
internal class Win32
{
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SystemParametersInfo(
uint uiAction,
uint uiParam,
ref ulong pvParam,
uint fWinIni
);
public enum FEEDBACK_TYPE : uint
{
FEEDBACK_TOUCH_CONTACTVISUALIZATION = 1,
FEEDBACK_PEN_BARRELVISUALIZATION = 2,
FEEDBACK_PEN_TAP = 3,
FEEDBACK_PEN_DOUBLETAP = 4,
FEEDBACK_PEN_PRESSANDHOLD = 5,
FEEDBACK_PEN_RIGHTTAP = 6,
FEEDBACK_TOUCH_TAP = 7,
FEEDBACK_TOUCH_DOUBLETAP = 8,
FEEDBACK_TOUCH_PRESSANDHOLD = 9,
FEEDBACK_TOUCH_RIGHTTAP = 10,
FEEDBACK_GESTURE_PRESSANDTAP = 11,
FEEDBACK_MAX = 0xFFFFFFFF
}
[DllImport("user32.dll")]
public static extern bool SetWindowFeedbackSetting(
IntPtr hwnd,
FEEDBACK_TYPE feedback,
uint dwFlags,
uint size,
[In] ref bool configuration
);
}
Non of the above disabled the round gray tap visual feedback nor did it disable the small white circle that appears when holding and dragging.
I even tried using the C# example in the blog:
Windows.UI.Input.PointerVisualizationSettings.
GetForCurrentView().
IsContactFeedbackEnabled = false;
This code works for a metro app, so I tried This SO post and got the Windows namespace but when running the code I get
"An unhandled exception of type 'System.Exception' occurred in MyProg.exe
WinRT information: Element not found.
Additional information: Element not found."
From what I could figure out, the PointerVisualizationSettings is not supported from a desktop application so this way is doomed...
If anyone can help me with this issue, please do.
Thanks
I had a similar problem and I was able to remove my tap gesture feedback by adding
Stylus.IsTapFeedbackEnabled = "False" to my root window.
Your TryDisableWindowsVisualFeedback method looks like it has the wrong pinvoke signature so you may be setting the visual feedback instead of clearing it. The configuration argument is a BOOL* not a bool*, and BOOL is a 4 byte integer. You can fix this with the MarshalAs attribute:
[In , MarshalAs(UnmanagedType.Bool)] ref bool configuration
You can call GetWindowFeedbackSetting to confirm that it was set correctly.
With the right pinvoke and hWnd, SetWindowFeedbackSetting should work. I confirmed that it does for me in a native app. WPF handles touch a bit oddly. I wouldn't expect it to affect this, but I haven't looked at WPF in depth for several years.
For your other methods, the Windows.UI.Input classes are documented to work only in Windows Store apps, so errors calling them from a desktop app are expected. Under the covers they'll make the same changes as SetWindowFeedbackSetting.
Using SystemParametersInfo to affect global UI is overkill: you don't want to solve a local problem by causing a global one. That said, it would probably work if you fire change notifications. Using SetWindowFeedbackSetting to target just your window is a much better solution though.
I don't know if this would resolve the OP's original issue (or even makes a difference), but I can confirm that I have successfully disabled all touch related visual feedback for my own Control-derived class selectively with the following method (almost like the one suggested by the OP) - at least on my Windows 10 machine:
public class MyTouchControl: Control
{
// ...a lot of other touch related stuff going on...
enum FEEDBACK_TYPE
{
TOUCH_CONTACTVISUALIZATION = 1,
PEN_BARRELVISUALIZATION = 2,
PEN_TAP = 3,
PEN_DOUBLETAP = 4,
PEN_PRESSANDHOLD = 5,
PEN_RIGHTTAP = 6,
TOUCH_TAP = 7,
TOUCH_DOUBLETAP = 8,
TOUCH_PRESSANDHOLD = 9,
TOUCH_RIGHTTAP = 10,
GESTURE_PRESSANDTAP = 11
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetWindowFeedbackSetting(IntPtr hWnd, FEEDBACK_TYPE feedback, int dwFlags, int size, ref int config);
void disableAllTouchVisualFeedback()
{
int enable = 0;
foreach (FEEDBACK_TYPE type in Enum.GetValues(typeof(FEEDBACK_TYPE)))
{
SetWindowFeedbackSetting(Handle, type, 0, 4, ref enable);
}
}
protected override void OnHandleCreated(EventArgs e)
{
disableAllTouchVisualFeedback();
base.OnHandleCreated(e);
}
}

Controlling volume in C# using WMPLib in Windows

The story:
I'm writing a music player controlled by voice. Previously the project used winamp for music -- which I'd like to do away with. I'd like to integrate the voice control with music player. The problem is, when changing the volume property of my media player object (mplayer.settings.volume = 5;), it changes the MASTER volume. Meaning any voice feedback will be completely inaudible while music is playing. Not cool when you're driving. If I fire up windows media player, I can change the volume of the music without affecting the master volume.. so there has to be a way.
I've thought of maybe finding out if there's an equalizer control buried in there, but the documentation on that is pathetic. -- either that or my google-fu is weak.
So does anyone know how I would go about separating master and music volume with windows media player control?
Particulars:
Target machine is XP(sp3), with .NET 4.0 I believe. Also, this is a console app.
Thanks in advance for any help
I have tested this in Windows Media Player VER 12, so I guess for most people there is a much easier way than using "user32.dll":
private static WMPLib.WindowsMediaPlayer Player;
public static void VolumeUp()
{
if (Player.settings.volume < 90)
{
Player.settings.volume = (Player.settings.volume + 10);
}
}
public static void VolumeDown()
{
if (Player.settings.volume > 1)
{
Player.settings.volume = (Player.settings.volume - (Player.settings.volume / 2));
}
}
No doubt this has been supported for some time now. It does not change the Master Volume and only the Media Player Volume is changed. The Windows Master Volume is left alone.
Hope this helps others out there that are not limited to XP SP3.
The only way I found of doing this was using Interop and WM_APPCOMMAND windows message:
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int WM_APPCOMMAND = 0x319;
private const int APPCOMMAND_MICROPHONE_VOLUME_UP = 26 * 65536;
private const int APPCOMMAND_MICROPHONE_VOLUME_DOWN = 25 * 65536;
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
private void SetMicVolume()
{
SendMessageW(new WindowInteropHelper(this).Handle, WM_APPCOMMAND, new (IntPtr)APPCOMMAND_MICROPHONE_VOLUME_UP);//or _DOWN
}

Spell checking library for Windows Mobile 6.x

We are looking into how we can check the spelling of text entered by the user in an app we have developed.
Is there any standard APIs and libraries/dictionaries included in the Windows Mobile 6.x OS that can be used for this? Please point me in the rigth direction if there is.
Thank you in advance!
Windows Mobile 6 has Auto Correction and Auto Suggestion built in. You can enable and disable these from your app with the following PInvoke call.
public static class InputContext
{
private enum SHIC_FEATURE : uint
{
RESTOREDEFAULT = 0,
AUTOCORRECT = 1,
AUTOSUGGEST = 2,
HAVETRAILER = 3,
CLASS = 4
}
[DllImport("aygshell.dll")]
private static extern int SHSetInputContext(IntPtr hwnd, SHIC_FEATURE dwFeature, ref bool lpValue);
public static void SetAutoSuggestion(IntPtr handle, bool enable)
{
SHSetInputContext(handle, SHIC_FEATURE.AUTOSUGGEST, ref enable);
SHSetInputContext(handle, SHIC_FEATURE.AUTOCORRECT, ref enable);
}
}

C# get master volume level/precent

I got this code to mute/unmute the master volume
private const int APPCOMMAND_VOLUME_MUTE = 0x80000;
private const int WM_APPCOMMAND = 0x319;
[DllImport("user32.dll")]
public static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
SendMessageW(this.Handle, WM_APPCOMMAND, this.Handle, (IntPtr)APPCOMMAND_VOLUME_MUTE);
I would to know how can I get the master volume level/precent because I want to know if the sound is already muted or not.
Edit:
or else I would like to split the mute/unmute sound so I will have two functions - one for mute and one for unmute.
thanks
Have a look at this project http://www.codeproject.com/KB/vista/CoreAudio.aspx
They created an own mixer control, that also reports the current volumne and the mute/unmute state:
defaultDevice.AudioEndpointVolume.OnVolumeNotification += new AudioEndpointVolumeNotificationDelegate(
AudioEndpointVolume_OnVolumeNotification);
// .. snip ..
void AudioEndpointVolume_OnVolumeNotification(AudioVolumeNotificationData data)
{
Console.WriteLine("New Volume {0}", data.MasterVolume);
Console.WriteLine("Muted {0}", data.Muted);
}
Does this help you?
EDIT: With this code and the class from the project you should be able to set and unset mute directly (without toggle):
MMDeviceEnumerator devEnum = new MMDeviceEnumerator();
MMDevice defaultDevice = devEnum.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia);
defaultDevice.AudioEndpointVolume.Mute = true; // or false
I could not do it for all Windows versions (xp, vista & 7).
Though, I achieved it by used external programs, such as NirCmd, and sent the command I needed.
not so good solution but it did solve my problem.
This thread shows how to control the master volume from C#.
You might also be interested in the responses to this question: Get Master Sound Volume in c#
Especially the NAudio managed wrapper.

Categories