123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- using Microsoft.Win32;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Linq;
- using System.Reflection;
- namespace Optimizer
- {
- public sealed class ColorOverrider
- {
- public static event Action SystemColorsChanging;
- public static event Action SystemColorsChanged;
- private int[] OriginalColors { get; }
- private IReadOnlyDictionary<int, int> KnownOriginalColors;
- private int[] _colorTable;
- private readonly FieldInfo _colorTableField;
- private readonly PropertyInfo _threadDataProperty;
- public ColorOverrider()
- {
- // force init color table
- byte unused = SystemColors.Window.R;
- var systemDrawingAssembly = typeof(Color).Assembly;
- string colorTableField = "colorTable";
- _colorTableField = systemDrawingAssembly.GetType("System.Drawing.KnownColorTable")
- .GetField(colorTableField, BindingFlags.Static | BindingFlags.NonPublic);
- _colorTable = readColorTable();
- SystemEvents.UserPreferenceChanging += userPreferenceChanging;
- OriginalColors = _colorTable.ToArray();
- KnownOriginalColors = KnownColors.Cast<int>()
- .ToDictionary(i => i, i => OriginalColors[i]);
- _threadDataProperty = systemDrawingAssembly.GetType("System.Drawing.SafeNativeMethods")
- .GetNestedType("Gdip", BindingFlags.NonPublic)
- .GetProperty("ThreadData", BindingFlags.Static | BindingFlags.NonPublic);
- string systemBrushesKeyField = "SystemBrushesKey";
- SystemBrushesKey = typeof(SystemBrushes)
- .GetField(systemBrushesKeyField, BindingFlags.Static | BindingFlags.NonPublic)
- ?.GetValue(null);
- SystemPensKey = typeof(SystemPens)
- .GetField("SystemPensKey", BindingFlags.Static | BindingFlags.NonPublic)
- ?.GetValue(null);
- }
- private void userPreferenceChanging(object sender, UserPreferenceChangingEventArgs e)
- {
- if (e.Category != UserPreferenceCategory.Color)
- return;
- _colorTable = readColorTable();
- fireColorsChangedEvents();
- }
- private static void fireColorsChangedEvents()
- {
- SystemColorsChanging?.Invoke();
- SystemColorsChanged?.Invoke();
- }
- private int[] readColorTable() =>
- (int[])_colorTableField.GetValue(null);
- public void SetColor(KnownColor knownColor, int argb)
- {
- setColor(knownColor, argb);
- if (SystemBrushesKey != null)
- ThreadData[SystemBrushesKey] = null;
- if (SystemPensKey != null)
- ThreadData[SystemPensKey] = null;
- fireColorsChangedEvents();
- }
- private void setColor(KnownColor knownColor, int argb) =>
- _colorTable[(int)knownColor] = argb;
- public int GetOriginalColor(KnownColor knownColor) =>
- OriginalColors[(int)knownColor];
- public int GetColor(KnownColor knownColor)
- {
- if (!KnownColors.Contains(knownColor))
- throw new ArgumentException();
- return _colorTable[(int)knownColor];
- }
- public IReadOnlyDictionary<int, int> Save() =>
- KnownColors.Cast<int>()
- .ToDictionary(i => i, i => _colorTable[i]);
- public void Load(IReadOnlyDictionary<int, int> saved)
- {
- foreach (var color in KnownColors)
- {
- int v;
- var value = saved.TryGetValue((int)color, out v);
- setColor(color, v);
- }
- if (SystemBrushesKey != null)
- ThreadData[SystemBrushesKey] = null;
- if (SystemPensKey != null)
- ThreadData[SystemPensKey] = null;
- fireColorsChangedEvents();
- }
- public void Reset(KnownColor color) =>
- SetColor(color, OriginalColors[(int)color]);
- public void ResetAll() =>
- Load(KnownOriginalColors);
- private IDictionary ThreadData =>
- (IDictionary)_threadDataProperty.GetValue(null, null);
- private object SystemBrushesKey { get; }
- private object SystemPensKey { get; }
- public readonly HashSet<KnownColor> KnownColors = new HashSet<KnownColor>(
- new[]
- {
- SystemColors.Control,
- SystemColors.ControlText,
- SystemColors.ButtonFace, // menu gradient
- SystemColors.ButtonShadow, // menu border
- SystemColors.Window,
- SystemColors.WindowText,
- SystemColors.GrayText,
- SystemColors.HotTrack,
- SystemColors.Highlight,
- SystemColors.HighlightText,
- SystemColors.ActiveCaption,
- SystemColors.GradientActiveCaption,
- SystemColors.InactiveCaption,
- SystemColors.GradientInactiveCaption,
- SystemColors.ActiveBorder
- }.Select(_ => _.ToKnownColor())
- );
- }
- }
|