3

Using the following PowerShell code:

$RegConnect = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"CurrentUser", "$env:COMPUTERNAME")
$RegCursors = $RegConnect.OpenSubKey("Control Panel\Desktop", $true)
$myVal = $RegCursors.GetValue("UserPreferencesMask")
write-output $myVal
$RegCursors.Close()
$RegConnect.Close()

It returns:

190
30
7
128
18
1
0
0

From the MS help on UserPreferencesMask, the bit I'm after is the 13th, Cursor shadow.

13 Cursor shadow -- 1 Default

Cursor shadow is enabled. This effect only appears if the system has a color depth of more than 256 colors.

How can I extract the boolean for the current mouse shadow from this?


Here's the values in the on and off state.

on = "UserPreferencesMask"=hex:be,3e,07,80,12,01,00,00

off = "UserPreferencesMask"=hex:be,1e,07,80,12,01,00,00
Community
  • 1
  • 1
Ste
  • 1,729
  • 1
  • 17
  • 27
  • 1
    `[Bool]($myVal -bAnd [math]::pow(2, 13))` – iRon Jan 17 '20 at 19:19
  • Thanks but this returns an error `Object reference not set to an instance of an object.` – Ste Jan 17 '20 at 19:24
  • ([System.Convert]::ToString([System.BitConverter]::ToUint64($myval, 0), 2).PadLeft(64, '0'))[51] --> is converting the Byte[] to a UInt64, then converting the UInt64 to a "binary string" representation, padding 0 to the left in case the Byte[] is lesser than 8192, then getting the (64-13)th char. Should do the trick. – Gzeh Niert Jan 17 '20 at 19:47
  • Unfortunately that doesn't work either, it returns `1` whether or not the shadow is on. I've checked the value of it, in its `on` state and `off` state and I'll update them in the OP if that helps. – Ste Jan 17 '20 at 20:00

2 Answers2

3

It looks like you're adding 32 or 0x20 to the second byte to turn it on:

$myval[1] += 32 # on
$myval[1] -= 32 # off

Bitwise, "or" to set, "and" with "bit complement (not)" to unset.

0x1e -bor 0x20 # on
62

0x3e -band -bnot 0x20 # off
30

Maybe you could make a flags enum for all the settings, but you'd have to convert the byte array to one large int.

EDIT: Oh, if you just want to check that a bit is set:

$shadowbit = 0x20
if (0x3e -band $shadowbit ) { 'yep' } else { 'nope' } # 32
yep

if (0x1e -band $shadowbit ) { 'yep' } else { 'nope' } # 0
nope

See also How do you set, clear, and toggle a single bit?

EDIT:

I went a little overboard. Having this in preperation:

[Flags()] enum UserPreferencesMask {
  ActiveWindowTracking       = 0x1
  MenuAnimation              = 0x2
  ComboBoxAnimation          = 0x4
  ListBoxSmoothScrolling     = 0x8
  GradientCaptions           = 0x10
  KeybordCues                = 0x20
  ActiveWindowTrackingZOrder = 0x40
  HotTracking                = 0x80
  Reserved8                  = 0x100
  MenuFade                   = 0x200
  SelectionFade              = 0x400
  ToolTipAnimation           = 0x800
  ToolTipFade                = 0x1000
  CursorShadow               = 0x2000 # 13
  Reserved14                 = 0x4000
  Reserved15                 = 0x8000
  Reserved16                 = 0x10000
  Reserved17                 = 0x20000
  Reserved18                 = 0x40000
  Reserved19                 = 0x80000
  Reserved20                 = 0x100000
  Reserved21                 = 0x200000
  Reserved22                 = 0x400000
  Reserved23                 = 0x800000
  Reserved24                 = 0x1000000
  Reserved25                 = 0x2000000
  Reserved26                 = 0x4000000
  Reserved27                 = 0x8000000
  Reserved28                 = 0x10000000
  Reserved29                 = 0x20000000
  Reserved30                 = 0x40000000
  UIEffects                  = 0x80000000 # 31
}                

You can do:

$myVal = get-itemproperty 'HKCU:\Control Panel\Desktop' UserPreferencesMask |
  % UserPreferencesMask
$b = [bitconverter]::ToInt32($myVal,0)

'0x{0:x}' -f $b
0x80073e9e

[UserPreferencesMask]$b
MenuAnimation, ComboBoxAnimation, ListBoxSmoothScrolling,
 GradientCaptions, HotTracking, MenuFade, SelectionFade,
 ToolTipAnimation, ToolTipFade, CursorShadow, Reserved16, Reserved17,
 Reserved18, UIEffects

[UserPreferencesMask]$b -band 'CursorShadow'
CursorShadow

if ([UserPreferencesMask]$b -band 'CursorShadow') { 'yes' }
yes

Note that 3 undocumented reserved bits are already in use in my Windows 10. This is with "show shadows under mouse pointer" checked under "performance options" (advanced system) in the control panel

OR, getting simple without the enums:

$b = [bitconverter]::ToInt32($myVal,0)  # 4 bytes from reg_binary to int
if ($b -band [math]::pow(2,13)) { 'cursor shadow' } 

I've noticed that that registry entry is actually 8 bytes long, but bringing in all 8 bytes doesn't change the answer, even if some of those extra bits are set in windows 10.

js2010
  • 23,033
  • 6
  • 64
  • 66
2

To find the specific bit:

You need to calculate the byte index (starting from 0) by dividing the absolute bit index by 8:
[math]::floor(13 / 8) → byte 1 for the absolute bit 13
*Note: as @mklement0 pointed out, you can't use [Int] for this as is doesn't round down, see: division and rounding

Then calculate the relative bit index in that byte by finding the remainder (modulo) of the division:
$BitIndex - 8 * $ByteIndex → 13 - (8 * 1) = 5
*Note: I am not using the arithmetic operator (%) for the modulus due to the modulo operation with negative numbers issue and I used [math]::floor vs [math]::truncate for rounding. This way, the function also supports negative bit indices, with -1 referring to the most significant bit

Then create a byte mask from the relative bit:
[Byte][math]::pow(2, <relative bit>) → 25 = 32 (20h)

And finally mask (-bAnd) the concerned byte:
[Bool]($ByteArray[$ByteIndex] -bAnd $ByteMask) → 62 bAnd 32 = 32 (true), 30 bAnd 32 = 0 (false)

To make this more clear, I have put this in a Test-Bit function:

Function Test-Bit([Int]$BitIndex, [Byte[]]$ByteArray) {
    $ByteIndex = [math]::floor($BitIndex / 8)
    $ByteMask = [Byte][math]::pow(2, ($BitIndex - 8 * $ByteIndex))
    [Bool]($ByteArray[$ByteIndex] -bAnd $ByteMask)
}

*Note: the Test-Bit function is based on little-endian byte order (see: Endianness)

Test:

Test-Bit 13 ([Byte[]](0xbe, 0x3e, 0x07, 0x80, 0x12, 0x01, 0x00, 0x00)) # True
Test-Bit 13 ([Byte[]](0xbe, 0x1e, 0x07, 0x80, 0x12, 0x01, 0x00, 0x00)) # False

Specific to your question:

$RegConnect = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]"CurrentUser", "$env:COMPUTERNAME")
$RegCursors = $RegConnect.OpenSubKey("Control Panel\Desktop", $true)
$MyVal = $RegCursors.GetValue("UserPreferencesMask")
$State = Test-Bit 13 $MyVal
If ($State) {
    # Cursor shadow is enabled
} Else {
    # Cursor shadow is disabled
}
$RegCursors.Close()
$RegConnect.Close()
iRon
  • 20,463
  • 10
  • 53
  • 79