I added this class :
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests
{
class WindowUtility
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
const uint SWP_NOSIZE = 0x0001;
const uint SWP_NOZORDER = 0x0004;
private static Size GetScreenSize() => new Size(GetSystemMetrics(0), GetSystemMetrics(1));
private struct Size
{
public int Width { get; set; }
public int Height { get; set; }
public Size(int width, int height)
{
Width = width;
Height = height;
}
}
[DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
private static extern int GetSystemMetrics(int nIndex);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowRect(HandleRef hWnd, out Rect lpRect);
[StructLayout(LayoutKind.Sequential)]
private struct Rect
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
private static Size GetWindowSize(IntPtr window)
{
if (!GetWindowRect(new HandleRef(null, window), out Rect rect))
throw new Exception("Unable to get window rect!");
int width = rect.Right - rect.Left;
int height = rect.Bottom - rect.Top;
return new Size(width, height);
}
public static void MoveWindowToCenter()
{
IntPtr window = Process.GetCurrentProcess().MainWindowHandle;
if (window == IntPtr.Zero)
throw new Exception("Couldn't find a window to center!");
Size screenSize = GetScreenSize();
Size windowSize = GetWindowSize(window);
int x = (screenSize.Width - windowSize.Width) / 2;
int y = (screenSize.Height - windowSize.Height) / 2;
SetWindowPos(window, IntPtr.Zero, x, y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
}
}
}
Using it in Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Tests
{
class Program
{
static void Main(string[] args)
{
WindowUtility.MoveWindowToCenter();
The problem is that it's showing for a second the window in some random position when running the application and then move it to the screen center.
Is there a way to make that when starting the application the window already will be in the center of the screen ?
I tried to use the accepted answer in this question in the link :
Show/Hide the console window of a C# console application
but then when i'm hiding the window then try to center it then to show it again when it's trying to center it can't find the window because it's hidden so it's throwing this message in the WindowUtility class :
"Couldn't find a window to center!"
I know you have your answer but this is I created for your question.
internal class WindowUtility
{
// P/Invoke declarations.
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);
const int MONITOR_DEFAULTTOPRIMARY = 1;
[DllImport("user32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
[StructLayout(LayoutKind.Sequential)]
struct MONITORINFO
{
public uint cbSize;
public RECT rcMonitor;
public RECT rcWork;
public uint dwFlags;
public static MONITORINFO Default
{
get { var inst = new MONITORINFO(); inst.cbSize = (uint)Marshal.SizeOf(inst); return inst; }
}
}
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left, Top, Right, Bottom;
}
[StructLayout(LayoutKind.Sequential)]
struct POINT
{
public int x, y;
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
const uint SW_RESTORE = 9;
[StructLayout(LayoutKind.Sequential)]
struct WINDOWPLACEMENT
{
public uint Length;
public uint Flags;
public uint ShowCmd;
public POINT MinPosition;
public POINT MaxPosition;
public RECT NormalPosition;
public static WINDOWPLACEMENT Default
{
get
{
var instance = new WINDOWPLACEMENT();
instance.Length = (uint)Marshal.SizeOf(instance);
return instance;
}
}
}
internal enum AnchorWindow
{
None = 0x0,
Top = 0x1,
Bottom = 0x2,
Left = 0x4,
Right = 0x8,
Center = 0x10,
Fill = 0x20
}
internal static void SetConsoleWindowPosition(AnchorWindow position)
{
// Get this console window's hWnd (window handle).
IntPtr hWnd = GetConsoleWindow();
// Get information about the monitor (display) that the window is (mostly) displayed on.
// The .rcWork field contains the monitor's work area, i.e., the usable space excluding
// the taskbar (and "application desktop toolbars" - see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947(v=vs.85).aspx)
var mi = MONITORINFO.Default;
GetMonitorInfo(MonitorFromWindow(hWnd, MONITOR_DEFAULTTOPRIMARY), ref mi);
// Get information about this window's current placement.
var wp = WINDOWPLACEMENT.Default;
GetWindowPlacement(hWnd, ref wp);
// Calculate the window's new position: lower left corner.
// !! Inexplicably, on W10, work-area coordinates (0,0) appear to be (7,7) pixels
// !! away from the true edge of the screen / taskbar.
int fudgeOffset = 7;
int _left = 0, _top = 0;
switch (position)
{
case AnchorWindow.Left|AnchorWindow.Top:
wp.NormalPosition = new RECT()
{
Left = -fudgeOffset,
Top = mi.rcWork.Top,
Right = (wp.NormalPosition.Right - wp.NormalPosition.Left) - fudgeOffset,
Bottom = (wp.NormalPosition.Bottom - wp.NormalPosition.Top)
};
break;
case AnchorWindow.Right| AnchorWindow.Top:
wp.NormalPosition = new RECT()
{
Left = mi.rcWork.Right - wp.NormalPosition.Right + wp.NormalPosition.Left + fudgeOffset,
Top = mi.rcWork.Top,
Right = mi.rcWork.Right + fudgeOffset,
Bottom = (wp.NormalPosition.Bottom - wp.NormalPosition.Top)
};
break;
case AnchorWindow.Left | AnchorWindow.Bottom:
wp.NormalPosition = new RECT()
{
Left = -fudgeOffset,
Top = mi.rcWork.Bottom - (wp.NormalPosition.Bottom - wp.NormalPosition.Top),
Right = (wp.NormalPosition.Right - wp.NormalPosition.Left) - fudgeOffset,
Bottom = fudgeOffset + mi.rcWork.Bottom
};
break;
case AnchorWindow.Right | AnchorWindow.Bottom:
wp.NormalPosition = new RECT()
{
Left = mi.rcWork.Right - wp.NormalPosition.Right + wp.NormalPosition.Left + fudgeOffset,
Top = mi.rcWork.Bottom - (wp.NormalPosition.Bottom - wp.NormalPosition.Top),
Right = mi.rcWork.Right + fudgeOffset,
Bottom = fudgeOffset + mi.rcWork.Bottom
};
break;
case AnchorWindow.Center|AnchorWindow.Top:
_left = mi.rcWork.Right / 2 - (wp.NormalPosition.Right - wp.NormalPosition.Left) / 2;
wp.NormalPosition = new RECT()
{
Left = _left,
Top = mi.rcWork.Top,
Right = mi.rcWork.Right + fudgeOffset - _left,
Bottom = (wp.NormalPosition.Bottom - wp.NormalPosition.Top)
};
break;
case AnchorWindow.Center | AnchorWindow.Bottom:
_left = mi.rcWork.Right / 2 - (wp.NormalPosition.Right - wp.NormalPosition.Left) / 2;
wp.NormalPosition = new RECT()
{
Left = _left,
Top = mi.rcWork.Bottom - (wp.NormalPosition.Bottom - wp.NormalPosition.Top),
Right = mi.rcWork.Right + fudgeOffset - _left,
Bottom = fudgeOffset + mi.rcWork.Bottom
};
break;
case AnchorWindow.Center:
_left = mi.rcWork.Right / 2 - (wp.NormalPosition.Right - wp.NormalPosition.Left) / 2;
_top = mi.rcWork.Bottom / 2 - (wp.NormalPosition.Bottom - wp.NormalPosition.Top) / 2;
wp.NormalPosition = new RECT()
{
Left = _left,
Top = _top,
Right = mi.rcWork.Right + fudgeOffset - _left,
Bottom = mi.rcWork.Bottom + fudgeOffset - _top
};
break;
case AnchorWindow.Fill:
wp.NormalPosition = new RECT()
{
Left = -fudgeOffset,
Top = mi.rcWork.Top,
Right = mi.rcWork.Right + fudgeOffset,
Bottom = mi.rcWork.Bottom + fudgeOffset
};
break;
default:
return;
}
// Place the window at the new position.
SetWindowPlacement(hWnd, ref wp);
}
}
You can use it like this.
WindowUtility.SetConsoleWindowPosition(WindowUtility.AnchorWindow.Left | WindowUtility.AnchorWindow.Top);
// or
WindowUtility.SetConsoleWindowPosition(WindowUtility.AnchorWindow.Center);
// or
WindowUtility.SetConsoleWindowPosition(WindowUtility.AnchorWindow.Fill);
I am attempting to create a custom ListBox control in WinForms.
I have subclassed it, set DrawMode.OwnerDrawFixed, and am overriding OnDrawItem. I have created a custom ColoredListBoxItem class that has additional properties to deal with the highlighting.
This is all fine. My issue is that this functionality needs to highlight words within the text of a list item.
Here is as far as I've gotten, and it doesn't work, because the X coordinate of the highlight remains constant and does not correspond to the actual X coordinate of the text.
How can I get a Point value (or Rectangle) to use with DrawText that will overlay the highlighted text? I've tried doing some math with the bounds of the original text Rectangle versus the highlight Rectangle but it is not working as expected.
protected override void OnDrawItem(DrawItemEventArgs e) {
ColoredListBoxItem item = this.Items[e.Index] as ColoredListBoxItem;
e.DrawBackground();
e.DrawFocusRectangle();
Rectangle fullMessageRect = e.Bounds;
// Draw the original, full text
TextRenderer.DrawText(e.Graphics, item.Message, e.Font,
new Point(fullMessageRect.X, fullMessageRect.Y),
this.ForeColor);
// Check if we have any text to be highlighted
if (SomethingToHighlight(item)) {
// Find the text to highlight, and get its area
SizeF highlightedAreaSize =
e.Graphics.MeasureString(item.TextToHightlight, e.Font);
PointF highlightAreaPoint = highlightedAreaSize.ToPointF();
Point point = new Point(Convert.ToInt32(highlightAreaPoint.X),
Convert.ToInt32(fullMessageRect.Y));
TextRenderer.DrawText(e.Graphics, item.TextToHightlight, e.Font,
point, this.ForeColor, item.HighlightColor);
}
}
Here is what I'm seeing in a demo app, where the output just shows work being done, and I am trying to highlight one particular word .. in this case "height".
Don't pay any attention to the actual output, it's a bunch of nonsense so I can see exactly how another part of the system is adjusting PictureBox images on the fly.
Lines that it thinks should be highlighted are shown twice, once in the original format and then again with the highlight applied. Notice how the highlighted part is correct in the Y coordinate, but does not change in the X.
Here's what I am seeing in the Watch window when I set a break point prior to writing the highlighted text:
Clearly, I don't need the variable highlightAreaPoint, because it's the same as highlightedAreaSize.
Probably something obvious here but I'm tired of fiddling with it at this point!
I can feel your pain as I have been there before. Actually, I wanted to design my own Textbox not inheriting from Microsoft.Textbox control and when I researched on-line, I sort of discouraged to learn 1000 reasons why one must not reinvent the wheel and why it is so difficult to do from scratch. Highlighting selection text was one of the major challenge among the others like right-to-left, caret positioning, non-fixed fonts etc. But I decided to fly against the wind because I had my reasons to do so and finally got what I wanted. Since my text selection code was for TextBox, I had to change it to suit your requirement as you are dealing with ListBox.
Following is the code snippet:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace HowToHighlightPortionOfText
{
public static class Helper
{
private static Rectangle dummy
{
get
{
return new Rectangle(0, 0, 10, 10);
}
}
const uint H = 0x00000000;
const uint V = 0x00000001;
const uint T = 0x00000002;
#region api functions
[DllImport("user32.dll")]
static extern int DrawText(IntPtr hdc, string lpStr, int nCount, ref Dimension lpRect, int wFormat);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(this IntPtr hdc, IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern int DeleteObject(this IntPtr hObject);
[DllImport("gdi32.dll", EntryPoint = "GdiGradientFill", ExactSpelling = true)]
static extern bool GradientFill(IntPtr hdc, Trivertex[] pVertex,
uint dwNumVertex, uint[] pMesh, uint dwNumMesh, uint dwMode);
[DllImport("gdi32")]
public static extern int SetBkMode(this IntPtr hdc, int nBkMode);
[DllImport("gdi32.dll")]
public static extern uint SetTextColor(this IntPtr hdc, int crColor);
[DllImport("gdi32.dll")]
public static extern uint SetBkColor(this IntPtr hdc, int crColor);
#endregion
#region public methods
//use this function to hilight portion of listbox item text
public static void HilightItemText(this ListBox control, int itemIndex, int startIndex, int endIndex,
Color highlightForeColor, Color highlightBackColorStart, Color? highlightBackColorEnd = null)
{
var container = control.GetItemRectangle(itemIndex);
var text = control.GetItemText(itemIndex);
using (Graphics g = control.CreateGraphics())
{
g.HighlightText(control.Font, text, container, startIndex, endIndex,
highlightForeColor, highlightBackColorStart, highlightBackColorEnd);
}
}
public static void HighlightText(this IDeviceContext dc, Font font, string text,
Rectangle container, int start, int end, Color highlightForeColor, Color highlightBackColorStart,
Color? highlightBackColorEnd, DrawTextFlags? flags = null)
{
IntPtr hdc = dc.GetHdc();
IntPtr _font = SelectObject(hdc, font.ToHfont());
Dimension dm = container;
var flag = flags.getMeasureFlag(false);
SetBkMode(hdc, ColorTranslator.ToWin32(Color.Transparent));
//first draw whole text
DrawText(hdc, text, text.Length, ref dm, 0);
//now get the highlight rectangle which will draw the highlighted text
Rectangle textBound, uptoIndex;
var rect = hdc.rangeBound(text, container, start, end, out textBound, out uptoIndex, flags: flags);
dm = rect;
var _backColorEnd = highlightBackColorEnd ?? highlightBackColorStart;
hdc.Fill(rect, highlightBackColorStart, _backColorEnd, Angle.A0);
SetTextColor(hdc, ColorTranslator.ToWin32(highlightForeColor));
if (start < 0 || start > text.Length - 1 || end < 0 || end > text.Length - 1)
throw new Exception("start and end value must be with in text length");
var _text = text.Substring(start, end - start + 1);
DrawText(hdc, _text, _text.Length, ref dm, 0);
DeleteObject(SelectObject(hdc, _font));
dc.ReleaseHdc();
}
public static Rectangle RangeBound(this IDeviceContext dc, Font font, string text,
Rectangle container, int start, int end, DrawTextFlags? flags = null)
{
Rectangle textBound, uptoIndex;
return dc.RangeBound(font, text, container, start, end, out textBound, out uptoIndex, flags);
}
public static Rectangle GetPortionRectangleToHighlight(this ListBox control, int itemIndex, int startIndex, int endIndex)
{
var container = control.GetItemRectangle(itemIndex);
var text = control.GetItemText(itemIndex);
Rectangle rect;
using (Graphics g = control.CreateGraphics())
{
rect = g.RangeBound(control.Font, text, container, startIndex, endIndex);
}
return rect;
}
public static bool Fill(this IntPtr hdc, Rectangle rc, Color c1,
Color c2, Angle angle)
{
return hdc.Fill(rc.X, rc.Y, rc.Right, rc.Bottom, c1, c2, angle);
}
public static bool Fill(this IntPtr hdc, int x0, int y0, int x1, int y1, Color c1, Color c2, Angle angle)
{
Trivertex[] t = new Trivertex[4]
{
new Trivertex(x0, y0, c1),
new Trivertex(x1, y1, c2),
new Trivertex(x0, y1, c1, c2),
new Trivertex(x1, y0, c1, c2)
};
uint[] pMesh = new uint[] { 0, 1, 2, 0, 1, 3 };
switch ((int)angle % 180)
{
case 0:
return GradientFill(hdc, t, 2, pMesh, 1, H);
case 45:
return GradientFill(hdc, t, 4, pMesh, 2, T);
case 90:
return GradientFill(hdc, t, 2, pMesh, 1, V);
case 135:
t[0].x = x1;
t[3].x = x0;
t[1].x = x0;
t[2].x = x1;
return GradientFill(hdc, t, 4, pMesh, 2, T);
default:
return false;
}
}
#endregion
#region get the highlight rectangle
static Rectangle RangeBound(this IDeviceContext dc, Font font, string text,
Rectangle container, int start, int end, out Rectangle textBound, out Rectangle uptoIndex, DrawTextFlags? flags = null)
{
textBound = Rectangle.Empty;
uptoIndex = Rectangle.Empty;
if (string.IsNullOrEmpty(text)) return Rectangle.Empty;
IntPtr hdc = dc.GetHdc();
IntPtr _font = SelectObject(hdc, font.ToHfont());
var rc = hdc.rangeBound(text, container, start, end, out textBound, out uptoIndex, flags: flags);
DeleteObject(SelectObject(hdc, _font));
dc.ReleaseHdc();
return rc;
}
static TextMeasurement charRectangle(this IntPtr hdc, string text, Rectangle container,
string wholeText = null, Point? point = null, bool adjustByPoint = false, DrawTextFlags? flags = null)
{
if (string.IsNullOrEmpty(text)) return TextMeasurement.Default;
TextMeasurement measurement = new TextMeasurement();
Rectangle textBound;
wholeText = (wholeText ?? text);
var location = container.Location;
var measureWholeText = point == null;
measurement.UserPoint = point ?? Point.Empty;
textBound = hdc.textBound(wholeText, container, flags: flags);
var rect = textBound;
var p = point ?? new Point(container.Right, container.Y);
if (!measureWholeText)
{
if (p.X > textBound.Right)
p.X = textBound.Right;
else if (p.X < textBound.Left)
p.X = textBound.X;
}
var charIndex = 0;
var result = hdc.charRectangle(text, ref p, rect, flags, measureWholeText);
charIndex = Math.Max(0, result.Item2);
var rectangles = result.Item1;
measurement.Bounds = rectangles[0];
measurement.TextBounds = (measureWholeText) ? rectangles[1] : textBound;
rectangles[1] = measurement.TextBounds;
if (!measureWholeText && adjustByPoint && charIndex > 0)
{
float middle = (float)measurement.Bounds.Left +
measurement.Bounds.Width / 2;
if (p.X > middle - 1)
{
Rectangle r;
Dimension r1 = measurement.TextBounds;
var newresult = hdc.charBound(text, charIndex + 2, ref r1,
(int)flags.getMeasureFlag(false), out r);
if (!newresult.Equals(measurement.Bounds) &&
newresult.X > measurement.Bounds.X)
{
charIndex++;
measurement.Bounds = newresult;
}
}
}
if (measurement.Bounds.Size.Width<=0)
measurement.Bounds = new Rectangle(measurement.Bounds.Location, new Size(2, 2));
measurement.CharIndex = charIndex;
measurement.Char = '\0';
measurement.Char = text[Math.Min(charIndex, text.Length - 1)];
return measurement;
}
static Tuple<Rectangle[], int> charRectangle(this IntPtr hdc, string text, ref Point p, Rectangle rect,
DrawTextFlags? flags, bool measureWholeText = false)
{
int i = 0;
int middle = text.Length / 2, start = 0;
bool first = true;
do
{
var upto = hdc.Measure(text.Substring(0, middle), null, rect, flags);
bool found = upto.Has(p);
if (!found)
{
start = middle;
middle += (text.Length - middle) / 2;
first = false;
if (start == middle) break;
}
else break;
} while (middle > 1 && text.Length - middle > 1);
if (first)
{
return hdc.charRectangle(text.Substring(0, middle),
ref p, rect, flags);
}
else
{
Rectangle[] list = new Rectangle[2];
for (i = start; i <= middle; i++)
{
if (hdc.Measure(text, out list, p, i + 1, rect, flags))
break;
}
i = Math.Max(i, 0);
return new Tuple<Rectangle[], int>(list, i);
}
}
static Rectangle charBound(this IntPtr hdc, string text, int len,
ref Dimension bounds, int flag, out Rectangle whole)
{
DrawText(hdc, text, len, ref bounds, flag);
whole = bounds;
var rc = bounds;
if (len - 1 > 0 && len <= text.Length)
{
DrawText(hdc, text.Substring(0, len - 1), len - 1, ref rc, flag);
rc = Rectangle.FromLTRB(rc.Right, bounds.Top, bounds.Right, bounds.Bottom);
}
return rc;
}
static Rectangle rangeBound(this IntPtr hdc, string text, Rectangle container, int start, int end,
out Rectangle textBound, out Rectangle uptoIndex, DrawTextFlags? flags = null)
{
textBound = Rectangle.Empty;
uptoIndex = Rectangle.Empty;
if (string.IsNullOrEmpty(text)) return Rectangle.Empty;
var location = container.Location;
textBound = hdc.textBound(text, container, flags);
Dimension rect = textBound;
var flag = flags.getMeasureFlag(false);
start++;
var text1 = text.Substring(0, start);
var rc = hdc.charBound(text1, text1.Length, ref rect, (int)flag, out uptoIndex);
end++;
var text2 = text.Substring(0, end);
DrawText(hdc, text2, text2.Length, ref rect, (int)flag);
return Rectangle.FromLTRB(rc.Left, rect.Top, rect.Right, rect.Bottom);
}
static Rectangle textBound(this IntPtr hdc, string text, Rectangle container, DrawTextFlags? flags = null)
{
Rectangle rc = Rectangle.Empty;
if (string.IsNullOrEmpty(text)) return rc;
Point p = container.Location;
var r = hdc.Measure(text, text.Length, flags: flags);
return new Rectangle(p, r.Size);
}
static DrawTextFlags getMeasureFlag(this DrawTextFlags? flags, bool textboxControl = false)
{
DrawTextFlags flag = DrawTextFlags.CalculateArea;
if (flags != null) flag |= flags.Value;
flag |= DrawTextFlags.WordBreak | DrawTextFlags.NoPrefix
| DrawTextFlags.NoPadding | DrawTextFlags.NoClipping;
if (textboxControl) flag |= DrawTextFlags.TextBoxControl;
else flag |= DrawTextFlags.SingleLine;
return flag;
}
static Rectangle RangeBound(this IntPtr hdc, string text,
Rectangle container, int start, int end, DrawTextFlags? flags = null)
{
Rectangle textBound, uptoIndex;
return hdc.rangeBound(text, container, start, end, out textBound, out uptoIndex, flags);
}
static Rectangle Measure(this IntPtr hdc, string text, int? length = null,
Rectangle? rect = null, DrawTextFlags? flags = null)
{
if (string.IsNullOrEmpty(text)) return Rectangle.Empty;
Dimension bounds = rect ?? dummy;
var len = length ?? text.Length;
var flag = flags.getMeasureFlag(false);
var i = DrawText(hdc, text, len, ref bounds, (int)flag);
return bounds;
}
static bool Measure(this IntPtr hdc, string text, out Rectangle[] rectangles, Point p,
int? length = null, Rectangle? rect = null, DrawTextFlags? flags = null)
{
rectangles = new Rectangle[2];
if (string.IsNullOrEmpty(text)) return true;
Dimension bounds = rect ?? dummy;
var len = length ?? text.Length;
var flag = flags.getMeasureFlag(false);
Rectangle rc, rc1;
rc1 = hdc.charBound(text, len, ref bounds, (int)flag, out rc);
rectangles = new Rectangle[] { rc1, rc };
return (rectangles[0].Left < bounds.Left || rectangles[0].Has(p.X));
}
static bool Has(this Rectangle rect, int x = -1,
int y = -1, int checkRightUpto = -1, int checkBottomUpto = -1)
{
if (x == -1 && y == -1)
{
x = 0;
y = 0;
}
else
{
x = x == -1 ? rect.X : x;
y = y == -1 ? rect.Y : y;
}
if (checkRightUpto == -1)
{
checkRightUpto = rect.Width;
}
if (checkBottomUpto == -1)
{
checkBottomUpto = rect.Height;
}
return x >= rect.Left && x <= rect.Left +
checkRightUpto && y >= rect.Top &&
y <= rect.Top + checkBottomUpto;
}
static bool Has(this Rectangle rect, Point p,
int checkRightUpto = -1, int checkBottomUpto = -1)
{
return rect.Has(p.X, p.Y, checkRightUpto, checkBottomUpto);
}
#endregion
}
#region structs
[StructLayout(LayoutKind.Sequential)]
public struct Dimension
{
public int Left, Top, Right, Bottom;
public Dimension(int left, int top, int right, int bottom)
{
this.Left = left;
this.Right = right;
this.Top = top;
this.Bottom = bottom;
}
public Dimension(Rectangle r)
{
this.Left = r.Left;
this.Top = r.Top;
this.Bottom = r.Bottom;
this.Right = r.Right;
}
public static implicit operator Rectangle(Dimension rc)
{
return Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom);
}
public static implicit operator Dimension(Rectangle rc)
{
return new Dimension(rc);
}
public static Dimension Default
{
get { return new Dimension(0, 0, 1, 1); }
}
}
[StructLayout(LayoutKind.Sequential)]
public struct Trivertex
{
public int x;
public int y;
public ushort Red;
public ushort Green;
public ushort Blue;
public ushort Alpha;
public Trivertex(int x, int y, Color color)
: this(x, y, color.R, color.G, color.B, color.A)
{
}
public Trivertex(int x, int y, Color color, Color other)
: this(x, y, color.R, color.G, color.B, color.A, other)
{
}
public Trivertex(int x, int y, ushort red, ushort green, ushort blue, ushort alpha)
{
this.x = x;
this.y = y;
Red = (ushort)(red << 8);
Green = (ushort)(green << 8);
Blue = (ushort)(blue << 8);
Alpha = (ushort)(alpha << 8);
}
public Trivertex(int x, int y, ushort red, ushort green, ushort blue, ushort alpha, Color other)
{
this.x = x;
this.y = y;
Red = (ushort)((red + other.R / 2) << 8);
Green = (ushort)((green + other.G / 2) << 8);
Blue = (ushort)((blue + other.B / 2) << 8);
Alpha = (ushort)((alpha + other.A / 2) << 8);
}
public static ushort R(Color c)
{
return (ushort)(c.R << 8);
}
public static ushort G(Color c)
{
return (ushort)(c.G << 8);
}
public static ushort B(Color c)
{
return (ushort)(c.B << 8);
}
public static ushort R(Color c, Color c1)
{
return (ushort)(((c.R + c1.R / 2)) << 8);
}
public static ushort G(Color c, Color c1)
{
return (ushort)(((c.G + c1.G / 2)) << 8);
}
public static ushort B(Color c, Color c1)
{
return (ushort)(((c.B + c1.B / 2)) << 8);
}
}
#endregion
#region textmeasurement interface + class
public interface ITextMeasurement : ICloneable
{
int CharIndex { get; set; }
int PreviousIndex { get; }
Rectangle Bounds { get; }
Rectangle TextBounds { get; }
char Char { get; }
Point UserPoint { get; }
void CopyFrom(ITextMeasurement other);
}
public class TextMeasurement : ITextMeasurement
{
Rectangle now, textBound;
public virtual Rectangle Bounds
{
get
{
return now;
}
set { now = value; }
}
public virtual Rectangle TextBounds
{
get
{
return textBound; ;
}
set { textBound = value; }
}
public virtual int CharIndex { get; set; }
public virtual int PreviousIndex { get; set; }
public virtual char Char { get; set; }
public Point UserPoint { get; set; }
public virtual void CopyFrom(ITextMeasurement tm)
{
PreviousIndex = tm.PreviousIndex;
CharIndex = tm.CharIndex;
Bounds = tm.Bounds;
Char = tm.Char;
TextBounds = tm.TextBounds;
UserPoint = tm.UserPoint;
if (UserPoint.IsEmpty) UserPoint = Bounds.Location;
}
public virtual object Clone()
{
var tm = new TextMeasurement();
tm.CopyFrom(this);
return tm;
}
protected virtual void ResetBounds(Point p)
{
ResetBounds(p.X, p.Y);
}
protected virtual void ResetBounds(int? lineX = null, int? lineY = null)
{
if (lineX.HasValue)
{
now.X = lineX.Value;
textBound.X = lineX.Value;
}
if (lineY.HasValue)
{
now.Y = lineY.Value;
textBound.Y = lineY.Value;
}
}
protected virtual void ResetEmptyBounds(Rectangle rc)
{
now = rc;
textBound = rc;
}
public static TextMeasurement Default
{
get { return new TextMeasurement(); }
}
}
#endregion
#region enums
public enum DrawTextFlags
{
CalculateArea = 0x00000400,
WordBreak = 0x00000010,
TextBoxControl = 0x00002000,
Top = 0x00000000,
Left = 0x00000000,
HorizontalCenter = 0x00000001,
Right = 0x00000002,
VerticalCenter = 0x00000004,
Bottom = 0x00000008,
SingleLine = 0x00000020,
ExpandTabs = 0x00000040,
TabStop = 0x00000080,
NoClipping = 0x00000100,
ExternalLeading = 0x00000200,
NoPrefix = 0x00000800,
Internal = 0x00001000,
PathEllipsis = 0x00004000,
EndEllipsis = 0x00008000,
WordEllipsis = 0x00040000,
ModifyString = 0x00010000,
RightToLeft = 0x00020000,
NoFullWidthCharacterBreak = 0x00080000,
HidePrefix = 0x00100000,
PrefixOnly = 0x00200000,
NoPadding = 0x10000000,
}
public enum Angle
{
A0 = 0,
A45 = 45,
A90 = 90,
A135 = 135,
A180 = 180
}
#endregion
}
Suppose your ItemText at index 2 is "StackOverFlow is a wonderful site" and you want to highlight "StackOverFlow" then your startIndex =0 and endIndex = 12.
To highlight portion of text use HighlightItemText method:
listBox.HilightItemText(2, 0, 12, Color.Black, Color.Gold, Color.Yellow);
To get highlighted coordinates use GetPortionRectangleToHighlight method to get co-ordinates of text portion to highlight. Please note that you just need to pass start and end index as well of portion text.
so call the function like:
var portionRectangle = listBox1.GetPortionRectangleToHighlight (2, 0, 12);
Have a look at the attached image as working proof of concept.
A simple example would be something like this:
private string[] _sentences = {
"Old height on pictureOne: 766",
"New height on pictureOne: 900",
"",
"Forcing width on objectX"
};
private void Form1Paint(object sender, PaintEventArgs e) {
int y = 10; //Start position
int x;
foreach (string s in _sentences) {
x = 0; //Start position
foreach (string word in s.Split(' ')) {
if (ShouldHeighlightWord(word)) {
e.Graphics.DrawString(word + " ", this.Font, new SolidBrush(Color.Red), x, y);
}
else {
e.Graphics.DrawString(word + " ", this.Font, new SolidBrush(Color.Black), x, y);
}
x += (int)e.Graphics.MeasureString(word + " ", this.Font).Width;
}
y += (int)Math.Ceiling(e.Graphics.MeasureString("I", this.Font).Height);
}
}
private bool ShouldHeighlightWord(string word) {
switch (word) {
case "on":
case "Old":
return true;
default:
return false;
}
}
This code is just drawing the strings onto an empty form and instead of highlighting it just changes the color to Red.
But i think you understand what i mean.
Since i dont have more code its hard to make a better example for you.
When you check:
if (SomethingToHighlight(item)) {
That only returns true/false i guess and you need something that returns all words to be highlighted, but since a word can occur twice (or more) in one sentence you need to be able to get a position in the string as well. Or just take one word at a time and check if it should be highlighted or not and then draw it to the control.
I used a custom control which is created by other posts. I tried to modify it to fit my requirements but I'm stuck in those areas which we cannot edit it.
This is my Modified Control Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace CControls
{
public partial class TapControl : TabControl
{
#region "Properties"
private int _hotTabIndex = -1;
private int HotTabIndex
{
get { return _hotTabIndex; }
set
{
if (_hotTabIndex != value)
{
_hotTabIndex = value;
this.Invalidate();
}
}
}
private int CloseButtonHeight
{
get { return FontHeight; }
}
#endregion
public TapControl()
{
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
this.DrawMode = TabDrawMode.OwnerDrawFixed;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawLine(Pens.White, 0, 0, ClientRectangle.Right,ClientRectangle.Top);
e.Graphics.DrawLine(Pens.Red, 0, ItemSize.Height+2, ClientRectangle.Right-1, ItemSize.Height+2);
base.OnPaint(e);
for (int id = 0; id < this.TabCount; id++)
DrawTabContent(e.Graphics, id);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
base.OnPaintBackground(pevent);
for (int id = 0; id < this.TabCount; id++)
DrawTabBackground(pevent.Graphics, id);
}
protected override void OnCreateControl()
{
base.OnCreateControl();
this.OnFontChanged(EventArgs.Empty);
}
protected override void OnFontChanged(EventArgs e)
{
base.OnFontChanged(e);
IntPtr hFont = this.Font.ToHfont();
SendMessage(this.Handle, WM_SETFONT, hFont, new IntPtr(-1));
SendMessage(this.Handle, WM_FONTCHANGE, IntPtr.Zero, IntPtr.Zero);
this.UpdateStyles();
}
private void DrawTabContent(Graphics graphics, int id)
{
bool selectedOrHot = id == this.SelectedIndex || id == this.HotTabIndex;
bool vertical = this.Alignment >= TabAlignment.Left;
Image tabImage = null;
if (this.ImageList != null)
{
TabPage page = this.TabPages[id];
if (page.ImageIndex > -1 && page.ImageIndex < this.ImageList.Images.Count)
tabImage = this.ImageList.Images[page.ImageIndex];
if (page.ImageKey.Length > 0 && this.ImageList.Images.ContainsKey(page.ImageKey))
tabImage = this.ImageList.Images[page.ImageKey];
}
Rectangle tabRect = GetTabRect(id);
Rectangle contentRect = vertical ? new Rectangle(0, 0, tabRect.Height, tabRect.Width) : new Rectangle(Point.Empty, tabRect.Size);
contentRect = new Rectangle(ClientRectangle.X, ClientRectangle.Y, ItemSize.Width, ItemSize.Height);
Rectangle textrect = contentRect;
textrect.Width -= FontHeight;
if (tabImage != null)
{
textrect.Width -= tabImage.Width;
textrect.X += tabImage.Width;
}
Color frColor = id == SelectedIndex ? Color.Black : this.ForeColor;
Color bkColor = id == SelectedIndex ? Color.White : FindForm().BackColor;
using (Bitmap bm = new Bitmap(contentRect.Width, contentRect.Height))
{
using (Graphics bmGraphics = Graphics.FromImage(bm))
{
TextRenderer.DrawText(bmGraphics, this.TabPages[id].Text, this.Font, textrect, frColor, bkColor);
//if (selectedOrHot)
//{
Rectangle closeRect = new Rectangle(contentRect.Right - CloseButtonHeight, 0, CloseButtonHeight, CloseButtonHeight);
closeRect.Offset(-2, (contentRect.Height - closeRect.Height) / 2);
DrawCloseButton(bmGraphics, closeRect);
//}
if (tabImage != null)
{
Rectangle imageRect = new Rectangle(Padding.X, 0, tabImage.Width, tabImage.Height);
imageRect.Offset(0, (contentRect.Height - imageRect.Height) / 2);
bmGraphics.DrawImage(tabImage, imageRect);
}
}
if (vertical)
{
if (this.Alignment == TabAlignment.Left)
bm.RotateFlip(RotateFlipType.Rotate270FlipNone);
else
bm.RotateFlip(RotateFlipType.Rotate90FlipNone);
}
graphics.DrawImage(bm, tabRect);
}
}
private void DrawCloseButton(Graphics graphics, Rectangle bounds)
{
using (Font closeFont = new Font("Tahoma", Font.Size, FontStyle.Bold))
TextRenderer.DrawText(graphics, "x", closeFont, bounds, Color.Gray, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.NoPadding | TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
}
private void DrawTabBackground(Graphics graphics, int id)
{
if (id == SelectedIndex)
graphics.FillRectangle(Brushes.White, GetTabRect(id));
else if (id == HotTabIndex)
{
Rectangle rc = GetTabRect(id);
rc.Width--;
rc.Height--;
graphics.DrawRectangle(Pens.DarkGray, rc);
}
}
private const int TCM_ADJUSTRECT = 0x1328;//(TCM_FIRST + 40);
protected override void WndProc(ref Message m)
{
if (m.Msg == TCM_SETPADDING)
{
m.LParam = MAKELPARAM(this.Padding.X + CloseButtonHeight / 2, this.Padding.Y);
}
if (m.Msg == WM_MOUSEDOWN && !this.DesignMode)
{
Point pt = this.PointToClient(Cursor.Position);
Rectangle closeRect = GetCloseButtonRect(HotTabIndex);
if (closeRect.Contains(pt) && HotTabIndex != 0)
{
TabPages.RemoveAt(HotTabIndex);
m.Msg = WM_NULL;
}
}
if (m.Msg == TCM_ADJUSTRECT && !this.DesignMode)
{
RECT rc = new RECT();
rc.Left -= 3;
rc.Right += 1;
rc.Top -= 1;
rc.Bottom += 1;
Marshal.StructureToPtr(rc, m.LParam, true);
}
base.WndProc(ref m);
}
private struct RECT{
public int Left, Top, Right, Bottom;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
TCHITTESTINFO HTI = new TCHITTESTINFO(e.X, e.Y);
HotTabIndex = SendMessage(this.Handle, TCM_HITTEST, IntPtr.Zero, ref HTI);
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
HotTabIndex = -1;
}
private IntPtr MAKELPARAM(int lo, int hi)
{
return new IntPtr((hi << 16) | (lo & 0xFFFF));
}
private Rectangle GetCloseButtonRect(int id)
{
Rectangle tabRect = GetTabRect(id);
Rectangle closeRect = new Rectangle(tabRect.Left, tabRect.Top, CloseButtonHeight, CloseButtonHeight);
switch (Alignment)
{
case TabAlignment.Left:
closeRect.Offset((tabRect.Width - closeRect.Width) / 2, 0);
break;
case TabAlignment.Right:
closeRect.Offset((tabRect.Width - closeRect.Width) / 2, tabRect.Height - closeRect.Height);
break;
default:
closeRect.Offset(tabRect.Width - closeRect.Width, (tabRect.Height - closeRect.Height) / 2);
break;
}
return closeRect;
}
#region Interop
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hwnd, int msg, IntPtr wParam, ref TCHITTESTINFO lParam);
[StructLayout(LayoutKind.Sequential)]
private struct TCHITTESTINFO
{
public Point pt;
public TCHITTESTFLAGS flags;
public TCHITTESTINFO(int x, int y)
{
pt = new Point(x, y);
flags = TCHITTESTFLAGS.TCHT_NOWHERE;
}
}
[Flags()]
private enum TCHITTESTFLAGS
{
TCHT_NOWHERE = 1,
TCHT_ONITEMICON = 2,
TCHT_ONITEMLABEL = 4,
TCHT_ONITEM = TCHT_ONITEMICON | TCHT_ONITEMLABEL
}
private const int WM_NULL = 0x0;
private const int WM_SETFONT = 0x30;
private const int WM_FONTCHANGE = 0x1D;
private const int WM_MOUSEDOWN = 0x201;
private const int TCM_FIRST = 0x1300;
private const int TCM_HITTEST = TCM_FIRST + 13;
private const int TCM_SETPADDING = TCM_FIRST + 43;
#endregion
}
}
and in the Below Picture, the result and required modifications
I am working with Wiimote API and I came across this code,
float[] srcX = new float[4];
float[] srcY = new float[4];
float[] dstX = new float[4];
float[] dstY = new float[4];
I am unable to understand why would there be an array of 4 floats to represent a single point. Please guide. Thanks.
Here is the whole code,
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;//for firing keyboard and mouse events (optional)
using System.IO;//for saving the reading the calibration data
using WiimoteLib;
namespace WiimoteWhiteboard
{
public partial class Form1 : Form
{
//instance of the wii remote
Wiimote wm = new Wiimote();
const int smoothingBufferSize = 50;
PointF[] smoothingBuffer = new PointF[smoothingBufferSize];
int smoothingBufferIndex = 0;
int smoothingAmount = 4;
bool enableSmoothing = true;
bool cursorControl = false;
int screenWidth = 1024;//defaults, gets replaced by actual screen size
int screenHeight = 768;
int calibrationState = 0;
float calibrationMargin = .1f;
CalibrationForm cf = null;
Warper warper = new Warper();
float[] srcX = new float[4];
float[] srcY = new float[4];
float[] dstX = new float[4];
float[] dstY = new float[4];
//declare consts for mouse messages
public const int INPUT_MOUSE = 0;
public const int INPUT_KEYBOARD = 1;
public const int INPUT_HARDWARE = 2;
public const int MOUSEEVENTF_MOVE = 0x01;
public const int MOUSEEVENTF_LEFTDOWN = 0x02;
public const int MOUSEEVENTF_LEFTUP = 0x04;
public const int MOUSEEVENTF_RIGHTDOWN = 0x08;
public const int MOUSEEVENTF_RIGHTUP = 0x10;
public const int MOUSEEVENTF_MIDDLEDOWN = 0x20;
public const int MOUSEEVENTF_MIDDLEUP = 0x40;
public const int MOUSEEVENTF_ABSOLUTE = 0x8000;
//declare consts for key scan codes
public const byte VK_TAB = 0x09;
public const byte VK_MENU = 0x12; // VK_MENU is Microsoft talk for the ALT key
public const byte VK_SPACE = 0x20;
public const byte VK_RETURN = 0x0D;
public const byte VK_LEFT =0x25;
public const byte VK_UP =0x26;
public const byte VK_RIGHT =0x27;
public const byte VK_DOWN =0x28;
public const int KEYEVENTF_EXTENDEDKEY = 0x01;
public const int KEYEVENTF_KEYUP = 0x02;
//for firing mouse and keyboard events
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;//4
public int dy;//4
public uint mouseData;//4
public uint dwFlags;//4
public uint time;//4
public IntPtr dwExtraInfo;//4
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort wVk;//2
public ushort wScan;//2
public uint dwFlags;//4
public uint time;//4
public IntPtr dwExtraInfo;//4
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
[StructLayout(LayoutKind.Explicit, Size = 28)]
public struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)] //*
public MOUSEINPUT mi;
[FieldOffset(4)] //*
public KEYBDINPUT ki;
[FieldOffset(4)] //*
public HARDWAREINPUT hi;
}
//imports mouse_event function from user32.dll
[DllImport("user32.dll")]
private static extern void mouse_event(
long dwFlags, // motion and click options
long dx, // horizontal position or change
long dy, // vertical position or change
long dwData, // wheel movement
long dwExtraInfo // application-defined information
);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetCursorPos(int X, int Y);
//imports keybd_event function from user32.dll
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void keybd_event(byte bVk, byte bScan, long dwFlags, long dwExtraInfo);
WiimoteState lastWiiState = new WiimoteState();//helps with event firing
//end keyboard and mouse input emulation variables----------------------------------------
Mutex mut = new Mutex();
public Form1()
{
screenWidth = Screen.GetBounds(this).Width;
screenHeight = Screen.GetBounds(this).Height;
InitializeComponent();
for (int i = 0; i < smoothingBufferSize; i++)
smoothingBuffer[i] = new PointF();
setSmoothing(smoothingAmount);
}
private void Form1_Load(object sender, EventArgs e)
{
//add event listeners to changes in the wiiremote
//fired for every input report - usually 100 times per second if acclerometer is enabled
wm.WiimoteChanged += new WiimoteChangedEventHandler(wm_OnWiimoteChanged);
//fired when the extension is attached on unplugged
wm.WiimoteExtensionChanged += new WiimoteExtensionChangedEventHandler(wm_OnWiimoteExtensionChanged);
try
{
//connect to wii remote
wm.Connect();
//set what features you want to enable for the remote, look at Wiimote.InputReport for options
wm.SetReportType(Wiimote.InputReport.IRAccel, true);
//set wiiremote LEDs with this enumerated ID
wm.SetLEDs(true, false, false, false);
}
catch (Exception x)
{
MessageBox.Show("Exception: " + x.Message);
this.Close();
}
loadCalibrationData();
}
void wm_OnWiimoteExtensionChanged(object sender, WiimoteExtensionChangedEventArgs args)
{
//if extension attached, enable it
if(args.Inserted)
wm.SetReportType(Wiimote.InputReport.IRExtensionAccel, true);
else
wm.SetReportType(Wiimote.InputReport.IRAccel, true);
}
float UpdateTrackingUtilization()
{
//area of ideal calibration coordinates (to match the screen)
float idealArea = (1 - 2*calibrationMargin) * 1024 * (1 - 2*calibrationMargin) * 768;
//area of quadrliatera
float actualArea = 0.5f * Math.Abs((srcX[1] - srcX[2]) * (srcY[0] - srcY[3]) - (srcX[0] - srcX[3]) * (srcY[1] - srcY[2]));
float util = (actualArea / idealArea)*100;
BeginInvoke((MethodInvoker)delegate() { lblTrackingUtil.Text = util.ToString("f0"); });
BeginInvoke((MethodInvoker)delegate() { pbTrackingUtil.Value = (int)util; });
return util;
}
PointF getSmoothedCursor(int amount)
{
int start = smoothingBufferIndex - amount;
if (start < 0)
start = 0;
PointF smoothed = new PointF(0,0);
int count = smoothingBufferIndex - start;
for (int i = start; i < smoothingBufferIndex; i++)
{
smoothed.X += smoothingBuffer[i%smoothingBufferSize].X;
smoothed.Y += smoothingBuffer[i % smoothingBufferSize].Y;
}
smoothed.X /= count;
smoothed.Y /= count;
return smoothed;
}
void wm_OnWiimoteChanged(object sender, WiimoteChangedEventArgs args)
{
mut.WaitOne();
//extract the wiimote state
WiimoteState ws = args.WiimoteState;
if (ws.IRState.Found1)
{
int x = ws.IRState.RawX1;
int y = ws.IRState.RawY1;
float warpedX = x;
float warpedY = y;
warper.warp(x, y, ref warpedX, ref warpedY);
smoothingBuffer[smoothingBufferIndex % smoothingBufferSize].X = warpedX;
smoothingBuffer[smoothingBufferIndex % smoothingBufferSize].Y = warpedY;
smoothingBufferIndex++;
if (!lastWiiState.IRState.Found1)//mouse down
{
lastWiiState.IRState.Found1 = ws.IRState.Found1;
smoothingBufferIndex = 0;//resets the count
if (cursorControl)
{
INPUT[] buffer = new INPUT[2];
buffer[0].type = INPUT_MOUSE;
buffer[0].mi.dx = (int)(warpedX *65535.0f/screenWidth);
buffer[0].mi.dy = (int)(warpedY * 65535.0f / screenHeight);
buffer[0].mi.mouseData = 0;
buffer[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
buffer[0].mi.time = 0;
buffer[0].mi.dwExtraInfo = (IntPtr)0;
buffer[1].type = INPUT_MOUSE;
buffer[1].mi.dx = 0;
buffer[1].mi.dy = 0;
buffer[1].mi.mouseData = 0;
buffer[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
buffer[1].mi.time = 1;
buffer[1].mi.dwExtraInfo = (IntPtr)0;
SendInput(2, buffer, Marshal.SizeOf(buffer[0]));
}//cusor control
switch (calibrationState)
{
case 1:
srcX[calibrationState - 1] = x;
srcY[calibrationState - 1] = y;
calibrationState = 2;
doCalibration();
break;
case 2:
srcX[calibrationState - 1] = x;
srcY[calibrationState - 1] = y;
calibrationState = 3;
doCalibration();
break;
case 3:
srcX[calibrationState - 1] = x;
srcY[calibrationState - 1] = y;
calibrationState = 4;
doCalibration();
break;
case 4:
srcX[calibrationState - 1] = x;
srcY[calibrationState - 1] = y;
calibrationState = 5;
doCalibration();
break;
default:
break;
}//calibtation state
}//mouse down
else
{
if (cursorControl)//dragging
{
INPUT[] buffer = new INPUT[1];
buffer[0].type = INPUT_MOUSE;
if (enableSmoothing)
{
PointF s = getSmoothedCursor(smoothingAmount);
buffer[0].mi.dx = (int)(s.X * 65535.0f / screenWidth);
buffer[0].mi.dy = (int)(s.Y * 65535.0f / screenHeight);
}
else
{
buffer[0].mi.dx = (int)(warpedX * 65535.0f / screenWidth);
buffer[0].mi.dy = (int)(warpedY * 65535.0f / screenHeight);
}
buffer[0].mi.mouseData = 0;
buffer[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
buffer[0].mi.time = 0;
buffer[0].mi.dwExtraInfo = (IntPtr)0;
SendInput(1, buffer, Marshal.SizeOf(buffer[0]));
}
}
}//ir visible
else
{
if (lastWiiState.IRState.Found1)//mouse up
{
lastWiiState.IRState.Found1 = ws.IRState.Found1;
if (cursorControl)
{
INPUT[] buffer = new INPUT[2];
buffer[0].type = INPUT_MOUSE;
buffer[0].mi.dx = 0;
buffer[0].mi.dy = 0;
buffer[0].mi.mouseData = 0;
buffer[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
buffer[0].mi.time = 0;
buffer[0].mi.dwExtraInfo = (IntPtr)0;
buffer[1].type = INPUT_MOUSE;
buffer[1].mi.dx = 0;
buffer[1].mi.dy = 0;
buffer[1].mi.mouseData = 0;
buffer[1].mi.dwFlags = MOUSEEVENTF_MOVE;
buffer[1].mi.time = 0;
buffer[1].mi.dwExtraInfo = (IntPtr)0;
SendInput(2, buffer, Marshal.SizeOf(buffer[0]));
}
}//ir lost
}
if (!lastWiiState.ButtonState.A && ws.ButtonState.A)
{
BeginInvoke((MethodInvoker)delegate() { btnCalibrate.PerformClick(); });
}
lastWiiState.ButtonState.A = ws.ButtonState.A;
if (!lastWiiState.ButtonState.B && ws.ButtonState.B)
keybd_event(VK_SPACE, 0x45, 0, 0);
if (lastWiiState.ButtonState.B && !ws.ButtonState.B)
keybd_event(VK_SPACE, 0x45, KEYEVENTF_KEYUP, 0);
lastWiiState.ButtonState.B = ws.ButtonState.B;
if (!lastWiiState.ButtonState.Up && ws.ButtonState.Up)
keybd_event(VK_UP, 0x45, 0, 0);
if (lastWiiState.ButtonState.Up && !ws.ButtonState.Up)
keybd_event(VK_UP, 0x45, KEYEVENTF_KEYUP, 0);
lastWiiState.ButtonState.Up = ws.ButtonState.Up;
if (!lastWiiState.ButtonState.Down && ws.ButtonState.Down)
keybd_event(VK_DOWN, 0x45, 0, 0);
if (lastWiiState.ButtonState.Down && !ws.ButtonState.Down)
keybd_event(VK_DOWN, 0x45, KEYEVENTF_KEYUP, 0);
lastWiiState.ButtonState.Down = ws.ButtonState.Down;
if (!lastWiiState.ButtonState.Left && ws.ButtonState.Left)
keybd_event(VK_LEFT, 0x45, 0, 0);
if (lastWiiState.ButtonState.Left && !ws.ButtonState.Left)
keybd_event(VK_LEFT, 0x45, KEYEVENTF_KEYUP, 0);
lastWiiState.ButtonState.Left = ws.ButtonState.Left;
if (!lastWiiState.ButtonState.Right && ws.ButtonState.Right)
keybd_event(VK_RIGHT, 0x45, 0, 0);
if (lastWiiState.ButtonState.Right && !ws.ButtonState.Right)
keybd_event(VK_RIGHT, 0x45, KEYEVENTF_KEYUP, 0);
lastWiiState.ButtonState.Right = ws.ButtonState.Right;
lastWiiState.IRState.Found1 = ws.IRState.Found1;
lastWiiState.IRState.RawX1 = ws.IRState.RawX1;
lastWiiState.IRState.RawY1 = ws.IRState.RawY1;
lastWiiState.IRState.Found2 = ws.IRState.Found2;
lastWiiState.IRState.RawX2 = ws.IRState.RawX2;
lastWiiState.IRState.RawY2 = ws.IRState.RawY2;
lastWiiState.IRState.Found3 = ws.IRState.Found3;
lastWiiState.IRState.RawX3 = ws.IRState.RawX3;
lastWiiState.IRState.RawY3 = ws.IRState.RawY3;
lastWiiState.IRState.Found4 = ws.IRState.Found4;
lastWiiState.IRState.RawX4 = ws.IRState.RawX4;
lastWiiState.IRState.RawY4 = ws.IRState.RawY4;
//draw battery value on GUI
//BeginInvoke((MethodInvoker)delegate() { pbBattery.Value = (ws.Battery > 0xc8 ? 0xc8 : (int)ws.Battery); });
//float f = (((100.0f * 48.0f * (float)(ws.Battery / 48.0f))) / 192.0f);
//BeginInvoke((MethodInvoker)delegate() { lblBattery.Text = f.ToString("f0") + "%"; });
//check the GUI check boxes if the IR dots are visible
//String irstatus = "Visible IR dots: ";
//if (ws.IRState.Found1)
// irstatus += "1 ";
//if (ws.IRState.Found2)
// irstatus += "2 ";
//if (ws.IRState.Found3)
// irstatus += "3 ";
//if (ws.IRState.Found4)
// irstatus += "4 ";
//BeginInvoke((MethodInvoker)delegate() { lblIRvisible.Text = irstatus; });
mut.ReleaseMutex();
}
public void loadCalibrationData()
{
// create reader & open file
try
{
TextReader tr = new StreamReader("calibration.dat");
for (int i = 0; i < 4; i++)
{
srcX[i] = float.Parse(tr.ReadLine());
srcY[i] = float.Parse(tr.ReadLine());
}
smoothingAmount = int.Parse(tr.ReadLine());
// close the stream
tr.Close();
}
catch (Exception x)
{
//no prexsting calibration
return;
}
warper.setDestination( screenWidth * calibrationMargin,
screenHeight * calibrationMargin,
screenWidth * (1.0f-calibrationMargin),
screenHeight * calibrationMargin,
screenWidth * calibrationMargin,
screenHeight * (1.0f - calibrationMargin),
screenWidth * (1.0f - calibrationMargin),
screenHeight * (1.0f - calibrationMargin));
warper.setSource(srcX[0], srcY[0], srcX[1], srcY[1], srcX[2], srcY[2], srcX[3], srcY[3]);
warper.computeWarp();
setSmoothing(smoothingAmount);
cursorControl = true;
// BeginInvoke((MethodInvoker)delegate() { cbCursorControl.Checked = cursorControl; });
UpdateTrackingUtilization();
}
public void saveCalibrationData()
{
TextWriter tw = new StreamWriter("calibration.dat");
// write a line of text to the file
for (int i = 0; i < 4; i++)
{
tw.WriteLine(srcX[i]);
tw.WriteLine(srcY[i]);
}
tw.WriteLine(smoothingAmount);
// close the stream
tw.Close();
}
public void doCalibration(){
if (cf == null)
return;
int x = 0;
int y = 0;
int size = 25;
Pen p = new Pen(Color.Red);
switch (calibrationState)
{
case 1:
x = (int)(screenWidth * calibrationMargin);
y = (int)(screenHeight * calibrationMargin);
cf.showCalibration(x, y, size, p);
dstX[calibrationState - 1] = x;
dstY[calibrationState - 1] = y;
break;
case 2:
x = screenWidth - (int)(screenWidth * calibrationMargin);
y = (int)(screenHeight * calibrationMargin);
cf.showCalibration(x, y, size, p);
dstX[calibrationState - 1] = x;
dstY[calibrationState - 1] = y;
break;
case 3:
x = (int)(screenWidth * calibrationMargin);
y = screenHeight -(int)(screenHeight * calibrationMargin);
cf.showCalibration(x, y, size, p);
dstX[calibrationState - 1] = x;
dstY[calibrationState - 1] = y;
break;
case 4:
x = screenWidth - (int)(screenWidth * calibrationMargin);
y = screenHeight -(int)(screenHeight * calibrationMargin);
cf.showCalibration(x, y, size, p);
dstX[calibrationState - 1] = x;
dstY[calibrationState - 1] = y;
break;
case 5:
//compute warp
warper.setDestination(dstX[0], dstY[0], dstX[1], dstY[1], dstX[2], dstY[2], dstX[3], dstY[3]);
warper.setSource(srcX[0], srcY[0], srcX[1], srcY[1], srcX[2], srcY[2], srcX[3], srcY[3]);
warper.computeWarp();
cf.Close();
cf = null;
calibrationState = 0;
cursorControl = true;
// BeginInvoke((MethodInvoker)delegate() { cbCursorControl.Checked = cursorControl; });
// saveCalibrationData();
UpdateTrackingUtilization();
break;
default:
break;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
//disconnect the wiimote
wm.Disconnect();
saveCalibrationData();
}
private void btnCalibrate_Click(object sender, EventArgs e)
{
if (cf == null)
{
cf = new CalibrationForm();
cf.Show();
}
if (cf.IsDisposed)
{
cf = new CalibrationForm();
cf.Show();
}
cursorControl = false;
calibrationState = 1;
doCalibration();
}
private void cbCursorControl_CheckedChanged(object sender, EventArgs e)
{
//cursorControl = cbCursorControl.Checked;
}
private void label1_Click(object sender, EventArgs e)
{
}
private void setSmoothing(int smoothing)
{
smoothingAmount = smoothing;
//trackBar1.Value = smoothing;
enableSmoothing = (smoothingAmount != 0);
// lblSmoothing.Text = "Smoothing: " + smoothingAmount;
}
//private void trackBar1_Scroll(object sender, EventArgs e)
//{
// smoothingAmount = trackBar1.Value;
// enableSmoothing = (smoothingAmount != 0);
// lblSmoothing.Text = "Smoothing: " + smoothingAmount;
//}
private void lblIRvisible_Click(object sender, EventArgs e)
{
}
}
}
It's used for calibration via matrix calculations.
The Warper actually handles matrix transformations to calibrate the screen position etc I guess.
The matrix is 4x4 --> 4 arrays with size of 4.
Here you can have a look into the Code
I know how set the system cursor from xxx.cur file, but I want to know how to save the current system cursor to a file.
In WPF, set system cursor can use the following code:
[DllImport("user32.dll")]
internal static extern IntPtr LoadCursorFromFile(string lpFileName);
[DllImport("user32.dll")]
internal static extern bool SetSystemCursor(IntPtr hcur, uint id);
internal const uint OCR_NORMAL = 32512;
IntPtr hAni = Win32Api.LoadCursorFromFile("file.cur");
bool b = SetSystemCursor(hAni, Win32Api.OCR_NORMAL);
But I don't know how to save the current system cursor to the disk.
Can anyone tell me, thanks.
This is potentially a bit ugly and the code I'm posting is not factored very nicely (it's rough to describe the solution), but you can pull the current cursors from the registry and then save them back out again.
public class UserCursors
{
[Serializable]
internal enum ImageType
{
Bitmap = 0,
Icon = 1,
Cursor = 2,
EnhMetafile = 3,
}
[Serializable, Flags]
internal enum LoadImageFlags
{
DefaultColor = 0x0,
Monochrome = 0x1,
Color = 0x2,
CopyReturnOriginal = 0x4,
CopyDeleteOriginal = 0x8,
LoadFromFile = 0x10,
LoadTransparent = 0x20,
DefaultSize = 0x40,
VgaColor = 0x80,
LoadMap3DColors = 0x1000,
CreateDibSection = 0x2000,
CopyFromResource = 0x4000,
Shared = 0x8000,
}
[DllImport("user32.dll")]
static extern IntPtr LoadImage(IntPtr hinst, String lpszName, ImageType uType, Int32 cxDesired, Int32 cyDesired, LoadImageFlags fuLoad);
public IntPtr hInst = IntPtr.Zero;
public String lpszName;
public Int32 width = 0;
public Int32 height = 0;
public string regKeyName = String.Empty;
public bool Changed = false;
public UserCursors()
{
}
public UserCursors(string cursorLocation, string keyName)
{
hInst = LoadImage(IntPtr.Zero, cursorLocation, ImageType.Cursor, width, height, LoadImageFlags.LoadFromFile);
lpszName = cursorLocation;
regKeyName = keyName;
}
}
Then create a list for example
public List<UserCursors> systemCursors;
Load up the list
[DllImport("user32.dll", SetLastError = true)]
static extern bool SetSystemCursor(IntPtr hcur, uint id);
const uint OCR_NORMAL = 32512;
const uint OCR_HAND = 32649;
const uint OCR_IBEAM = 32513;
IntPtr hArrow = LoadImage(IntPtr.Zero, "<my custom cursor file>", ImageType.Cursor, width, height, LoadImageFlags.LoadFromFile);
IntPtr hHand = LoadImage(IntPtr.Zero, "<my custom cursor file>", ImageType.Cursor, width, height, LoadImageFlags.LoadFromFile);
IntPtr hBeam = LoadImage(IntPtr.Zero, "<my custom cursor file>", ImageType.Cursor, width, height, LoadImageFlags.LoadFromFile);
RegistryKey myCursors = Registry.CurrentUser.OpenSubKey(defaultCursors);
string[] keyCursors = myCursors.GetValueNames();
bool beamFound = false;
int lastError = 0;
foreach (string cursorKey in keyCursors)
{
RegistryValueKind rvk = myCursors.GetValueKind(cursorKey);
switch (rvk)
{
case RegistryValueKind.ExpandString:
string cursorValue = myCursors.GetValue(cursorKey) as string;
if (!String.IsNullOrEmpty(cursorValue))
{
UserCursors currentSystemCursor = new UserCursors(cursorValue, cursorKey);
switch (cursorKey)
{
case "Arrow":
currentSystemCursor.Changed = SetSystemCursor(hArrow, OCR_NORMAL);
break;
case "Hand":
currentSystemCursor.Changed = SetSystemCursor(hHand, OCR_HAND);
if (!currentSystemCursor.Changed)
{
lastError = Marshal.GetLastWin32Error();
Win32Exception ex = new Win32Exception(lastError);
}
break;
case "IBeam":
beamFound = true;
currentSystemCursor.Changed = SetSystemCursor(hBeam, OCR_IBEAM);
break;
default:
break;
}
systemCursors.Add(currentSystemCursor);
}
break;
default:
break;
}
}
// if a user hasn't customised the IBeam then it doesn't appear in the registry so we still change it
// and then clear the value to remove it.
if (!beamFound)
{
UserCursors currentSystemCursor = new UserCursors("C:\\Windows\\Cursors\\beam_i.cur", "IBeam");
currentSystemCursor.Changed = SetSystemCursor(hBeam, OCR_IBEAM);
systemCursors.Add(currentSystemCursor);
}
and then in the destructor or finalize or similar
~MainWindow()
{
int lastError = 0;
bool changed = false;
foreach (UserCursors savedCursor in systemCursors)
{
if (savedCursor.Changed)
{
switch (savedCursor.regKeyName)
{
case "Arrow":
changed = SetSystemCursor(savedCursor.hInst, OCR_NORMAL);
if (!changed)
{
lastError = Marshal.GetLastWin32Error();
Win32Exception ex = new Win32Exception(lastError);
}
break;
case "Hand":
changed = SetSystemCursor(savedCursor.hInst, OCR_HAND);
if (!changed)
{
lastError = Marshal.GetLastWin32Error();
Win32Exception ex = new Win32Exception(lastError);
}
break;
case "IBeam":
changed = SetSystemCursor(savedCursor.hInst, OCR_IBEAM);
if (!changed)
{
lastError = Marshal.GetLastWin32Error();
Win32Exception ex = new Win32Exception(lastError);
}
break;
default:
break;
}
}
}
}