检测深色 windows 任务栏
Detect dark windows taskbar
为了主题化的目的,我希望检测 Windows 任务栏的颜色(在我的例子中,是托盘图标)。
我正在使用 Java,但欢迎任何解决方案,因为我很乐意根据需要转换它们。
- 我的第一次尝试是读取注册表。
- 这对于提供此值的桌面非常有效,但 失败
short当注册表
不提供。
我的第二次尝试是截取任务栏的屏幕截图并尝试猜测它是深色主题还是浅色主题。
这甚至在自动隐藏打开时也有效。不幸的是,无论我做什么,它 returns 都是黑色背景:
WinDef.HWND tray = User32.INSTANCE.FindWindow("Shell_TrayWnd", null);
BufferedImage bi = GDI32Util.getScreenshot(tray);
SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(null, new JLabel((new ImageIcon(bi)))));
假设我不想依赖Windows标志的white/black颜色,有没有办法检测到这一点?
相关:
- How do I get the mode (Light/Dark) of the PC in C#?
- Similar (10 year old) question on MSDN
目前为止,我还没有遇到注册表中缺少SystemUsesLightTheme
和AppsUseLightTheme
的情况
但我认为重新创建键值值得一试。
这是代码示例(C++):
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <Windows.h>
using namespace std;
int main() {
HKEY key;
if (RegOpenKey(HKEY_CURRENT_USER, TEXT("Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"), &key) != ERROR_SUCCESS)
{
cout << "unable to open registry";
}
DWORD value_data = 0;
if (RegSetValueEx(key, TEXT("SystemUsesLightTheme"), 0, REG_DWORD, (const BYTE*)&value_data, sizeof(value_data)) != ERROR_SUCCESS)
{
RegCloseKey(key);
cout << "Unable to set registry value value_name";
}
else
{
cout << "value_name was set" << endl;
}
}
当记录的注册表项丢失时,OS 中的某些内容被编码为回退以下设置:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\
- 如果
AppsUseLightTheme
缺失,假设它是 1
- ...然后根据此值做出 dark/light Windowing 决策。
- 如果
SystemUsesLightTheme
缺失,假设它是 0
- ... 然后根据此值做出 dark/light Taskbar/SystemTray 决策。
荣耀详情...
虽然全新 Windows 主页安装默认为 Light
主题,但这些全新安装程序也正确设置了注册表项,因此缺少注册表项和浅色任务栏的组合极不可能(并且可能是不可能的)。类似地,研究现代 OSs 可能——不正确地——建议默认值来自文件 C:\Windows\resources\Themes\aero.theme
**,但不要被愚弄!较早的 OS 也没有区分条目... 更多内容如下。
直觉会建议 CurrentTheme
或 InstallTheme
注册表值可以作为合理的后备值,但更改这些值似乎是出于历史目的,似乎并没有真正改变light/dark 主题。
reg query HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes /v InstallTheme
>>> returns the path to aero.theme
type %SystemRoot%\resources\Themes\aero.theme |find "SystemMode"
>>> returns SystemMode=dark
即使更改整个机器的 InstallTheme
(HKEY_LOCAL_MACHINE
) 也不会修改这种偏好 SystemMode=dark
的行为(请注意,即使此条目在旧 Windows 10 个版本。例如 Windows 10 v1507 主题文件中也没有此条目。
追逐 aero.theme
也遇到了一些死胡同。尝试直接修改aero.theme
因权限问题失败,但将aero.theme
复制到桌面并将SystemMode=dark
更改为SystemMode=light
然后双击主题文件会使任务栏消失白色,但仅适用于支持浅色主题的较新 Windows 版本。
所以,是的,我必须同意@strive-sun-msft 的观点,SystemUsesLightTheme
注册表项是最佳位置。测试时,甚至任务栏本身也会对此进行监控,将其删除会将其重置为黑色。不幸的是,后备黑色任务栏颜色仍然是个谜。我只能假设它被硬编码到任务栏本身。
此行为的另一种解决方法是,如果缺少注册表项,则通过 运行 再次安装 aero.theme
文件。在较新的 Windows 10 版本中,只需 运行 此文件即可创建缺少的条目。不幸的是,这不适用于较旧的 Windows 10 版本,更糟糕的是,这将重置用户设置的所有自定义首选项。
因此,检测任务栏颜色的侵入性最小的方法是读取注册表,如果缺少密钥,只需假设 Windows10 附带的主题仍然有效:Dark Taskbar, Light Windows.
您可以使用此注册表路径中可用的 Windows 注册表值 SystemUsesLightTheme
:Software\Microsoft\Windows\CurrentVersion\Themes\Personalize
用于检测 dark/light 主题。
我找到了一个名为 JRegistry 的库,它允许您访问
这个值。
RegistryKey windowsPersonalizeKey = new RegistryKey("Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
RegistryValue systemUsesLightThemeValue = windowsPersonalizeKey.getValue("SystemUsesLightTheme");
if (systemUsesLightThemeValue != null) {
//this value is available
//getting the actual value
byte[] data = systemUsesLightThemeValue.getByteData();
byte actualValue = data[0];
boolean windows10Dark = actualValue == 0;
if (windows10Dark) {
//the theme is dark
} else {
// the theme is light
}
}
另外,如果你想动态监听这个值:
RegistryKey registryKey = new RegistryKey("Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
RegistryWatcher.addRegistryListener((RegistryEvent registryEvent) -> {
RegistryKey changedKey = registryEvent.getKey();
if (changedKey.equals(registryKey)) {
RegistryValue value = changedKey.getValue("SystemUsesLightTheme");
//....
}
});
RegistryWatcher.watchKey(registryKey);
为了主题化的目的,我希望检测 Windows 任务栏的颜色(在我的例子中,是托盘图标)。
我正在使用 Java,但欢迎任何解决方案,因为我很乐意根据需要转换它们。
- 我的第一次尝试是读取注册表。
- 这对于提供此值的桌面非常有效,但 失败 short当注册表 不提供。
我的第二次尝试是截取任务栏的屏幕截图并尝试猜测它是深色主题还是浅色主题。
这甚至在自动隐藏打开时也有效。不幸的是,无论我做什么,它 returns 都是黑色背景:
WinDef.HWND tray = User32.INSTANCE.FindWindow("Shell_TrayWnd", null); BufferedImage bi = GDI32Util.getScreenshot(tray); SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(null, new JLabel((new ImageIcon(bi)))));
假设我不想依赖Windows标志的white/black颜色,有没有办法检测到这一点?
相关:
- How do I get the mode (Light/Dark) of the PC in C#?
- Similar (10 year old) question on MSDN
目前为止,我还没有遇到注册表中缺少SystemUsesLightTheme
和AppsUseLightTheme
的情况
但我认为重新创建键值值得一试。
这是代码示例(C++):
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <Windows.h>
using namespace std;
int main() {
HKEY key;
if (RegOpenKey(HKEY_CURRENT_USER, TEXT("Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"), &key) != ERROR_SUCCESS)
{
cout << "unable to open registry";
}
DWORD value_data = 0;
if (RegSetValueEx(key, TEXT("SystemUsesLightTheme"), 0, REG_DWORD, (const BYTE*)&value_data, sizeof(value_data)) != ERROR_SUCCESS)
{
RegCloseKey(key);
cout << "Unable to set registry value value_name";
}
else
{
cout << "value_name was set" << endl;
}
}
当记录的注册表项丢失时,OS 中的某些内容被编码为回退以下设置:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\
- 如果
AppsUseLightTheme
缺失,假设它是1
- ...然后根据此值做出 dark/light Windowing 决策。
- 如果
SystemUsesLightTheme
缺失,假设它是0
- ... 然后根据此值做出 dark/light Taskbar/SystemTray 决策。
荣耀详情...
虽然全新 Windows 主页安装默认为 Light
主题,但这些全新安装程序也正确设置了注册表项,因此缺少注册表项和浅色任务栏的组合极不可能(并且可能是不可能的)。类似地,研究现代 OSs 可能——不正确地——建议默认值来自文件 C:\Windows\resources\Themes\aero.theme
**,但不要被愚弄!较早的 OS 也没有区分条目... 更多内容如下。
直觉会建议 CurrentTheme
或 InstallTheme
注册表值可以作为合理的后备值,但更改这些值似乎是出于历史目的,似乎并没有真正改变light/dark 主题。
reg query HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes /v InstallTheme
>>> returns the path to aero.theme
type %SystemRoot%\resources\Themes\aero.theme |find "SystemMode"
>>> returns SystemMode=dark
即使更改整个机器的 InstallTheme
(HKEY_LOCAL_MACHINE
) 也不会修改这种偏好 SystemMode=dark
的行为(请注意,即使此条目在旧 Windows 10 个版本。例如 Windows 10 v1507 主题文件中也没有此条目。
追逐 aero.theme
也遇到了一些死胡同。尝试直接修改aero.theme
因权限问题失败,但将aero.theme
复制到桌面并将SystemMode=dark
更改为SystemMode=light
然后双击主题文件会使任务栏消失白色,但仅适用于支持浅色主题的较新 Windows 版本。
所以,是的,我必须同意@strive-sun-msft 的观点,SystemUsesLightTheme
注册表项是最佳位置。测试时,甚至任务栏本身也会对此进行监控,将其删除会将其重置为黑色。不幸的是,后备黑色任务栏颜色仍然是个谜。我只能假设它被硬编码到任务栏本身。
此行为的另一种解决方法是,如果缺少注册表项,则通过 运行 再次安装 aero.theme
文件。在较新的 Windows 10 版本中,只需 运行 此文件即可创建缺少的条目。不幸的是,这不适用于较旧的 Windows 10 版本,更糟糕的是,这将重置用户设置的所有自定义首选项。
因此,检测任务栏颜色的侵入性最小的方法是读取注册表,如果缺少密钥,只需假设 Windows10 附带的主题仍然有效:Dark Taskbar, Light Windows.
您可以使用此注册表路径中可用的 Windows 注册表值 SystemUsesLightTheme
:Software\Microsoft\Windows\CurrentVersion\Themes\Personalize
用于检测 dark/light 主题。
我找到了一个名为 JRegistry 的库,它允许您访问 这个值。
RegistryKey windowsPersonalizeKey = new RegistryKey("Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
RegistryValue systemUsesLightThemeValue = windowsPersonalizeKey.getValue("SystemUsesLightTheme");
if (systemUsesLightThemeValue != null) {
//this value is available
//getting the actual value
byte[] data = systemUsesLightThemeValue.getByteData();
byte actualValue = data[0];
boolean windows10Dark = actualValue == 0;
if (windows10Dark) {
//the theme is dark
} else {
// the theme is light
}
}
另外,如果你想动态监听这个值:
RegistryKey registryKey = new RegistryKey("Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
RegistryWatcher.addRegistryListener((RegistryEvent registryEvent) -> {
RegistryKey changedKey = registryEvent.getKey();
if (changedKey.equals(registryKey)) {
RegistryValue value = changedKey.getValue("SystemUsesLightTheme");
//....
}
});
RegistryWatcher.watchKey(registryKey);