/// <summary> /// Creates an Image object containing a screen shot of a specific window /// </summary> /// <param name="handle">The handle to the window. (In windows forms, this is obtained by the Handle property)</param> /// <returns></returns> public Image CaptureWindow(IntPtr handle) { // get te hDC of the target window IntPtr hdcSrc = User32.GetWindowDC(handle); // get the size User32.RECT windowRect = new User32.RECT(); User32.GetWindowRect(handle, ref windowRect); //int width = windowRect.right - windowRect.left; //int height = windowRect.bottom - windowRect.top; int width = ScreenPixelHelper.GetScreenSize().Width; int height = ScreenPixelHelper.GetScreenSize().Height; // create a device context we can copy to IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc); // create a bitmap we can copy it to, // using GetDeviceCaps to get the width/height IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height); // select the bitmap object IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap); // bitblt over GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY); // restore selection GDI32.SelectObject(hdcDest, hOld); // clean up GDI32.DeleteDC(hdcDest); User32.ReleaseDC(handle, hdcSrc); // get a .NET image object for it Image img = Image.FromHbitmap(hBitmap); // free up the Bitmap object GDI32.DeleteObject(hBitmap); return(img); }
//Input: c is the proposed center, w is width of rectangle, h is the height //Output: returns a new center point so that the entire rectangle fits the screen public Point CalculateRectCenterToFitScreen(Point c, float w, float h) { Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); Point r = new Point(c.X, c.Y); if (c.X - w / 2 < 0) { //We need to shift to right r.X = c.X - (c.X - Convert.ToInt32(Math.Round(w / 2))); } if (c.X + w / 2 > screenSize.Width) { //shift to the left r.X = c.X - (c.X + Convert.ToInt32(Math.Round(w / 2)) - screenSize.Width); } if (c.Y - h / 2 < 0) { //We need to shift down r.Y = c.Y - (c.Y - Convert.ToInt32(Math.Round(h / 2))); } if (c.Y + h / 2 > screenSize.Height) { //shift up r.Y = c.Y - (c.Y + Convert.ToInt32(Math.Round(h / 2)) - screenSize.Height); } return(r); }
public void Update(Point p, float addedMagnification = 0) { if (!active) { return; } Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); p = BoundPointToRect(p, screenSize, 5); zoomPct = ConfigManager.zoomWindowMagnificationPct + addedMagnification; activeRectPctScreen = ConfigManager.zoomWindowPctScreen; activeRectPaddedPctScreen = activeRectPctScreen + 15; aciveRectSrcPctScreen = (float)activeRectPctScreen * 100 / (float)zoomPct; //Calculate the size and position of the source rectangle float w = (float)screenSize.Width * aciveRectSrcPctScreen / 100; float h = (float)screenSize.Height * aciveRectSrcPctScreen / 100; //Check based on the height, width, and p if we need to shift to fit on screen activeRectSrcCenter = CalculateRectCenterToFitScreen(p, w, h); int xScreen = activeRectSrcCenter.X - Convert.ToInt32(w / 2); int yScreen = activeRectSrcCenter.Y - Convert.ToInt32(h / 2); activeRectSrc = new Rectangle(xScreen, yScreen, Convert.ToInt32(w), Convert.ToInt32(h)); float activeRectWidth = (float)screenSize.Width * activeRectPctScreen / 100; float activeRectHeight = (float)screenSize.Height * activeRectPctScreen / 100; activeRectCenter = CalculateRectCenterToFitScreen(p, activeRectWidth, activeRectHeight); xScreen = activeRectCenter.X - Convert.ToInt32((activeRectWidth / 2)); yScreen = activeRectCenter.Y - Convert.ToInt32((activeRectHeight / 2)); activeRect = new Rectangle(xScreen, yScreen, Convert.ToInt32(activeRectWidth), Convert.ToInt32(activeRectHeight)); //Calculate the padded activeRect so that within this padding the zoombox does not cancel when user looks away float activeRectWidthPadded = screenSize.Width * activeRectPaddedPctScreen / 100; float activeRectHeightPadded = screenSize.Height * activeRectPaddedPctScreen / 100; xScreen = activeRectCenter.X - Convert.ToInt32((activeRectWidthPadded / 2)); yScreen = activeRectCenter.Y - Convert.ToInt32((activeRectHeightPadded / 2)); activeRectPadded = new Rectangle(xScreen, yScreen, Convert.ToInt32(activeRectWidthPadded), Convert.ToInt32(activeRectHeightPadded)); //Allows drawing cursor icons underneath the WinzoomForm. //wzuf is already fine and needs no updating since all it's location info happens in OnPaint //zbf.BackColor = Color.FromArgb(216,249,107); //a very unusual light green color wzf.magnification = (float)zoomPct / 100; wzf.mag.magnification = (float)zoomPct / 100; wzf.Width = Convert.ToInt32(activeRectWidth); wzf.Height = Convert.ToInt32(activeRectHeight); wzf.StartPosition = FormStartPosition.Manual; wzf.Location = new Point(activeRect.X, activeRect.Y); wzf.mag.SetSourceRect(activeRectSrc); wzf.mag.SetActiveRect(activeRect); wzf.Invalidate(); }
public static Rectangle GetStartMenuRect() { Rectangle screenRect = ScreenPixelHelper.GetScreenSize(); Rectangle waRect = ScreenPixelHelper.GetScreenWorkingArea(); //the taskbar might be located other than the bottom of the screen default //But it doesn't matter since we are showing this overlay form return(new Rectangle(0, waRect.Bottom, 48, screenRect.Bottom - waRect.Bottom)); //value measured with pixel ruler }
public bool BoxLargeEnough(Box b) { if (b == null) { return(false); } int threshold = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.cursorMagnetClippingMinBoxWidthMm); return(b.width() >= threshold && b.height() >= threshold); }
private void CalibrationAdjusterManualForm_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { int s = ScreenPixelHelper.ConvertMmToPixels(1); //step size of keyboard arrow input to control the gaze point adjustment offset switch (e.KeyCode) { case Keys.Enter: currentCircle++; this.Invalidate(); // This forces the form to repaint break; case Keys.Up: ca.adjGridOffset[currentCircle].Offset(0, -1 * s); break; case Keys.Down: ca.adjGridOffset[currentCircle].Offset(0, s); break; case Keys.Left: ca.adjGridOffset[currentCircle].Offset(-1 * s, 0); break; case Keys.Right: ca.adjGridOffset[currentCircle].Offset(s, 0); break; case Keys.Alt: //no break stmt case Keys.Escape: ca.writeCalibrationAdjustmentCsv(); this.Close(); //prevent altf4 crash break; case Keys.Space: //record adjustment Point wp = controller.WarpPointer.GetWarpPoint(); Point calpoint = ca.adjGrid[currentCircle]; ca.adjGridOffset[currentCircle] = new Point((calpoint.X - wp.X), (calpoint.Y - wp.Y)); this.Invalidate(); // This forces the form to repaint break; default: break; } //see if done all adjustment points if (currentCircle == 9) { ca.writeCalibrationAdjustmentCsv(); currentCircle = 0; this.Close(); } }
//Calculates target circle radius based on number of iterations completed, max number of iterations, min and max circle radiuses private int GetTargetCircleRadius(int iter) { int maxIterations = ConfigManager.calibrationIterationCountMax; int minRadius = ScreenPixelHelper.ConvertMmToPixels(1); int maxRadius = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.calibrationCircleSizeMm); int rDiff = maxRadius - minRadius; double rStep = (double)rDiff / (double)(maxIterations - 1); int iterBounded = Math.Min(iter, maxIterations - 1); //note: deliberately capping at maxIterations -1 and therefore never reaches 0.2% screen return((int)(maxRadius - iterBounded * rStep)); }
public bool NearLastIbeamPoint(Point p) { if (lastIbeamPoint == null) { return(false); } int nearbyMm = 7; //mm int nearbyPixels = ScreenPixelHelper.ConvertMmToPixels(nearbyMm); return(PointHelper.GetPointDistance(p, lastIbeamPoint) <= nearbyPixels); }
public CursorOverlayForm() { InitializeComponent(); FormBorderStyle = FormBorderStyle.None; this.Size = ScreenPixelHelper.GetScreenWorkingArea().Size; User32.SetWindowPos(this.Handle, User32.HWND_TOPMOST, 0, 0, 0, 0, (User32.SWP_NOMOVE | User32.SWP_NOSIZE | User32.SWP_SHOWWINDOW)); UpArrowImage = Properties.Resources.uparrow; DownArrowImage = Properties.Resources.downarrow; Logger.WriteMsg("CursorOverlayForm instantiated."); }
//whenever this method is called, it paints from scratch and does not append to what's already on the screen //this method is typically called whenever RefreshScreen is called (60 fps) protected override void OnPaint(PaintEventArgs e) { int radius = ScreenPixelHelper.ConvertMmToPixels(1.25); //radius Point p = ca.adjGrid[currentCircle]; Rectangle rec = new Rectangle(p.X - radius, p.Y - radius, radius * 2, radius * 2); e.Graphics.DrawEllipse(Pens.White, rec); //draw gray gaze point p = controller.WarpPointer.GetNextPoint(controller.WarpPointer.GetGazePoint()); p.Offset(ca.adjGridOffset[currentCircle]); rec = new Rectangle(p.X - radius, p.Y - radius, radius * 2, radius * 2); e.Graphics.FillEllipse(Brushes.Gray, rec); }
//TODO: refactor these methods to same one and use enums /* * Returns true if: * All gazepoints for the past minMs duration are within radiusMm of the first gaze point in the observed set. * * This function should be called when you want to limit the fixation region to a certain millimeters within the * gazepoint at minMs milliseconds ago. */ public static bool IsStationaryFixation(int minMs, int radiusMm) { if (warpPointer == null) { return(false); } List <Point> rawGazePoints = warpPointer.GetGazeHistory(); if (rawGazePoints == null || rawGazePoints.Count == 0) { return(false); } int sampleRate = warpPointer.GetSampleRate(); //total number of samples that should be meet the fixation width criteria int lookbackSampleCount = (int)Math.Max(1, sampleRate * minMs / 1000); if (lookbackSampleCount > rawGazePoints.Count) { return(false); } //Find the average of all the lookbackSamples ... int startIndex = Math.Max(0, rawGazePoints.Count - lookbackSampleCount); Point runningSum = new Point(0, 0); Point runningAvg = new Point(0, 0); for (int i = startIndex; i < rawGazePoints.Count; i++) { runningSum.X += rawGazePoints[i].X; runningSum.Y += rawGazePoints[i].Y; } runningAvg.X = runningSum.X / lookbackSampleCount; runningAvg.Y = runningSum.Y / lookbackSampleCount; //Check if distances between all points are within radius for (int i = startIndex + 1; i < rawGazePoints.Count; i++) { if (PointHelper.GetPointDistance(runningAvg, rawGazePoints[i]) > ScreenPixelHelper.ConvertMmToPixels(radiusMm)) { return(false); //this point is too far from the first point } } return(true); }
public List <Box> getNearBoxes(Point gp) { List <Box> nearby = new List <Box>(); int nearThreshold = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.cursorMagnetClippingThresholdMm); foreach (Box b in boxes) { //should only work if the box have height and width //if box is valid and the point is near a box defined by threshold, then we add it to the working set if ((isNearBox(gp, b, nearThreshold)) && (b.top != b.bottom && b.left != b.right)) { nearby.Add(b); // Debug.WriteLine("Found Box nearby" + currentBox[0] + "," + currentBox[1] + " " + Cursor.Position); } } return(nearby); }
private void AddGazeButtons() { //int buttonHeight = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.dockButtonHeightMm); int buttonHeightOffsetPx = ScreenPixelHelper.ConvertMmToPixels(5); int buttonHeight = (this.Height / gazeButtonTextStrings.Length) - buttonHeightOffsetPx; //Calculate vertical spacing between each of the buttons int heightStep = (this.Height - buttonHeight) / (gazeButtonTextStrings.Length - 1); for (int i = 0; i < gazeButtonTextStrings.Length; i++) { //create a new button Button b = new Button(); b.AutoSize = false; b.Width = this.Width; //TODO: replace with just height b.Height = buttonHeight; //Location of the button is relative to the form b.Location = new Point(this.Width - b.Width, i * heightStep); b.Text = gazeButtonTextStrings[i]; b.Font = new Font(FontFamily.GenericSansSerif, 14); b.TextAlign = ContentAlignment.MiddleRight; b.ForeColor = Color.White; b.BackColor = Color.Black; //remove border b.TabStop = false; b.FlatStyle = FlatStyle.Flat; b.FlatAppearance.BorderSize = 0; //Apply padding to enlarge the "gazeable/clickable" area of the button //b.Padding = new Padding(buttonLeftPadding, buttonVerticalPadding, 0, buttonVerticalPadding); //b.Margin = new Padding(buttonLeftPadding, buttonVerticalPadding, 0, buttonVerticalPadding); b.Click += gazeButton_Click; //b.Paint += new System.Windows.Forms.PaintEventHandler(this.gazeButton_Paint); b.MouseEnter += gazeButton_MouseEnter; b.MouseLeave += gazeButton_MouseLeave; //TODO: ButtonBorderStyle.None gazeButtonsList.Add(b); this.Controls.Add(b); } }
public void setMode(Mode mode) { if (warp != null) { warp.Dispose(); } if (prec != null) { prec.Dispose(); } this.mode = mode; switch (mode) { case Mode.EYEX_AND_TRACKIR: warp = new EyeXWarpPointer(ScreenPixelHelper.ConvertMmToPixels(25)); prec = new TrackIRPrecisionPointer(ScreenPixelHelper.ConvertMmToPixels(25), 0.3); break; case Mode.EYEX_AND_SMARTNAV: warp = new EyeXWarpPointer(ScreenPixelHelper.ConvertMmToPixels(1)); prec = new NoPrecisionPointer(); state = TrackingState.RUNNING; break; case Mode.EYEX_ONLY: warp = new EyeXWarpPointer(ScreenPixelHelper.ConvertMmToPixels(5)); prec = new NoPrecisionPointer(); break; } Logger.WriteVar(nameof(mode), mode); if (!warp.IsStarted()) { state = TrackingState.ERROR; } if (!prec.IsStarted()) { state = TrackingState.ERROR; } }
public bool WithinRect(Point p, ZOOMBOX_RECT_T rect_t) { if (!active) { return(false); } Rectangle rect = GetActiveRectFromType(rect_t); Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); p = BoundPointToRect(p, screenSize, 5); if (p.X >= rect.Left && p.X <= rect.Right && p.Y >= rect.Top && p.Y <= rect.Bottom) { return(true); } return(false); }
public Point StayOrExitBox(Point gp) { //iterate through all the most recent raw gaze points and check that they all are at least thresholdPixels away int threshold = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.cursorMagnetClippingExitThresholdMm); List <Point> rawGazePoints = mc.WarpPointer.GetGazeHistory(); if (rawGazePoints == null || rawGazePoints.Count == 0 || ClippedBox == null) { winzoomAvailable = true; return(gp); //todo: out of bound? } int sampleRate = mc.WarpPointer.GetSampleRate(); int recentDurationMs = ConfigManager.cursorMagnetClippingExitDurationMs; //todo: config int lookbackSampleCount = sampleRate * recentDurationMs / 1000; int startIndex = Math.Max(0, rawGazePoints.Count - lookbackSampleCount); //all points have to leave the box by at least exitThreshold amount in order to consider exit //equivalent to having 1 point not leave the box by exitThreshold to continue staying for (int i = startIndex; i < rawGazePoints.Count; i++) { //use the calibration adjusted value for the raw data Point adjustedGp = new Point(rawGazePoints[i].X, rawGazePoints[i].Y); adjustedGp.Offset(calibrationAdjuster.GetCalibrationAdjustment(adjustedGp)); if (isNearBox(adjustedGp, ClippedBox, ScreenPixelHelper.ConvertMmToPixels(ConfigManager.cursorMagnetClippingExitThresholdMm))) { //stay in box, since 1 point is still threshold/2 near the perimeter of the currently clipped box return(ClippedBox.center()); } } //We went through the most recent gaze points and all of them are more than threshold away //Exit this box ClippedBox = null; winzoomAvailable = true; return(gp); //todo: out of bound }
public Point limitToScreenBounds(Point p) { Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); int margin = 5; if (p.X < margin) { p.X = margin; } if (p.Y < margin) { p.Y = margin; } if (p.X >= screenSize.Width - margin) { p.X = screenSize.Width - margin; } if (p.Y >= screenSize.Height - margin - 5) { p.Y = screenSize.Height - margin - 5; } return(p); }
protected override void OnPaint(PaintEventArgs e) { User32.SetFormTransparent(this.Handle); //Convert the current warp point a point on the screen Point wp = warpPointer.GetWarpPoint(); wp.Offset(calibrationAdjuster.GetCalibrationAdjustment(wp)); Point screenPoint = wz.ConvertToScreenPoint(wp); Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); if (ConfigManager.zoomboxGrid) { //Draw a vertical line e.Graphics.DrawLine(Pens.Black, new Point(screenPoint.X, screenSize.Top), new Point(screenPoint.X, screenSize.Bottom)); //Draw a horizontal line e.Graphics.DrawLine(Pens.Black, new Point(screenSize.Left, screenPoint.Y), new Point(screenSize.Right, screenPoint.Y)); } else { DrawApplicableCursorSymbol(e, screenPoint); } }
private void DockForm_Load(object sender, EventArgs e) { //1. Setup dock so that form window takes calculated user-amount of space on right side int dockWidth = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.dockFormMaxWidthMm); //Calculate dock height Rectangle wa = ScreenPixelHelper.GetScreenWorkingArea(); int dockHeight = wa.Height; //calculate dock location Point dockLocation = new Point(wa.Right - dockWidth, wa.Top); this.Location = dockLocation; this.Size = new Size(dockWidth, dockHeight); this.BackColor = Color.Black; //Add all the buttons for the dock AddGazeButtons(); SetActiveGazeButton(GAZE_BUTTON_TYPE.NONE); Logger.WriteMsg("About to register dockbar."); //Now let's dock the window RegisterDockbar(); }
/* * Returns true if: * The speed of eye movement does not exceed (radiusMM / ConfigManager.fixationMinDurationMs) millimeters/seconds * measured over a total duration of minMs. * * This function should be called when it's acceptable for the eyes to continue moving slowly and still count it as fixation. */ public static bool IsMovingFixation(int minMs, int radiusMm) { if (warpPointer == null) { return(false); } List <Point> rawGazePoints = warpPointer.GetGazeHistory(); if (rawGazePoints == null || rawGazePoints.Count == 0) { return(false); } int sampleRate = warpPointer.GetSampleRate(); //total number of samples that should be meet the fixation width criteria int lookbackSampleCount = (int)Math.Max(1, sampleRate * minMs / 1000); if (lookbackSampleCount > rawGazePoints.Count) { return(false); } //moving window samples amount int windowSampleCount = Math.Max(sampleRate * ConfigManager.fixationMinDurationMs / 1000, 1); int stopIndex = Math.Max(0, rawGazePoints.Count - windowSampleCount); //Get average of the first window //We start at the most recent point in history Point runningSum = new Point(0, 0); Point runningAvg = new Point(0, 0); for (int i = rawGazePoints.Count - 1; i >= stopIndex; i--) { runningSum.X += rawGazePoints[i].X; runningSum.Y += rawGazePoints[i].Y; } runningAvg.X = runningSum.X / windowSampleCount; runningAvg.Y = runningSum.Y / windowSampleCount; //Check that each point in the current window meets the fixation width criteria for (int i = rawGazePoints.Count - 1; i >= stopIndex; i--) { if (PointHelper.GetPointDistance(runningAvg, rawGazePoints[i]) > ScreenPixelHelper.ConvertMmToPixels(radiusMm)) { return(false); //this point is too far from the avg } } //slide window until we complete lookbackSampleCount many stopIndex = Math.Max(0, rawGazePoints.Count - lookbackSampleCount); int lowerIndex = rawGazePoints.Count - 1 - windowSampleCount; while (lowerIndex >= stopIndex) { int upperIndex = lowerIndex + windowSampleCount; //Remove one point from window runningSum.X -= rawGazePoints[upperIndex].X; runningSum.Y -= rawGazePoints[upperIndex].Y; //Add another point to the window runningSum.X += rawGazePoints[lowerIndex].X; runningSum.Y += rawGazePoints[lowerIndex].Y; //Recalculate avg runningAvg.X = runningSum.X / windowSampleCount; runningAvg.Y = runningSum.Y / windowSampleCount; //See if newest point is within the average if (PointHelper.GetPointDistance(runningAvg, rawGazePoints[lowerIndex]) > ScreenPixelHelper.ConvertMmToPixels(radiusMm)) { return(false); //this point is too far from the avg } lowerIndex--; } //Been through lookbackSampleCount and all of them according to the moving window are within fixation width requirement return(true); }
private Point getScreenCenter() { Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); return(new Point(screenSize.Width / 2, screenSize.Height / 2)); }
//NOTE: it doesn't really matter if user's taskbar is arranged elsewhere since we are using this hider form public static Point GetStartMenuLocation() { return(new Point(ScreenPixelHelper.ConvertMmToPixels(3), ScreenPixelHelper.GetScreenSize().Height - ScreenPixelHelper.ConvertMmToPixels(4))); }
//It is hardcoded to set to the right side private void ABSetPos() { Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); try { APPBARDATA abd = new APPBARDATA(); abd.cbSize = Marshal.SizeOf(abd); abd.hWnd = this.Handle; abd.uEdge = (int)ABEdge.ABE_RIGHT; if (abd.uEdge == (int)ABEdge.ABE_LEFT || abd.uEdge == (int)ABEdge.ABE_RIGHT) { abd.rc.top = 0; abd.rc.bottom = screenSize.Height; if (abd.uEdge == (int)ABEdge.ABE_LEFT) { abd.rc.left = 0; abd.rc.right = Size.Width; } else { abd.rc.right = screenSize.Width; abd.rc.left = abd.rc.right - Size.Width; } } else { abd.rc.left = 0; abd.rc.right = screenSize.Width; if (abd.uEdge == (int)ABEdge.ABE_TOP) { abd.rc.top = 0; abd.rc.bottom = Size.Height; } else { abd.rc.bottom = screenSize.Height; abd.rc.top = abd.rc.bottom - Size.Height; } } // Query the system for an approved size and position. SHAppBarMessage((int)ABMsg.ABM_QUERYPOS, ref abd); // Adjust the rectangle, depending on the edge to which the // appbar is anchored. switch (abd.uEdge) { case (int)ABEdge.ABE_LEFT: abd.rc.right = abd.rc.left + Size.Width; break; case (int)ABEdge.ABE_RIGHT: abd.rc.left = abd.rc.right - Size.Width; break; case (int)ABEdge.ABE_TOP: abd.rc.bottom = abd.rc.top + Size.Height; break; case (int)ABEdge.ABE_BOTTOM: abd.rc.top = abd.rc.bottom - Size.Height; break; } // Pass the final bounding rectangle to the system. SHAppBarMessage((int)ABMsg.ABM_SETPOS, ref abd); // Move and size the appbar so that it conforms to the // bounding rectangle passed to the system. MoveWindow(abd.hWnd, abd.rc.left, abd.rc.top, abd.rc.right - abd.rc.left, abd.rc.bottom - abd.rc.top, true); } catch (Exception ex) { Logger.WriteError(ex.ToString()); } }
//This function gets called pretty much every precision gaze mouse form refresh public void ShowCursorOverlay(Point p) { if (activeGazeButton == GAZE_BUTTON_TYPE.DOWN || activeGazeButton == GAZE_BUTTON_TYPE.UP) { if (cursorOverlayForm == null || cursorOverlayForm.IsDisposed) { Logger.WriteMsg("New Cursor Overlay Form being created."); cursorOverlayForm = new CursorOverlayForm(); } //Only update the overlay location if there is a change by more than 5 mm if (PointHelper.GetPointDistance(p, cursorOverlayForm.currentPoint) > ScreenPixelHelper.ConvertMmToPixels(5)) { cursorOverlayForm.currentPoint = p; if (activeGazeButton == GAZE_BUTTON_TYPE.DOWN) { cursorOverlayForm.UpdateOverlayType(CursorOverlayForm.OVERLAY_TYPE.DOWNARROW); } else if (activeGazeButton == GAZE_BUTTON_TYPE.UP) { cursorOverlayForm.UpdateOverlayType(CursorOverlayForm.OVERLAY_TYPE.UPARROW); } if (!cursorOverlayForm.Visible) { Logger.WriteMsg("Cursor OverlyForm about to be shown."); cursorOverlayForm.Show(); } else { cursorOverlayForm.Invalidate(); } } } else { HideCursorOverlayForm(); } }
public static Rectangle GetScreenSize() { return(ScreenPixelHelper.GetScreenSize()); }
public Point ConvertToScreenPoint(Point p) { Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); p = BoundPointToRect(p, screenSize, 5); int delta = ScreenPixelHelper.ConvertMmToPixels(1); //We want to find the "center" which is the focal point of where magnified and system cursor intersect //on the winzoom box. It is different whether edge or corner, or if winzoom box is in middle of screen int x = 0; if (Math.Abs(activeRect.Left - activeRectSrc.Left) < delta) { x = 0; } else if (Math.Abs(activeRect.Right - activeRectSrc.Right) < delta) { x = screenSize.Width; } else if (activeRect.Left < delta) //only activeRect is left aligned { //Experimentally and analytically determined this formula x = Convert.ToInt32((Convert.ToDouble(activeRectSrc.Left) * zoomPct / (zoomPct - 100))); } else if (Math.Abs(activeRect.Right - screenSize.Width) < delta) //only activeRect is right aligned { int xdiff = (activeRect.Right - activeRectSrc.Right); //this will be a positive number int xDiffScaled = Convert.ToInt32((Convert.ToDouble(xdiff) * zoomPct / (zoomPct - 100))); x = activeRect.Right - xDiffScaled; } else { x = activeRectSrcCenter.X; } int y = 0; if (Math.Abs(activeRect.Top - activeRectSrc.Top) < delta) { y = 0; } else if (Math.Abs(activeRect.Bottom - activeRectSrc.Bottom) < delta) { y = screenSize.Height; } else if (activeRect.Top < delta) //only activeRect is left aligned { y = Convert.ToInt32((activeRectSrc.Top * zoomPct / (zoomPct - 100))); } else if (Math.Abs(activeRect.Bottom - screenSize.Width) < delta) //only activeRect is right aligned { int ydiff = (activeRect.Bottom - activeRectSrc.Bottom); //this will be a positive number int yDiffScaled = Convert.ToInt32((ydiff * zoomPct / (zoomPct - 100))); y = activeRect.Bottom - yDiffScaled; } else { y = activeRectSrcCenter.Y; } //This center is essentially the focal point of the magnified cursor and system cursor Point center = new Point(x, y); Point diff = new Point(p.X - center.X, p.Y - center.Y); //The magnified cursor and the actively controlled cursor are the same point in top left corner of activeRectSrc //As main cursor moves, magnified cursor moves away twice as fast if we return p and do no adjustments //Therefore we need to divide the distance of gaze point from top left corner by zoomFactor to get magnified and gaze point to be same return(new Point(center.X + Convert.ToInt32((float)diff.X / ((float)zoomPct / (float)100)), center.Y + Convert.ToInt32((float)diff.Y / ((float)zoomPct / (float)100))));; }
public Point ClipToBox(Point gp) { //Check if LinkDict is not populated if (ClippedBox == null) { if (!boxesInitComplete || boxes.Count < 1) { return(gp); } //We also want to make sure that the gp is not near the Windows Taskbar, otherwise have difficulty using start menu or switching applications Rectangle workingArea = ScreenPixelHelper.GetScreenWorkingArea(); //We also want to make sure browser navigation buttons can be clicked comfortably int topBar = 105; if (gp.X < workingArea.Left || gp.X > workingArea.Right || gp.X < (workingArea.Top + topBar - 15) || gp.Y > workingArea.Bottom) { winzoomAvailable = true; return(gp); } List <Box> nearby = new List <Box>(); nearby.AddRange(getNearBoxes(gp)); if (nearby.Count == 0) { winzoomAvailable = true; return(gp); } if (nearby.Count == 1)//if no box around, we keep the cursor where it is { //We clip to the center of the clickable element winzoomAvailable = false; ClippedBox = nearby[0]; return(ClippedBox.center()); } else { if (!CheckAllBoxesLargeEnough(nearby)) { winzoomAvailable = true; ClippedBox = null; return(gp); } ClippedBox = findClosestBox(gp, nearby);//closest Box winzoomAvailable = false; return(ClippedBox.center()); } } else //box was previously clipped { /* * if(no box around) * ruturn ClippedBox.center or (-100,-100)either exit or stay * else * if GP is in direction of anotherBox * return changeBox() * else * either exit or stay */ //no other box around, //exit List <Box> otherNearby = getNearBoxes(gp); if (otherNearby.Contains(ClippedBox)) { otherNearby.Remove(ClippedBox); } //remove the clipped box as it is itself if (otherNearby.Count == 0) { return(StayOrExitBox(gp)); } else { if (!CheckAllBoxesLargeEnough(otherNearby)) { //must use winzoom and exit since we've approached a really small box, force exit from box winzoomAvailable = true; ClippedBox = null; return(gp); } if (ClippedBox.ContainsPoint(gp)) { return(ClippedBox.center()); } //Check if gp is contained by any of the otherNearby boxes, and if so is it at least changeBoxPercThresh into it foreach (Box b in otherNearby) { //If it's a large box then a few pixels should be enough to enter it... and for a small box use a small percentage of it if (b.ContainsPointPercentageWithin(ClippedBox, gp, ConfigManager.cursorMagnetClippingChangeBoxIntoPerc) || b.ContainsPointPixelsWithin(ClippedBox, gp, ScreenPixelHelper.ConvertMmToPixels(ConfigManager.cursorMagnetClippingExitThresholdMm)) ) { winzoomAvailable = false; ClippedBox = b; return(b.center()); } } //the gazepoint has not met the criteria for changing to a different box, see if it should stay or exit return(StayOrExitBox(gp)); } } }
//whenever this method is called, it paints from scratch and does not append to what's already on the screen //this method is typically called whenever RefreshScreen is called (60 fps) protected override void OnPaint(PaintEventArgs e) { //Draw overall target circle (which shrinks with duration) int radius = GetTargetCircleRadius(iteration); Point calpoint = ca.adjGrid[currentCircle]; Rectangle rec = new Rectangle(calpoint.X - radius, calpoint.Y - radius, radius * 2, radius * 2); if (iteration == 0) { e.Graphics.DrawEllipse(Pens.White, rec); } else if (iteration < ConfigManager.calibrationIterationCountMax - 1) { e.Graphics.DrawEllipse(Pens.DarkCyan, rec); //also draw inner circles to guide radius = GetTargetCircleRadius(iteration + 1); rec = new Rectangle(calpoint.X - radius, calpoint.Y - radius, radius * 2, radius * 2); e.Graphics.DrawEllipse(Pens.DarkMagenta, rec); } else { e.Graphics.FillEllipse(Brushes.DarkMagenta, rec); e.Graphics.DrawEllipse(Pens.DarkCyan, rec); } //Reset the iterations and calibrating this point if user has already been trying longer than expected if (iteration > ConfigManager.calibrationIterationCountMax + 1) { calstate = CalState.WAITING_FOCUS; iteration = 0; } Point gp = controller.WarpPointer.GetNextPoint(controller.WarpPointer.GetGazePoint()); //detect whether gaze point is close to the calibration circle (at most 7cm of screen away) if (PointHelper.GetPointDistance(gp, calpoint) < ScreenPixelHelper.ConvertMmToPixels(70)) { //draw gray gaze point as long as it's not the final iteration(s) int gazeRadius = ScreenPixelHelper.ConvertMmToPixels(1) / 2; Point p = controller.WarpPointer.GetNextPoint(controller.WarpPointer.GetGazePoint()); p.Offset(ca.adjGridOffset[currentCircle]); rec = new Rectangle(p.X - gazeRadius, p.Y - gazeRadius, gazeRadius * 2, gazeRadius * 2); if (iteration < ConfigManager.calibrationIterationCountMax) { e.Graphics.FillEllipse(Brushes.Gray, rec); if (iteration > 0) { //Get antipoint, which is basically located on other cide of currentCircle int xDiff = p.X - ca.adjGrid[currentCircle].X; int yDiff = p.Y - ca.adjGrid[currentCircle].Y; Point ap = new Point(p.X - xDiff * 2, p.Y - yDiff * 2); rec = new Rectangle(ap.X - gazeRadius, ap.Y - gazeRadius, gazeRadius * 2, gazeRadius * 2); e.Graphics.FillEllipse(Brushes.Gray, rec); } } if (calstate == CalState.WAITING_FOCUS) { StartTimer(); calstate = CalState.FOCUS_IN_PROGRESS; return; } else if (calstate == CalState.FOCUS_IN_PROGRESS) { if (DoneWaitingTime(150)) { calstate = CalState.FOCUSED; } else { return; } } else if (calstate == CalState.FOCUSED) { //Done waiting the focus time and eyes are focussed UpdateCalibrationAdjustmentWithCurrentGaze(); StartTimer(); sampleCollectionStartTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond; calstate = CalState.COLLECTING_SAMPLES; iteration = 0; return; } else if (calstate == CalState.COLLECTING_SAMPLES) { //Done waiting time to start collecting samples //We don't want the gaze to lag across the screen so we trick the user thinking it's centered already if (iteration == 0 || iteration == 1) { UpdateCalibrationAdjustmentWithCurrentGaze(); } if (DoneWaitingTime(ConfigManager.calibrationIterationTimeMs)) { //Check if current gaze point is close to the center of the target circle iteration++; Point wp = controller.WarpPointer.GetWarpPoint(); double pointDistance = PointHelper.GetPointDistance(calpoint, wp); int pointDistanceThreshold = ScreenPixelHelper.ConvertMmToPixels(ConfigManager.calibrationCompletedThresholdMm); UpdateCalibrationAdjustmentWithCurrentGaze(); if (iteration >= ConfigManager.calibrationIterationCountMax && pointDistance < pointDistanceThreshold) { //calibration for this point is successful currentCircle++; if (currentCircle == 9) { ca.writeCalibrationAdjustmentCsv(); currentCircle = 0; Cursor.Show(); this.Close(); } } else { StartTimer(); } this.Invalidate();// This forces the form to repaint } } } else { iteration = 0; calstate = CalState.WAITING_FOCUS; } }
public void Show(Point p, float addedMagnification = 0) { if (active) { return; } Logger.WriteEvent(); active = true; Rectangle screenSize = ScreenPixelHelper.GetScreenSize(); p = BoundPointToRect(p, screenSize, 5); zoomPct = ConfigManager.zoomWindowMagnificationPct + addedMagnification; activeRectPctScreen = ConfigManager.zoomWindowPctScreen; activeRectPaddedPctScreen = activeRectPctScreen + 15; aciveRectSrcPctScreen = (float)activeRectPctScreen * 100 / (float)zoomPct; //Calculate the size and position of the source rectangle float w = (float)screenSize.Width * aciveRectSrcPctScreen / 100; float h = (float)screenSize.Height * aciveRectSrcPctScreen / 100; //Check based on the height, width, and p if we need to shift to fit on screen activeRectSrcCenter = CalculateRectCenterToFitScreen(p, w, h); int xScreen = activeRectSrcCenter.X - Convert.ToInt32(w / 2); int yScreen = activeRectSrcCenter.Y - Convert.ToInt32(h / 2); activeRectSrc = new Rectangle(xScreen, yScreen, Convert.ToInt32(w), Convert.ToInt32(h)); float activeRectWidth = (float)screenSize.Width * activeRectPctScreen / 100; float activeRectHeight = (float)screenSize.Height * activeRectPctScreen / 100; activeRectCenter = CalculateRectCenterToFitScreen(p, activeRectWidth, activeRectHeight); xScreen = activeRectCenter.X - Convert.ToInt32((activeRectWidth / 2)); yScreen = activeRectCenter.Y - Convert.ToInt32((activeRectHeight / 2)); activeRect = new Rectangle(xScreen, yScreen, Convert.ToInt32(activeRectWidth), Convert.ToInt32(activeRectHeight)); //Calculate the padded activeRect so that within this padding the zoombox does not cancel when user looks away float activeRectWidthPadded = screenSize.Width * activeRectPaddedPctScreen / 100; float activeRectHeightPadded = screenSize.Height * activeRectPaddedPctScreen / 100; xScreen = activeRectCenter.X - Convert.ToInt32((activeRectWidthPadded / 2)); yScreen = activeRectCenter.Y - Convert.ToInt32((activeRectHeightPadded / 2)); activeRectPadded = new Rectangle(xScreen, yScreen, Convert.ToInt32(activeRectWidthPadded), Convert.ToInt32(activeRectHeightPadded)); //Allows drawing cursor icons underneath the WinzoomForm. wzuf = new WinzoomUnderlayForm(warpPointer, calibrationAdjuster, this); wzuf.StartPosition = FormStartPosition.Manual; wzuf.WindowState = FormWindowState.Maximized; wzuf.AllowTransparency = true; wzuf.TransparencyKey = wzuf.BackColor; wzuf.TopMost = true; wzuf.Show(); //zbf.BackColor = Color.FromArgb(216,249,107); //a very unusual light green color wzf = new WinzoomForm(this); wzf.magnification = (float)zoomPct / 100; wzf.mag.magnification = (float)zoomPct / 100; wzf.Width = Convert.ToInt32(activeRectWidth); wzf.Height = Convert.ToInt32(activeRectHeight); wzf.StartPosition = FormStartPosition.Manual; wzf.Location = new Point(activeRect.X, activeRect.Y); wzf.mag.SetSourceRect(activeRectSrc); wzf.mag.SetActiveRect(activeRect); wzf.Show(); }