/*
* Util.ExtendedDisplayIdentificationData.cs
* Authors: Adam Nabinger
* Copyright (c) 2007-2008 Cornell University
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Collections.Generic;
using Microsoft.Win32;
using Microsoft.Xna.Framework.Graphics;
namespace Util
{
///
/// Attempt to pull the device information from the windows registry. This is /very/ hardware dependent and not guaranteed to work.
/// It does, however, work on the development dell laptops.
/// See the DeviceInfo class for more options.
///
public static class ExtendedDisplayIdentificationData
{
#region Fields
// Array for storing all the arrays of information of the various graphics devices
private static readonly byte[][] data;
// Array for storing all the information for the current graphics device
private static byte[] bytes;
#endregion
#region Properties
///
/// Check if there is a profile available to read information from.
///
public static bool HasProfile { get { return bytes != null; } }
///
/// The reported Physical Horizontal Width of the Monitor, in Millimeters.
///
public static int HorizontalSize
{
get
{
#if DEBUG
if (!HasProfile)
{
throw new InvalidOperationException("This is not guaranteed to work. Check if the EDID Has Profile first!");
}
#endif
return getHorizontalSize(bytes);
}
}
///
/// The reported Physical Vertical Height of the Monitor, in Millimeters.
///
public static int VerticalSize
{
get
{
#if DEBUG
if (!HasProfile)
{
throw new InvalidOperationException("This is not guaranteed to work. Check if the EDID Has Profile first!");
}
#endif
return getVerticalSize(bytes);
}
}
///
/// The reported Horizontal Resolution of the Monitor, in Pixels.
///
public static int HorizontalResolution
{
get
{
#if DEBUG
if (!HasProfile)
{
throw new InvalidOperationException("This is not guaranteed to work. Check if the EDID Has Profile first!");
}
#endif
return getHorizontalResolution(bytes);
}
}
///
/// The reported Vertical Resolution of the Monitor, in Pixels.
///
public static int VerticalResolution
{
get
{
#if DEBUG
if (!HasProfile)
{
throw new InvalidOperationException("This is not guaranteed to work. Check if the EDID Has Profile first!");
}
#endif
return getVerticalResolution(bytes);
}
}
#endregion
#region Creation
///
/// Constructor
///
static ExtendedDisplayIdentificationData()
{
List list = new List();
try
{
RegistryKey DisplayKey = Registry.LocalMachine.OpenSubKey("SYSTEM").OpenSubKey("CurrentControlSet").OpenSubKey("Enum").OpenSubKey("DISPLAY");
foreach (string s in DisplayKey.GetSubKeyNames())
{
RegistryKey MonitorKey = DisplayKey.OpenSubKey(s);
foreach (string x in MonitorKey.GetSubKeyNames())
{
list.Add((byte[])MonitorKey.OpenSubKey(x).OpenSubKey("Device Parameters").GetValue("EDID"));
}
}
} catch(NullReferenceException)
{
// Error reading from registry, stop and use what we've got so far.
}
data = list.ToArray();
}
#endregion
#region Getters
///
/// Gets the horizontal resolution of the current graphics device
///
/// The array of information for the current graphics device
/// The horizontal resolution of the current graphics device
private static int getHorizontalResolution(byte[] p_bytes)
{
return ((((240 & (p_bytes[58])) >> 4) << 8) | p_bytes[56]);
}
///
/// Gets the verticle resolution of the current graphics device
///
/// The array of information for the current graphics device
/// The verticle resolution of the current graphics device
private static int getVerticalResolution(byte[] p_bytes)
{
return ((((240 & (p_bytes[61])) >> 4) << 8) | p_bytes[59]);
}
///
/// Gets the horizontal size of the current graphics device
///
/// The array of information for the current graphics device
/// The horizontal size of the current graphics device
private static int getHorizontalSize(byte[] p_bytes)
{
return ((((240 & (p_bytes[68])) >> 4) << 8) | p_bytes[66]);
}
///
/// Gets the verticle size of the current graphics device
///
/// The array of information for the current graphics device
/// The verticle size of the current graphics device
private static int getVerticalSize(byte[] p_bytes)
{
return (((15 & (p_bytes[68])) << 4) | p_bytes[67]);
}
#endregion
#region Setters
///
/// The EDID data may contain multiple devices, such as for example, on a dual-monitor machine.
/// We pick a dataset that matches the known information about the graphics device we're being displayed on.
///
/// The graphics device to set as active
public static void SetActiveDevice(GraphicsDevice device)
{
bytes = null;
foreach (byte[] b in data)
{
if (b == null)
{
continue;
}
if (getHorizontalResolution(b) != device.DisplayMode.Width || getVerticalResolution(b) != device.DisplayMode.Height)
{
continue;
}
#if DEBUG
if (bytes != null)
{
Console.WriteLine("Debug: More than one possible matching display device EDID");
}
#endif
bytes = b;
#if !DEBUG
return;
#endif
}
}
#endregion
}
}