Detecting Light/Dark Mode on Windows

  1. 5 weeks ago

    Garry P

    Sep 9 Pre-Release Testers, Xojo Pro Europe (Torquay, UK)

    This is a summary post bringing together information gleaned from this post and this post .

    It turns out that there's a dark mode (of sorts) on Windows that can be found in the _Personalisation_ section of _Settings_. I wanted the app I'm working on to honour dark mode if the user has it enabled on their system and I wanted it to immediately switch modes when the user does so.

    After several hours of messing around I came up with a solution. This solution relies on MonkeyBread Software's MBS Win Plugin , specifically the WinNotificationMBS class. Essentially, I tell a subclass of WinNotificationMBS to listen for a specific message broadcast by Windows (WM_SETTINGCHANGE). This message is broadcast whenever the registry is altered. When my subclass receives this message it fires its GotNotification event. In this event I check the value of a specific registry key (HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize\AppsUseLightTheme). If its value is 0 then Windows is in dark mode, if it's 1 then it's in light mode. I then update my UI accordingly.

    Walkthrough

    1. Subclass WinNotificationMBS. Call it WindowsMessageHandler.
    2. Add a boolean property to the subclass called mDarkMode.
    3. Add an Integer constant to the subclass called WM_SETTINGCHANGE and set it to &h001A
    4. Create the following Constructor for the subclass:
    Public Sub Constructor()
      // Calling the overridden superclass constructor.
      Super.Constructor
      
      // Listen for changes to the system registry.
      Call Me.ListenForMessage(WM_SETTINGCHANGE)
      
      // Determine if Windows is in dark mode or not.
      Try
        Dim reg As New _
        RegistryItem("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", False)
        For i As Integer = 0 To reg.KeyCount - 1
          If reg.Name(i) = "AppsUseLightTheme" Then
            If reg.Value(i) = 0 Then
              mDarkMode = True
            Else
              mDarkMode = False
            End If
          End If
        Next i
      Catch e As RegistryAccessErrorException
        mDarkMode = False
      End Try
    
    End Sub

    5. Add an event definition called AppearanceChanged(darkMode As Boolean) to WindowsMessageHandler. We will fire this whenever the user switches between light and dark mode and we will pass in the mode type.

    6. Add the following code to the WindowsMessageHandler.GotNotification event:

    Select Case Message
    Case WM_SETTINGCHANGE // A system wide setting has been changed. 
      // Has the default app mode changed (light/dark mode)?
      Try
        Dim reg As New _
        RegistryItem("HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize")
        For i As Integer = 0 To reg.KeyCount - 1
          If reg.Name(i) = "AppsUseLightTheme" Then
            // Only update the appearance if the key has changed since the last known state.
            Var currentlyInDarkMode As Boolean = If(reg.Value(i) = 0, True, False)
            If currentlyInDarkMode <> mDarkMode Then
              mDarkMode = currentlyInDarkMode
              // Fire our custom event.
              AppearanceChanged(mDarkMode)
            End If
          End If
        Next i
      End Try
    End Select
    1. Add a new method to the App class called UpdateAppearance(sender As Object, darkMode As boolean). This is where you put the logic to handle light/dark mode changes.
    2. Add an instance of WindowsMessageHandler to your App class. We'll call it WindowsMessages.
    3. In the App.Open event, instantiate our message handler:
    #If TargetWindows
      // Setup our Windows message handler. This will listen for changes to the registry that 
      // will tell us that the user has switched between light and dark mode.
      WindowsMessages = New WindowsMessageHandler
      // Intercept the `AppearanceChanged` event that the message handler fires and direct to our custom method:
      AddHandler WindowsMessages.AppearanceChanged, AddressOf UpdateAppearance
    #EndIf

    Hopefully this will save a few people some time.

or Sign Up to reply!