902 lines
30 KiB
C#
902 lines
30 KiB
C#
|
|
using System;
|
|||
|
|
using System.Runtime.InteropServices;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 跨平台系统控制器
|
|||
|
|
/// 提供亮度、音量等系统级功能的真实控制
|
|||
|
|
/// 支持 Windows、Android 等平台
|
|||
|
|
/// </summary>
|
|||
|
|
public static class WindowsSystemController
|
|||
|
|
{
|
|||
|
|
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR
|
|||
|
|
|
|||
|
|
#region Windows API 声明
|
|||
|
|
|
|||
|
|
// 音量控制 API
|
|||
|
|
[DllImport("user32.dll")]
|
|||
|
|
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
|
|||
|
|
|
|||
|
|
[DllImport("user32.dll")]
|
|||
|
|
private static extern byte MapVirtualKey(uint uCode, uint uMapType);
|
|||
|
|
|
|||
|
|
// 亮度控制 API
|
|||
|
|
[DllImport("dxva2.dll", SetLastError = true)]
|
|||
|
|
private static extern bool SetMonitorBrightness(IntPtr hMonitor, uint dwNewBrightness);
|
|||
|
|
|
|||
|
|
[DllImport("dxva2.dll", SetLastError = true)]
|
|||
|
|
private static extern bool GetMonitorBrightness(IntPtr hMonitor, ref uint pdwMinimumBrightness, ref uint pdwCurrentBrightness, ref uint pdwMaximumBrightness);
|
|||
|
|
|
|||
|
|
[DllImport("dxva2.dll", SetLastError = true)]
|
|||
|
|
private static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);
|
|||
|
|
|
|||
|
|
[DllImport("dxva2.dll", SetLastError = true)]
|
|||
|
|
private static extern bool GetPhysicalMonitorsFromHMONITOR(IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray);
|
|||
|
|
|
|||
|
|
[DllImport("user32.dll")]
|
|||
|
|
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);
|
|||
|
|
|
|||
|
|
[DllImport("dxva2.dll", SetLastError = true)]
|
|||
|
|
private static extern bool DestroyPhysicalMonitors(uint dwPhysicalMonitorArraySize, [In] PHYSICAL_MONITOR[] pPhysicalMonitorArray);
|
|||
|
|
|
|||
|
|
// WMI 相关 API (备用亮度控制方案)
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern IntPtr LoadLibrary(string lpFileName);
|
|||
|
|
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
|
|||
|
|
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern bool FreeLibrary(IntPtr hModule);
|
|||
|
|
|
|||
|
|
// 时间设置 API
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern bool SetSystemTime(ref SYSTEMTIME lpSystemTime);
|
|||
|
|
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern void GetSystemTime(out SYSTEMTIME lpSystemTime);
|
|||
|
|
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern bool SetLocalTime(ref SYSTEMTIME lpSystemTime);
|
|||
|
|
|
|||
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|||
|
|
private static extern void GetLocalTime(out SYSTEMTIME lpSystemTime);
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 常量定义
|
|||
|
|
|
|||
|
|
// 音量控制常量
|
|||
|
|
private const byte VK_VOLUME_MUTE = 0xAD;
|
|||
|
|
private const byte VK_VOLUME_DOWN = 0xAE;
|
|||
|
|
private const byte VK_VOLUME_UP = 0xAF;
|
|||
|
|
private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
|
|||
|
|
private const uint KEYEVENTF_KEYUP = 0x0002;
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 结构体定义
|
|||
|
|
|
|||
|
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
|||
|
|
public struct PHYSICAL_MONITOR
|
|||
|
|
{
|
|||
|
|
public IntPtr hPhysicalMonitor;
|
|||
|
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
|||
|
|
public string szPhysicalMonitorDescription;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData);
|
|||
|
|
|
|||
|
|
[StructLayout(LayoutKind.Sequential)]
|
|||
|
|
public struct Rect
|
|||
|
|
{
|
|||
|
|
public int left;
|
|||
|
|
public int top;
|
|||
|
|
public int right;
|
|||
|
|
public int bottom;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[StructLayout(LayoutKind.Sequential)]
|
|||
|
|
public struct SYSTEMTIME
|
|||
|
|
{
|
|||
|
|
public ushort wYear;
|
|||
|
|
public ushort wMonth;
|
|||
|
|
public ushort wDayOfWeek;
|
|||
|
|
public ushort wDay;
|
|||
|
|
public ushort wHour;
|
|||
|
|
public ushort wMinute;
|
|||
|
|
public ushort wSecond;
|
|||
|
|
public ushort wMilliseconds;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 音量控制
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置系统音量到指定百分比
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="volumePercent">音量百分比 (0-100)</param>
|
|||
|
|
public static bool SetSystemVolume(int volumePercent)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 获取当前音量
|
|||
|
|
int currentVolume = GetCurrentSystemVolume();
|
|||
|
|
if (currentVolume == -1) return false;
|
|||
|
|
|
|||
|
|
int targetVolume = Mathf.Clamp(volumePercent, 0, 100);
|
|||
|
|
int difference = targetVolume - currentVolume;
|
|||
|
|
|
|||
|
|
// 根据差值调整音量
|
|||
|
|
if (difference > 0)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < Math.Abs(difference); i += 2) // 每次大约调整2%
|
|||
|
|
{
|
|||
|
|
SystemVolumeUp();
|
|||
|
|
System.Threading.Thread.Sleep(10); // 短暂延时确保命令执行
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (difference < 0)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < Math.Abs(difference); i += 2) // 每次大约调整2%
|
|||
|
|
{
|
|||
|
|
SystemVolumeDown();
|
|||
|
|
System.Threading.Thread.Sleep(10); // 短暂延时确保命令执行
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Debug.Log($"WindowsSystemController: 音量已设置为 {targetVolume}%");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"WindowsSystemController: 设置音量失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 增加系统音量
|
|||
|
|
/// </summary>
|
|||
|
|
public static void SystemVolumeUp()
|
|||
|
|
{
|
|||
|
|
keybd_event(VK_VOLUME_UP, MapVirtualKey(VK_VOLUME_UP, 0), KEYEVENTF_EXTENDEDKEY, 0);
|
|||
|
|
keybd_event(VK_VOLUME_UP, MapVirtualKey(VK_VOLUME_UP, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 降低系统音量
|
|||
|
|
/// </summary>
|
|||
|
|
public static void SystemVolumeDown()
|
|||
|
|
{
|
|||
|
|
keybd_event(VK_VOLUME_DOWN, MapVirtualKey(VK_VOLUME_DOWN, 0), KEYEVENTF_EXTENDEDKEY, 0);
|
|||
|
|
keybd_event(VK_VOLUME_DOWN, MapVirtualKey(VK_VOLUME_DOWN, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 切换系统静音状态
|
|||
|
|
/// </summary>
|
|||
|
|
public static void SystemMute()
|
|||
|
|
{
|
|||
|
|
keybd_event(VK_VOLUME_MUTE, MapVirtualKey(VK_VOLUME_MUTE, 0), KEYEVENTF_EXTENDEDKEY, 0);
|
|||
|
|
keybd_event(VK_VOLUME_MUTE, MapVirtualKey(VK_VOLUME_MUTE, 0), KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取当前系统音量 (简化估算,实际实现可能需要更复杂的 API)
|
|||
|
|
/// </summary>
|
|||
|
|
private static int GetCurrentSystemVolume()
|
|||
|
|
{
|
|||
|
|
// 这是一个简化版本,实际实现需要使用 Windows Volume API
|
|||
|
|
// 目前返回 -1 表示无法获取,使用相对调整
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 亮度控制
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置显示器亮度
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="brightnessPercent">亮度百分比 (0-100)</param>
|
|||
|
|
public static bool SetMonitorBrightness(int brightnessPercent)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
uint brightness = (uint)Mathf.Clamp(brightnessPercent, 0, 100);
|
|||
|
|
|
|||
|
|
// 方法1: 尝试使用 DXVA2 API
|
|||
|
|
if (SetBrightnessViaDDC(brightness))
|
|||
|
|
{
|
|||
|
|
Debug.Log($"WindowsSystemController: 亮度已通过DDC设置为 {brightness}%");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方法2: 尝试使用 WMI (需要管理员权限)
|
|||
|
|
if (SetBrightnessViaWMI(brightness))
|
|||
|
|
{
|
|||
|
|
Debug.Log($"WindowsSystemController: 亮度已通过WMI设置为 {brightness}%");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 方法3: 使用 PowerShell 命令 (备用方案)
|
|||
|
|
if (SetBrightnessViaPowerShell(brightness))
|
|||
|
|
{
|
|||
|
|
Debug.Log($"WindowsSystemController: 亮度已通过PowerShell设置为 {brightness}%");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Debug.LogWarning("WindowsSystemController: 所有亮度控制方法都失败了");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"WindowsSystemController: 设置亮度失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通过 DDC/CI 设置亮度 (外接显示器)
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetBrightnessViaDDC(uint brightness)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
bool success = false;
|
|||
|
|
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) =>
|
|||
|
|
{
|
|||
|
|
uint numPhysicalMonitors = 0;
|
|||
|
|
if (GetNumberOfPhysicalMonitorsFromHMONITOR(hMonitor, ref numPhysicalMonitors) && numPhysicalMonitors > 0)
|
|||
|
|
{
|
|||
|
|
PHYSICAL_MONITOR[] physicalMonitors = new PHYSICAL_MONITOR[numPhysicalMonitors];
|
|||
|
|
|
|||
|
|
if (GetPhysicalMonitorsFromHMONITOR(hMonitor, numPhysicalMonitors, physicalMonitors))
|
|||
|
|
{
|
|||
|
|
for (uint i = 0; i < numPhysicalMonitors; i++)
|
|||
|
|
{
|
|||
|
|
if (SetMonitorBrightness(physicalMonitors[i].hPhysicalMonitor, brightness))
|
|||
|
|
{
|
|||
|
|
success = true;
|
|||
|
|
Debug.Log($"成功设置显示器 {physicalMonitors[i].szPhysicalMonitorDescription} 亮度为 {brightness}%");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DestroyPhysicalMonitors(numPhysicalMonitors, physicalMonitors);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return true; // 继续枚举
|
|||
|
|
}, IntPtr.Zero);
|
|||
|
|
|
|||
|
|
return success;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"DDC亮度控制失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通过 WMI 设置亮度 (笔记本内置屏幕)
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetBrightnessViaWMI(uint brightness)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 使用 WMI 设置亮度 (需要 System.Management 或者 PowerShell)
|
|||
|
|
// 这里使用简化的 PowerShell 调用方式
|
|||
|
|
string script = $"(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1,{brightness})";
|
|||
|
|
return ExecutePowerShellCommand(script);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"WMI亮度控制失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通过 PowerShell 设置亮度
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetBrightnessViaPowerShell(uint brightness)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 使用 Windows 10/11 的现代亮度控制
|
|||
|
|
string script = $@"
|
|||
|
|
Add-Type -AssemblyName System.Windows.Forms
|
|||
|
|
$brightness = {brightness}
|
|||
|
|
try {{
|
|||
|
|
(Get-WmiObject -Namespace root/WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1,$brightness)
|
|||
|
|
exit 0
|
|||
|
|
}} catch {{
|
|||
|
|
exit 1
|
|||
|
|
}}
|
|||
|
|
";
|
|||
|
|
|
|||
|
|
return ExecutePowerShellCommand(script);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"PowerShell亮度控制失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 执行 PowerShell 命令
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool ExecutePowerShellCommand(string script)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var processInfo = new System.Diagnostics.ProcessStartInfo
|
|||
|
|
{
|
|||
|
|
FileName = "powershell.exe",
|
|||
|
|
Arguments = $"-Command \"{script}\"",
|
|||
|
|
UseShellExecute = false,
|
|||
|
|
CreateNoWindow = true,
|
|||
|
|
RedirectStandardOutput = true,
|
|||
|
|
RedirectStandardError = true
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
using (var process = System.Diagnostics.Process.Start(processInfo))
|
|||
|
|
{
|
|||
|
|
process.WaitForExit(5000); // 5秒超时
|
|||
|
|
return process.ExitCode == 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"PowerShell执行失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#elif UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
|
|||
|
|
#region Android 实现
|
|||
|
|
|
|||
|
|
private static AndroidJavaClass _unityPlayer;
|
|||
|
|
private static AndroidJavaObject _currentActivity;
|
|||
|
|
private static AndroidJavaObject _audioManager;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 初始化Android系统控制
|
|||
|
|
/// </summary>
|
|||
|
|
static WindowsSystemController()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
_unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
|
|||
|
|
_currentActivity = _unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
|
|||
|
|
|
|||
|
|
// 获取AudioManager
|
|||
|
|
_audioManager = _currentActivity.Call<AndroidJavaObject>("getSystemService", "audio");
|
|||
|
|
|
|||
|
|
Debug.Log("Android系统控制器初始化成功");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android系统控制器初始化失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置Android系统音量
|
|||
|
|
/// </summary>
|
|||
|
|
public static bool SetSystemVolume(int volumePercent)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_audioManager == null) return false;
|
|||
|
|
|
|||
|
|
// 获取最大音量
|
|||
|
|
int maxVolume = _audioManager.Call<int>("getStreamMaxVolume", 3); // STREAM_MUSIC = 3
|
|||
|
|
|
|||
|
|
// 计算目标音量
|
|||
|
|
int targetVolume = Mathf.RoundToInt((volumePercent / 100f) * maxVolume);
|
|||
|
|
targetVolume = Mathf.Clamp(targetVolume, 0, maxVolume);
|
|||
|
|
|
|||
|
|
// 设置音量
|
|||
|
|
_audioManager.Call("setStreamVolume", 3, targetVolume, 0); // FLAG_SHOW_UI = 1, 不显示UI = 0
|
|||
|
|
|
|||
|
|
Debug.Log($"Android: 音量已设置为 {volumePercent}% (系统值: {targetVolume}/{maxVolume})");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android音量设置失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 增加Android系统音量
|
|||
|
|
/// </summary>
|
|||
|
|
public static void SystemVolumeUp()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_audioManager == null) return;
|
|||
|
|
|
|||
|
|
_audioManager.Call("adjustStreamVolume", 3, 1, 0); // STREAM_MUSIC, ADJUST_RAISE, no flags
|
|||
|
|
Debug.Log("Android: 音量增加");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android音量增加失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 降低Android系统音量
|
|||
|
|
/// </summary>
|
|||
|
|
public static void SystemVolumeDown()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_audioManager == null) return;
|
|||
|
|
|
|||
|
|
_audioManager.Call("adjustStreamVolume", 3, -1, 0); // STREAM_MUSIC, ADJUST_LOWER, no flags
|
|||
|
|
Debug.Log("Android: 音量降低");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android音量降低失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 切换Android系统静音
|
|||
|
|
/// </summary>
|
|||
|
|
public static void SystemMute()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_audioManager == null) return;
|
|||
|
|
|
|||
|
|
// 获取当前音量
|
|||
|
|
int currentVolume = _audioManager.Call<int>("getStreamVolume", 3);
|
|||
|
|
|
|||
|
|
if (currentVolume > 0)
|
|||
|
|
{
|
|||
|
|
// 静音
|
|||
|
|
_audioManager.Call("setStreamVolume", 3, 0, 0);
|
|||
|
|
Debug.Log("Android: 静音");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
// 恢复到中等音量
|
|||
|
|
int maxVolume = _audioManager.Call<int>("getStreamMaxVolume", 3);
|
|||
|
|
_audioManager.Call("setStreamVolume", 3, maxVolume / 2, 0);
|
|||
|
|
Debug.Log("Android: 恢复音量");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android静音切换失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置Android屏幕亮度
|
|||
|
|
/// </summary>
|
|||
|
|
public static bool SetMonitorBrightness(int brightnessPercent)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_currentActivity == null) return false;
|
|||
|
|
|
|||
|
|
// Android亮度范围是0-255
|
|||
|
|
float brightness = Mathf.Clamp01(brightnessPercent / 100f);
|
|||
|
|
int systemBrightness = Mathf.RoundToInt(brightness * 255f);
|
|||
|
|
|
|||
|
|
// 方法1: 设置当前窗口亮度 (仅对当前应用生效)
|
|||
|
|
AndroidJavaObject window = _currentActivity.Call<AndroidJavaObject>("getWindow");
|
|||
|
|
AndroidJavaObject layoutParams = window.Call<AndroidJavaObject>("getAttributes");
|
|||
|
|
|
|||
|
|
layoutParams.Set("screenBrightness", brightness); // 0.0f - 1.0f
|
|||
|
|
window.Call("setAttributes", layoutParams);
|
|||
|
|
|
|||
|
|
Debug.Log($"Android: 应用窗口亮度已设置为 {brightnessPercent}%");
|
|||
|
|
|
|||
|
|
// 方法2: 尝试设置系统亮度 (需要WRITE_SETTINGS权限)
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
AndroidJavaClass settingsSystem = new AndroidJavaClass("android.provider.Settings$System");
|
|||
|
|
AndroidJavaObject contentResolver = _currentActivity.Call<AndroidJavaObject>("getContentResolver");
|
|||
|
|
|
|||
|
|
bool success = settingsSystem.CallStatic<bool>("putInt",
|
|||
|
|
contentResolver,
|
|||
|
|
"screen_brightness",
|
|||
|
|
systemBrightness);
|
|||
|
|
|
|||
|
|
if (success)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"Android: 系统亮度已设置为 {brightnessPercent}%");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("Android: 系统亮度设置失败,可能缺少WRITE_SETTINGS权限");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"Android系统亮度设置失败 (权限问题): {ex.Message}");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android亮度设置失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取当前Android音量
|
|||
|
|
/// </summary>
|
|||
|
|
public static int GetCurrentVolume()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_audioManager == null) return -1;
|
|||
|
|
|
|||
|
|
int currentVolume = _audioManager.Call<int>("getStreamVolume", 3);
|
|||
|
|
int maxVolume = _audioManager.Call<int>("getStreamMaxVolume", 3);
|
|||
|
|
|
|||
|
|
return Mathf.RoundToInt((currentVolume / (float)maxVolume) * 100f);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"获取Android音量失败: {ex.Message}");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取当前Android亮度
|
|||
|
|
/// </summary>
|
|||
|
|
public static int GetCurrentBrightness()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (_currentActivity == null) return -1;
|
|||
|
|
|
|||
|
|
AndroidJavaClass settingsSystem = new AndroidJavaClass("android.provider.Settings$System");
|
|||
|
|
AndroidJavaObject contentResolver = _currentActivity.Call<AndroidJavaObject>("getContentResolver");
|
|||
|
|
|
|||
|
|
int brightness = settingsSystem.CallStatic<int>("getInt",
|
|||
|
|
contentResolver,
|
|||
|
|
"screen_brightness",
|
|||
|
|
128); // 默认值
|
|||
|
|
|
|||
|
|
return Mathf.RoundToInt((brightness / 255f) * 100f);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"获取Android亮度失败: {ex.Message}");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 时间控制
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 设置系统时间 - 跨平台实现
|
|||
|
|
/// </summary>
|
|||
|
|
/// <param name="dateTime">要设置的时间</param>
|
|||
|
|
/// <returns>设置是否成功</returns>
|
|||
|
|
public static bool SetSystemTime(DateTime dateTime)
|
|||
|
|
{
|
|||
|
|
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR
|
|||
|
|
return SetWindowsSystemTime(dateTime);
|
|||
|
|
#elif UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
return SetAndroidSystemTime(dateTime);
|
|||
|
|
#else
|
|||
|
|
Debug.Log($"[模拟] 系统时间设置为: {dateTime:yyyy-MM-dd HH:mm:ss}");
|
|||
|
|
return true;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取当前系统时间 - 跨平台实现
|
|||
|
|
/// </summary>
|
|||
|
|
/// <returns>当前系统时间</returns>
|
|||
|
|
public static DateTime GetSystemTime()
|
|||
|
|
{
|
|||
|
|
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR
|
|||
|
|
return GetWindowsSystemTime();
|
|||
|
|
#elif UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
return GetAndroidSystemTime();
|
|||
|
|
#else
|
|||
|
|
return DateTime.Now;
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Windows平台设置系统时间
|
|||
|
|
/// 注意:需要管理员权限
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetWindowsSystemTime(DateTime dateTime)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
SYSTEMTIME st = new SYSTEMTIME
|
|||
|
|
{
|
|||
|
|
wYear = (ushort)dateTime.Year,
|
|||
|
|
wMonth = (ushort)dateTime.Month,
|
|||
|
|
wDayOfWeek = (ushort)dateTime.DayOfWeek,
|
|||
|
|
wDay = (ushort)dateTime.Day,
|
|||
|
|
wHour = (ushort)dateTime.Hour,
|
|||
|
|
wMinute = (ushort)dateTime.Minute,
|
|||
|
|
wSecond = (ushort)dateTime.Second,
|
|||
|
|
wMilliseconds = (ushort)dateTime.Millisecond
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
bool result = SetLocalTime(ref st);
|
|||
|
|
|
|||
|
|
if (result)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"Windows: 系统时间已设置为 {dateTime:yyyy-MM-dd HH:mm:ss}");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("Windows: 设置系统时间失败,可能需要管理员权限");
|
|||
|
|
|
|||
|
|
// 尝试使用命令行方式
|
|||
|
|
return SetWindowsSystemTimeViaCommand(dateTime);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Windows系统时间设置失败: {ex.Message}");
|
|||
|
|
return SetWindowsSystemTimeViaCommand(dateTime);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通过命令行设置Windows系统时间
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetWindowsSystemTimeViaCommand(DateTime dateTime)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string dateCommand = $"date {dateTime:MM-dd-yyyy}";
|
|||
|
|
string timeCommand = $"time {dateTime:HH:mm:ss}";
|
|||
|
|
|
|||
|
|
var processDate = new System.Diagnostics.Process
|
|||
|
|
{
|
|||
|
|
StartInfo = new System.Diagnostics.ProcessStartInfo
|
|||
|
|
{
|
|||
|
|
FileName = "cmd.exe",
|
|||
|
|
Arguments = $"/C {dateCommand}",
|
|||
|
|
UseShellExecute = false,
|
|||
|
|
CreateNoWindow = true,
|
|||
|
|
Verb = "runas" // 以管理员身份运行
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
var processTime = new System.Diagnostics.Process
|
|||
|
|
{
|
|||
|
|
StartInfo = new System.Diagnostics.ProcessStartInfo
|
|||
|
|
{
|
|||
|
|
FileName = "cmd.exe",
|
|||
|
|
Arguments = $"/C {timeCommand}",
|
|||
|
|
UseShellExecute = false,
|
|||
|
|
CreateNoWindow = true,
|
|||
|
|
Verb = "runas" // 以管理员身份运行
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
bool dateSuccess = processDate.Start() && processDate.WaitForExit(5000);
|
|||
|
|
bool timeSuccess = processTime.Start() && processTime.WaitForExit(5000);
|
|||
|
|
|
|||
|
|
if (dateSuccess && timeSuccess)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"Windows: 通过命令行设置系统时间成功 {dateTime:yyyy-MM-dd HH:mm:ss}");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("Windows: 命令行设置系统时间失败,可能被用户拒绝或超时");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Windows命令行时间设置失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取Windows系统时间
|
|||
|
|
/// </summary>
|
|||
|
|
private static DateTime GetWindowsSystemTime()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
GetLocalTime(out SYSTEMTIME st);
|
|||
|
|
return new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"获取Windows系统时间失败: {ex.Message}");
|
|||
|
|
return DateTime.Now;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
#if UNITY_ANDROID && !UNITY_EDITOR
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Android平台设置系统时间
|
|||
|
|
/// 注意:需要WRITE_SECURE_SETTINGS权限,通常只有系统应用才能获得
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetAndroidSystemTime(DateTime dateTime)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
using (var unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
|
|||
|
|
using (var currentActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity"))
|
|||
|
|
using (var contentResolver = currentActivity.Call<AndroidJavaObject>("getContentResolver"))
|
|||
|
|
{
|
|||
|
|
// Android系统时间是以毫秒为单位的时间戳
|
|||
|
|
long timeMillis = ((DateTimeOffset)dateTime).ToUnixTimeMilliseconds();
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 尝试设置系统时间 (需要系统权限)
|
|||
|
|
var systemClock = new AndroidJavaClass("android.os.SystemClock");
|
|||
|
|
bool result = systemClock.CallStatic<bool>("setCurrentTimeMillis", timeMillis);
|
|||
|
|
|
|||
|
|
if (result)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"Android: 系统时间已设置为 {dateTime:yyyy-MM-dd HH:mm:ss}");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("Android: 设置系统时间失败,可能缺少WRITE_SECURE_SETTINGS权限");
|
|||
|
|
|
|||
|
|
// 尝试使用AlarmManager设置(备用方案)
|
|||
|
|
return SetAndroidTimeViaAlarmManager(currentActivity, dateTime);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"Android直接时间设置失败: {ex.Message}");
|
|||
|
|
return SetAndroidTimeViaAlarmManager(currentActivity, dateTime);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android系统时间设置失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 通过AlarmManager尝试时间设置(限制较多)
|
|||
|
|
/// </summary>
|
|||
|
|
private static bool SetAndroidTimeViaAlarmManager(AndroidJavaObject activity, DateTime dateTime)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
// 注意:从Android 4.2开始,普通应用无法直接修改系统时间
|
|||
|
|
// 这里只能提供用户引导到系统设置页面
|
|||
|
|
|
|||
|
|
Debug.LogWarning("Android: 普通应用无法直接修改系统时间,将引导用户到系统设置");
|
|||
|
|
|
|||
|
|
// 打开系统日期时间设置页面
|
|||
|
|
var intent = new AndroidJavaObject("android.content.Intent");
|
|||
|
|
intent.Call<AndroidJavaObject>("setAction", "android.settings.DATE_SETTINGS");
|
|||
|
|
|
|||
|
|
activity.Call("startActivity", intent);
|
|||
|
|
|
|||
|
|
Debug.Log("Android: 已打开系统日期时间设置页面");
|
|||
|
|
return false; // 返回false表示需要用户手动设置
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"Android时间设置引导失败: {ex.Message}");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 获取Android系统时间
|
|||
|
|
/// </summary>
|
|||
|
|
private static DateTime GetAndroidSystemTime()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var systemClass = new AndroidJavaClass("java.lang.System");
|
|||
|
|
long timeMillis = systemClass.CallStatic<long>("currentTimeMillis");
|
|||
|
|
|
|||
|
|
DateTime dateTime = DateTimeOffset.FromUnixTimeMilliseconds(timeMillis).DateTime;
|
|||
|
|
return dateTime;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"获取Android系统时间失败: {ex.Message}");
|
|||
|
|
return DateTime.Now;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#else
|
|||
|
|
|
|||
|
|
// 其他平台或编辑器模式的模拟实现
|
|||
|
|
public static bool SetSystemVolume(int volumePercent)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[模拟] 音量设置为: {volumePercent}%");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static void SystemVolumeUp()
|
|||
|
|
{
|
|||
|
|
Debug.Log("[模拟] 音量增加");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static void SystemVolumeDown()
|
|||
|
|
{
|
|||
|
|
Debug.Log("[模拟] 音量减少");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static void SystemMute()
|
|||
|
|
{
|
|||
|
|
Debug.Log("[模拟] 静音切换");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool SetMonitorBrightness(int brightnessPercent)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[模拟] 亮度设置为: {brightnessPercent}%");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static int GetCurrentVolume()
|
|||
|
|
{
|
|||
|
|
Debug.Log("[模拟] 获取当前音量");
|
|||
|
|
return 50; // 模拟返回50%
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static int GetCurrentBrightness()
|
|||
|
|
{
|
|||
|
|
Debug.Log("[模拟] 获取当前亮度");
|
|||
|
|
return 70; // 模拟返回70%
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static bool SetSystemTime(DateTime dateTime)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[模拟] 系统时间设置为: {dateTime:yyyy-MM-dd HH:mm:ss}");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public static DateTime GetSystemTime()
|
|||
|
|
{
|
|||
|
|
Debug.Log("[模拟] 获取系统时间");
|
|||
|
|
return DateTime.Now;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endif
|
|||
|
|
}
|