upd
@@ -1,22 +1,78 @@
|
||||
using System.Windows;
|
||||
using NAudio.CoreAudioApi;
|
||||
using Application = System.Windows.Application;
|
||||
|
||||
namespace HttpKeys;
|
||||
|
||||
[Flags]
|
||||
public enum MicMode
|
||||
{
|
||||
None = 0,
|
||||
Any = 1 << 0,
|
||||
Ts = 1 << 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
private Dictionary<MicMode, Icon> _trayIcons = new();
|
||||
|
||||
private NotifyIcon _trayIcon;
|
||||
|
||||
private const string TsDeviceId =
|
||||
"{0.0.1.00000000}.{cf287ff4-c39e-4b09-bc8d-b927c7d59779}";
|
||||
|
||||
public void UpdateIcon()
|
||||
{
|
||||
using var enumerator = new MMDeviceEnumerator();
|
||||
|
||||
var devices = enumerator
|
||||
.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active)
|
||||
.Select(d => new
|
||||
{
|
||||
Id = d.ID,
|
||||
Muted = d.AudioEndpointVolume.Mute
|
||||
})
|
||||
.ToList();
|
||||
|
||||
if (devices.Count == 0)
|
||||
{
|
||||
_trayIcon.Icon = _trayIcons[MicMode.None];
|
||||
return;
|
||||
}
|
||||
|
||||
bool tsMuted = devices.Any(x =>
|
||||
string.Equals(x.Id, TsDeviceId, StringComparison.OrdinalIgnoreCase) && x.Muted);
|
||||
|
||||
bool anyMuted = devices.Any(x =>
|
||||
!string.Equals(x.Id, TsDeviceId, StringComparison.OrdinalIgnoreCase) && x.Muted);
|
||||
|
||||
MicMode mode = MicMode.None;
|
||||
|
||||
if (tsMuted)
|
||||
mode |= MicMode.Ts;
|
||||
|
||||
if (anyMuted)
|
||||
mode |= MicMode.Any;
|
||||
|
||||
|
||||
_trayIcon.Icon = _trayIcons[mode];
|
||||
}
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
|
||||
_trayIcons.Add(MicMode.Ts | MicMode.Any, new Icon("micro_off.ico"));
|
||||
_trayIcons.Add(MicMode.None, new Icon("micro_on.ico"));
|
||||
_trayIcons.Add(MicMode.Ts, new Icon("micro_ts.ico"));
|
||||
_trayIcons.Add(MicMode.Any, new Icon("micro_any.ico"));
|
||||
|
||||
_trayIcon = new NotifyIcon
|
||||
{
|
||||
Icon = new System.Drawing.Icon("app.ico"),
|
||||
Icon = _trayIcons[MicMode.None],
|
||||
Visible = true,
|
||||
Text = "My WPF Tray App"
|
||||
};
|
||||
|
||||
@@ -13,6 +13,22 @@
|
||||
<None Update="app.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="micro_any.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="micro_off.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="micro_on.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="micro_ts.ico">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NAudio" Version="2.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace HttpKeys;
|
||||
class Params
|
||||
{
|
||||
public string ActionId { get; set; } = null!;
|
||||
public string State { get; set; } = null!;
|
||||
public bool IsOn { get; set; }
|
||||
public bool ToggleChanged { get; set; }
|
||||
}
|
||||
|
||||
@@ -52,22 +52,34 @@ public class Listener
|
||||
var p = JsonSerializer.Deserialize<Params>(body, options);
|
||||
if (p == null)
|
||||
continue;
|
||||
|
||||
Log(body);
|
||||
|
||||
|
||||
Log("---- REQUEST ----");
|
||||
Log("URL: " + p.ActionId);
|
||||
Log("URL: " + p.State);
|
||||
Log("URL: " + p.ToggleChanged);
|
||||
if(p.ActionId == "globalmute")
|
||||
MicController.ToggleAllMicsSimple(p.IsOn);
|
||||
|
||||
var responseBytes = "OK"u8.ToArray();
|
||||
ctx.Response.StatusCode = 200;
|
||||
ctx.Response.ContentType = "text/plain; charset=utf-8";
|
||||
await ctx.Response.OutputStream.WriteAsync(responseBytes);
|
||||
ctx.Response.Close();
|
||||
if (p.ActionId == "tsmute")
|
||||
MicController.ToggleTsMicsSimple(p.IsOn);
|
||||
|
||||
await WriteText(ctx, 200, "OK");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log("Error: " + ex.Message);
|
||||
await WriteText(ctx, 500, "Error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task WriteText(HttpListenerContext ctx, int statusCode, string text)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(text);
|
||||
ctx.Response.StatusCode = statusCode;
|
||||
ctx.Response.ContentType = "text/plain; charset=utf-8";
|
||||
ctx.Response.ContentLength64 = bytes.Length;
|
||||
await ctx.Response.OutputStream.WriteAsync(bytes, 0, bytes.Length);
|
||||
ctx.Response.OutputStream.Close();
|
||||
ctx.Response.Close();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace HttpKeys;
|
||||
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using NAudio.CoreAudioApi;
|
||||
using Application = System.Windows.Application;
|
||||
|
||||
namespace HttpKeys;
|
||||
|
||||
public static class MicController
|
||||
{
|
||||
public static void PrintCaptureDevices()
|
||||
{
|
||||
using var enumerator = new MMDeviceEnumerator();
|
||||
var devices = enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.All);
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
Console.WriteLine("===================================");
|
||||
Console.WriteLine($"Name: {device.FriendlyName}");
|
||||
Console.WriteLine($"ID: {device.ID}");
|
||||
Console.WriteLine($"State:{device.State}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Управляет всеми активными микрофонами.
|
||||
/// isOn = true → микрофоны включены (Mute = false)
|
||||
/// isOn = false → микрофоны выключены (Mute = true)
|
||||
/// </summary>
|
||||
public static void ToggleAllMicsSimple(bool isOn)
|
||||
{
|
||||
using var enumerator = new MMDeviceEnumerator();
|
||||
var devices = enumerator.EnumerateAudioEndPoints(DataFlow.Capture, DeviceState.Active);
|
||||
|
||||
foreach (var device in devices)
|
||||
{
|
||||
var endpoint = device.AudioEndpointVolume;
|
||||
|
||||
bool shouldBeMuted = !isOn;
|
||||
|
||||
// Если уже в нужном состоянии — ничего не делаем
|
||||
if (endpoint.Mute == shouldBeMuted)
|
||||
continue;
|
||||
|
||||
endpoint.Mute = shouldBeMuted;
|
||||
}
|
||||
|
||||
var app = Application.Current;
|
||||
app.Dispatcher.Invoke(() =>(app as App)?.UpdateIcon());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Управляет конкретным микрофоном по ID.
|
||||
/// </summary>
|
||||
public static void ToggleTsMicsSimple(bool isOn)
|
||||
{
|
||||
SetMicStateById(
|
||||
"{0.0.1.00000000}.{cf287ff4-c39e-4b09-bc8d-b927c7d59779}",
|
||||
isOn
|
||||
);
|
||||
|
||||
var app = Application.Current;
|
||||
app.Dispatcher.Invoke(() =>(app as App)?.UpdateIcon());
|
||||
}
|
||||
|
||||
private static void SetMicStateById(string deviceId, bool isOn)
|
||||
{
|
||||
using var enumerator = new MMDeviceEnumerator();
|
||||
|
||||
MMDevice device;
|
||||
|
||||
try
|
||||
{
|
||||
device = enumerator.GetDevice(deviceId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (device.DataFlow != DataFlow.Capture)
|
||||
return;
|
||||
|
||||
if (device.State != DeviceState.Active)
|
||||
return;
|
||||
|
||||
var endpoint = device.AudioEndpointVolume;
|
||||
|
||||
bool shouldBeMuted = !isOn;
|
||||
|
||||
// Уже в нужном состоянии — выходим
|
||||
if (endpoint.Mute == shouldBeMuted)
|
||||
return;
|
||||
|
||||
endpoint.Mute = shouldBeMuted;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 264 KiB |
|
After Width: | Height: | Size: 264 KiB |
|
After Width: | Height: | Size: 264 KiB |
|
After Width: | Height: | Size: 264 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 65 KiB |
@@ -3,21 +3,12 @@ let uuid = null;
|
||||
let ctxSettings = new Map();
|
||||
|
||||
const ACTION_MAP = {
|
||||
"ru.wildtail.httpkeys.discord_micro_mute": {
|
||||
actionId: "discord_micro_mute"
|
||||
"ru.wildtail.httpkeys.globalmute": {
|
||||
actionId: "globalmute"
|
||||
},
|
||||
"ru.wildtail.httpkeys.discord_mute": {
|
||||
actionId: "discord_mute"
|
||||
"ru.wildtail.httpkeys.tsmute": {
|
||||
actionId: "tsmute"
|
||||
},
|
||||
"ru.wildtail.httpkeys.teamspeak_micro_mute": {
|
||||
actionId: "teamspeak_micro_mute"
|
||||
},
|
||||
"ru.wildtail.httpkeys.talk_micro_mute": {
|
||||
actionId: "talk_micro_mute"
|
||||
},
|
||||
"ru.wildtail.httpkeys.system_micro_mute": {
|
||||
actionId: "system_micro_mute"
|
||||
}
|
||||
};
|
||||
|
||||
// подключение от D6
|
||||
@@ -42,6 +33,17 @@ function connectElgatoStreamDeckSocket(inPort, inUUID, inRegisterEvent, inInfo)
|
||||
const s = (payload && payload.settings) || { isOn: false };
|
||||
ctxSettings.set(context, s);
|
||||
setState(context, s.isOn ? 1 : 0);
|
||||
|
||||
const cfg = ACTION_MAP[action];
|
||||
if (!cfg) return;
|
||||
|
||||
post("http://127.0.0.1:16888/press", {
|
||||
actionUUID: action,
|
||||
actionId: cfg.actionId,
|
||||
toggleChanged: false,
|
||||
isOn: !s.isOn,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -84,13 +86,8 @@ function handleKeyDown(action, context) {
|
||||
post("http://127.0.0.1:16888/press", {
|
||||
actionUUID: action,
|
||||
actionId: cfg.actionId,
|
||||
|
||||
toggleChanged: prevState !== newState,
|
||||
state: newState ? "on" : "off",
|
||||
|
||||
isOn: newState,
|
||||
context: context,
|
||||
timestamp: Date.now()
|
||||
isOn: !newState,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -15,99 +15,38 @@
|
||||
|
||||
"Actions": [
|
||||
{
|
||||
"Name": "Discord Mute Micro",
|
||||
"UUID": "ru.wildtail.httpkeys.discord_micro_mute",
|
||||
"Name": "Global Mute Micro",
|
||||
"UUID": "ru.wildtail.httpkeys.globalmute",
|
||||
"Icon": "icon",
|
||||
"Tooltip": "Toggle Discord Mute Micro",
|
||||
"Tooltip": "Global Mute Micro",
|
||||
"PropertyInspectorPath": "index.html",
|
||||
"States": [
|
||||
{
|
||||
"Image": "icons/DiscordUnmuteMicro",
|
||||
"Image": "icons/micro_on",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
},
|
||||
{
|
||||
"Image": "icons/DiscordMuteMicro",
|
||||
"Image": "icons/micro_off",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"Name": "Discord Mute",
|
||||
"UUID": "ru.wildtail.httpkeys.discord_mute",
|
||||
"Icon": "icon",
|
||||
"Tooltip": "Toggle Discord Full Mute",
|
||||
"PropertyInspectorPath": "index.html",
|
||||
"States": [
|
||||
{
|
||||
"Image": "icons/DiscordUnmute",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
},
|
||||
{
|
||||
"Image": "icons/DiscordMute",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"Name": "Teamspeak Mute Micro",
|
||||
"UUID": "ru.wildtail.httpkeys.teamspeak_micro_mute",
|
||||
"Name": "Teamspeacks Mute Micro",
|
||||
"UUID": "ru.wildtail.httpkeys.tsmute",
|
||||
"Icon": "icon",
|
||||
"Tooltip": "Toggle Teamspeak Mute Micro",
|
||||
"Tooltip": "Teamspeacks Mute Micro",
|
||||
"PropertyInspectorPath": "index.html",
|
||||
"States": [
|
||||
{
|
||||
"Image": "icons/TeamspeakUnmuteMicro",
|
||||
"Image": "icons/groupmicro_on",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
},
|
||||
{
|
||||
"Image": "icons/TeamspeakMuteMicro",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"Name": "Talk Mute Micro",
|
||||
"UUID": "ru.wildtail.httpkeys.talk_micro_mute",
|
||||
"Icon": "icon",
|
||||
"Tooltip": "Toggle Talk Mute",
|
||||
"PropertyInspectorPath": "index.html",
|
||||
"States": [
|
||||
{
|
||||
"Image": "icons/TalkUnmuteMicro",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
},
|
||||
{
|
||||
"Image": "icons/TalkMuteMicro",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"Name": "System Mute Micro",
|
||||
"UUID": "ru.wildtail.httpkeys.system_micro_mute",
|
||||
"Icon": "icon",
|
||||
"Tooltip": "Toggle System Mute Micro",
|
||||
"PropertyInspectorPath": "index.html",
|
||||
"States": [
|
||||
{
|
||||
"Image": "icons/SystemUnmuteMicro",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
},
|
||||
{
|
||||
"Image": "icons/SystemMuteMicro",
|
||||
"Image": "icons/groupmicro_off",
|
||||
"TitleAlignment": "middle",
|
||||
"FontSize": "12"
|
||||
}
|
||||
|
||||