【问题标题】:Detect dark windows taskbar检测暗窗口任务栏
【发布时间】:2020-07-05 08:25:04
【问题描述】:

出于主题目的,我希望检测 Windows 任务栏的颜色(在我的例子中,是托盘图标)。

我正在使用 Java,但欢迎任何解决方案,因为我很乐意根据需要对其进行转换。

  • 我的第一次尝试是读取注册表。
    • 这对于提供此值的桌面非常有效,但falls short 在注册表时 不提供。
  • 我的第二次尝试是截取任务栏的屏幕截图并尝试猜测它是深色主题还是浅色主题。

    • 这甚至在自动隐藏打开时也有效。不幸的是,无论我做什么,它都会返回黑色背景:

        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 徽标的白色/黑色,有没有办法检测到这一点?

相关:

【问题讨论】:

  • 我认为GetSysColor() 会起作用,但这似乎只适用于 Windows 主题,而不适用于新的“暗模式”。看起来您确实可以按需创建一个新的资源管理器窗口并测试其属性,但我将把它留给您进行试验......
  • 不知道是否重现了和你一样的问题,当我将浅色改为深色时,图标会变暗,点击它,会更正。见this
  • @StriveSun-MSFT,您的示例使用的是 Windows 图标。我正在创建自己的。

标签: java winapi jna taskbar


【解决方案1】:

到目前为止,我还没有遇到注册表中缺少SystemUsesLightThemeAppsUseLightTheme的情况。

但我认为重新创建键值是值得尝试的。

这里是代码示例(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;
    }

}

【讨论】:

  • @tresf 你好,这个答案对你有用吗?
  • 一旦选择了深色/自定义/浅色,注册表就会起作用。此错误报告是关于未设置它们的情况(例如在某些 Windows 版本的默认安装之后)。如果您的解决方案是盲目地设置这些值,不,那没有帮助。 :)
  • @tresf 是的,这是我正在尝试做的一部分。如果注册表缺少键值,我们可以尝试创建它们并更改颜色(深色/自定义/浅色)以查看键值是否更改。另外,您介意分享某些 Windows 版本吗?
  • 我相信这不是 Windows 特定的,而是原始 Windows 特定的,因为我们无法在全新安装时重现丢失的密钥。有人会认为这使得这种情况很少见,但相反,我发现它的最新机器数量非常多,所以我只能假设它可以追溯到一个版本信息早已丢失的版本在升级过程中。 github.com/qzind/tray/issues/597
  • @tresf 谢谢分享。当老版本的windows更新到新版本时,比如1903->1909,可能会出现这个问题。我理解正确吗?
【解决方案2】:

当记录的注册表项丢失时,操作系统中的某些内容被编码为回退以下设置

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\

  • 如果缺少AppsUseLightTheme,则假定它是1
    • ...然后根据此值做出暗/亮窗口化决策。
  • 如果缺少SystemUsesLightTheme,则假定为0
    • ... 然后根据 this 值做出暗/亮 Taskbar/SystemTray 决策。

荣耀详情...

尽管全新的 Windows Home 安装默认为 Light 主题,但这些全新的安装程序也正确设置了注册表项,因此缺少注册表项和轻量任务栏的组合极不可能(而且可能是不可能的)。与此类似,研究现代操作系统可能——不正确地——暗示默认值来自文件C:\Windows\resources\Themes\aero.theme**,但不要被愚弄了!较旧的操作系统也没有差异化条目...更多内容如下。

Instinct 会建议 CurrentThemeInstallTheme 注册表值将用作合理的后备值,但更改这些值似乎是出于历史目的,似乎并没有真正改变明暗主题。

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 版本,更糟糕的是,这将重置用户设置的任何自定义首选项。

因此,检测任务栏颜色的最小干扰方法是读取注册表,如果缺少键,只需假设 Windows 10 附带的主题仍然有效:深色任务栏,浅色 Windows。

【讨论】:

    【解决方案3】:

    您可以使用此注册表路径中可用的 Windows 注册表值 SystemUsesLightThemeSoftware\Microsoft\Windows\CurrentVersion\Themes\Personalize 用于检测深色/浅色主题。

    我找到了一个名为 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      • 2017-05-28
      • 2011-10-31
      相关资源
      最近更新 更多