You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
4.1 KiB
123 lines
4.1 KiB
2 years ago
|
from winreg import HKEY_CURRENT_USER as hkey, QueryValueEx as getSubkeyValue, OpenKey as getKey
|
||
|
|
||
|
import ctypes
|
||
|
import ctypes.wintypes
|
||
|
|
||
|
advapi32 = ctypes.windll.advapi32
|
||
|
|
||
|
# LSTATUS RegOpenKeyExA(
|
||
|
# HKEY hKey,
|
||
|
# LPCSTR lpSubKey,
|
||
|
# DWORD ulOptions,
|
||
|
# REGSAM samDesired,
|
||
|
# PHKEY phkResult
|
||
|
# );
|
||
|
advapi32.RegOpenKeyExA.argtypes = (
|
||
|
ctypes.wintypes.HKEY,
|
||
|
ctypes.wintypes.LPCSTR,
|
||
|
ctypes.wintypes.DWORD,
|
||
|
ctypes.wintypes.DWORD,
|
||
|
ctypes.POINTER(ctypes.wintypes.HKEY),
|
||
|
)
|
||
|
advapi32.RegOpenKeyExA.restype = ctypes.wintypes.LONG
|
||
|
|
||
|
# LSTATUS RegQueryValueExA(
|
||
|
# HKEY hKey,
|
||
|
# LPCSTR lpValueName,
|
||
|
# LPDWORD lpReserved,
|
||
|
# LPDWORD lpType,
|
||
|
# LPBYTE lpData,
|
||
|
# LPDWORD lpcbData
|
||
|
# );
|
||
|
advapi32.RegQueryValueExA.argtypes = (
|
||
|
ctypes.wintypes.HKEY,
|
||
|
ctypes.wintypes.LPCSTR,
|
||
|
ctypes.wintypes.LPDWORD,
|
||
|
ctypes.wintypes.LPDWORD,
|
||
|
ctypes.wintypes.LPBYTE,
|
||
|
ctypes.wintypes.LPDWORD,
|
||
|
)
|
||
|
advapi32.RegQueryValueExA.restype = ctypes.wintypes.LONG
|
||
|
|
||
|
# LSTATUS RegNotifyChangeKeyValue(
|
||
|
# HKEY hKey,
|
||
|
# WINBOOL bWatchSubtree,
|
||
|
# DWORD dwNotifyFilter,
|
||
|
# HANDLE hEvent,
|
||
|
# WINBOOL fAsynchronous
|
||
|
# );
|
||
|
advapi32.RegNotifyChangeKeyValue.argtypes = (
|
||
|
ctypes.wintypes.HKEY,
|
||
|
ctypes.wintypes.BOOL,
|
||
|
ctypes.wintypes.DWORD,
|
||
|
ctypes.wintypes.HANDLE,
|
||
|
ctypes.wintypes.BOOL,
|
||
|
)
|
||
|
advapi32.RegNotifyChangeKeyValue.restype = ctypes.wintypes.LONG
|
||
|
|
||
|
def theme():
|
||
|
""" Uses the Windows Registry to detect if the user is using Dark Mode """
|
||
|
# Registry will return 0 if Windows is in Dark Mode and 1 if Windows is in Light Mode. This dictionary converts that output into the text that the program is expecting.
|
||
|
valueMeaning = {0: "Dark", 1: "Light"}
|
||
|
# In HKEY_CURRENT_USER, get the Personalisation Key.
|
||
|
try:
|
||
|
key = getKey(hkey, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize")
|
||
|
# In the Personalisation Key, get the AppsUseLightTheme subkey. This returns a tuple.
|
||
|
# The first item in the tuple is the result we want (0 or 1 indicating Dark Mode or Light Mode); the other value is the type of subkey e.g. DWORD, QWORD, String, etc.
|
||
|
subkey = getSubkeyValue(key, "AppsUseLightTheme")[0]
|
||
|
except FileNotFoundError:
|
||
|
# some headless Windows instances (e.g. GitHub Actions or Docker images) do not have this key
|
||
|
return None
|
||
|
return valueMeaning[subkey]
|
||
|
|
||
|
def isDark():
|
||
|
if theme() is not None:
|
||
|
return theme() == 'Dark'
|
||
|
|
||
|
def isLight():
|
||
|
if theme() is not None:
|
||
|
return theme() == 'Light'
|
||
|
|
||
|
#def listener(callback: typing.Callable[[str], None]) -> None:
|
||
|
def listener(callback):
|
||
|
hKey = ctypes.wintypes.HKEY()
|
||
|
advapi32.RegOpenKeyExA(
|
||
|
ctypes.wintypes.HKEY(0x80000001), # HKEY_CURRENT_USER
|
||
|
ctypes.wintypes.LPCSTR(b'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize'),
|
||
|
ctypes.wintypes.DWORD(),
|
||
|
ctypes.wintypes.DWORD(0x00020019), # KEY_READ
|
||
|
ctypes.byref(hKey),
|
||
|
)
|
||
|
|
||
|
dwSize = ctypes.wintypes.DWORD(ctypes.sizeof(ctypes.wintypes.DWORD))
|
||
|
queryValueLast = ctypes.wintypes.DWORD()
|
||
|
queryValue = ctypes.wintypes.DWORD()
|
||
|
advapi32.RegQueryValueExA(
|
||
|
hKey,
|
||
|
ctypes.wintypes.LPCSTR(b'AppsUseLightTheme'),
|
||
|
ctypes.wintypes.LPDWORD(),
|
||
|
ctypes.wintypes.LPDWORD(),
|
||
|
ctypes.cast(ctypes.byref(queryValueLast), ctypes.wintypes.LPBYTE),
|
||
|
ctypes.byref(dwSize),
|
||
|
)
|
||
|
|
||
|
while True:
|
||
|
advapi32.RegNotifyChangeKeyValue(
|
||
|
hKey,
|
||
|
ctypes.wintypes.BOOL(True),
|
||
|
ctypes.wintypes.DWORD(0x00000004), # REG_NOTIFY_CHANGE_LAST_SET
|
||
|
ctypes.wintypes.HANDLE(None),
|
||
|
ctypes.wintypes.BOOL(False),
|
||
|
)
|
||
|
advapi32.RegQueryValueExA(
|
||
|
hKey,
|
||
|
ctypes.wintypes.LPCSTR(b'AppsUseLightTheme'),
|
||
|
ctypes.wintypes.LPDWORD(),
|
||
|
ctypes.wintypes.LPDWORD(),
|
||
|
ctypes.cast(ctypes.byref(queryValue), ctypes.wintypes.LPBYTE),
|
||
|
ctypes.byref(dwSize),
|
||
|
)
|
||
|
if queryValueLast.value != queryValue.value:
|
||
|
queryValueLast.value = queryValue.value
|
||
|
callback('Light' if queryValue.value else 'Dark')
|