puklaus's picture

PointToClient()

I need to convert screen coordinates to the window and PointToClient() method isnt
implemented but only on windows.

So, here's linux code (mono's windows.forms sources was useful http://anonsvn.mono-project.com/viewvc/trunk/mcs/class/Managed.Windows.F...):

To X11GLNative.cs

#region PointToClient
 
static object XlibLock=new object(); // ?
public void PointToClient(ref System.Drawing.Point p)
{
   int	ox, oy;
   IntPtr child;
 
   lock (XlibLock) { // dont know what that means
	Functions.XTranslateCoordinates(window.Display, window.RootWindow, window.WindowHandle, p.X, p.Y, out ox, out oy, out child);
   }
   p.X = ox;
   p.Y = oy;
}
#endregion

And here mac code, cant test it and it is most likely not yet right
but if anyone can test/fix it, great:

To CarbonGLNative.cs:

        #region PointToClient
        public void PointToClient(ref System.Drawing.Point p)
        {
            // not sure. this should be the same as linux  window.WindowHandle  (if i understand that correctly) ...
            IntPtr handle = window.WindowRef;
 
            System.Drawing.Point t = new System.Drawing.Point(p.X, p.Y);
            System.Drawing.Point point = Carbon.API.ConvertScreenPointToClient(handle, t);
            p.X = point.X;
            p.Y = point.Y;
        }
        #endregion

And in CarbonAPI.cs, in API class:

        public static System.Drawing.Point ConvertScreenPointToClient(IntPtr handle, System.Drawing.Point point)
        {
            System.Drawing.Point converted_point = new System.Drawing.Point();
            Carbon.Rect window_bounds = new Carbon.Rect();
            Point native_point = new Point();
 
            Carbon.API.GetWindowBounds(handle, WindowRegionCode.StructureRegion /*32*/, out window_bounds);
 
            native_point.H = (short)(point.X - window_bounds.X);
            native_point.V = (short)(point.Y - window_bounds.Y);
 
            HIViewConvertPoint(ref native_point, IntPtr.Zero, handle);
 
            converted_point.X = (int)native_point.H;
            converted_point.Y = (int)native_point.V;
 
            return converted_point;
        }
        [DllImport("/System/Library/Frameworks/Carbon.framework/Versions/Current/Carbon")]
        extern static int HIViewConvertPoint(ref Point point, IntPtr pView, IntPtr cView);

Yup and it compiles but not tested otherwise.

Here http://dhost.info/haima/pointtoclient.7z you can find little test and compiled exe (and modificated opentk), it
works on win and linux..
In this test, it opens opentk window and when pressing space, it puts mouse pointer center of it.

And one more thing:

            // pointer to middle of the window
            if (Keyboard[Key.Space])
            {
                Point p=new Point(300, 200);
 
                Point pos = PointToClient(p);
                pos.X = Width - pos.X;    // that I down get, why i must decrase from width(and height) these positions..
                pos.Y = Height - pos.Y;
 
                System.Windows.Forms.Cursor.Position = pos;
            }

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Many thanks for the code, I will add it to OpenTK.

As far as I can tell, the issue is that the calculation only considers the client area, without taking into account the window decoration. I'll have to check to make sure, however.

kanato's picture

Yes, that code for the mac most certainly won't work, since HI methods generally take HI structures, like HIPoint whose members are floats instead of shorts. Fiddler, if you commit that code I will tidy up the mac parts of it tonight.

the Fiddler's picture

Committed (rev. 1740) with slight modifications:

  1. HIPoint instead of Point in HIViewConvertPoint.
  2. Modified API to match Windows.Forms.Control.PointToClient.

Kanato, please take a look - I don't have the means to test Mac OS X code here.

kanato's picture

Well, apparently using the functions HIViewConvertPoint and/or HiPointConvert are not straightforward.

How are you getting your screen coordinates? I have done some testing with System.Windows.Forms.Cursor.Position and it seems to return weird values to me that I don't understand yet. In my testing, the origin was to the left of the center of the screen. This might be a bug in Mono's WinForms but I am unsure at this point.

puklaus's picture

I updated that test in the first post.

Crashes on mac (tested by someone else):
Unhandled Exception: OpenTK.Platform.MacOS.MacOSException: Error Code: -30599
at OpenTK.Platform.MacOS.Carbon.API.HIViewConvertPoint (IntPtr handle, HIPoint point)
.
.

Dont know about screen coordinates, had no need to read them (only setting new position, used window coords to read), but
on windows, 0,0 is top left corner.

kanato's picture

Wait, it sounds like what you want should be PointToScreen. If the client area of your window is sized (600,400), then (300, 200) is the center of your window in client coordinates. But to move the mouse by setting Cursor.Position, you need screen coordinates. So you have to convert from client space to screen space. Is that right?

puklaus's picture

Hmm..I think that a little.
I want center of the window, because I coded "mouse grabbing" I mean put mouse pointer center of the window, calculate
deltas on next frame and then center it. Then you need to know client's coords (not screen coordinates)
(well, its calculated WITH borders and topbar so it must be calculate when you want it center of the window (like when I put cursor center, then calculate deltas and again middle, must add this correction these values)) (its quite hack, what i did but it works).. "mouse grabbing" (?) or something like that.

And when you can read coordinates, mouse position must be in that window, so it must centered every frame.
I think..

kanato's picture

In your example you have this line:
System.Windows.Forms.Cursor.Position = pos;

Cursor.Position expects coordinate to be in screen space. So you have to convert the point in the center of your window in client coordinates (width / 2, height / 2) to screen space coordinates in order to set the position of the cursor to the center of your window. The function which does that conversion should probably be called PointToScreen. The equivalent function in windows.forms.control is called PointToScreen.

I am noticing that from doing testing on windows, this PointToClient function returns coordinates with the origin in the lower-right hand corner, with positive X going left and positive Y going up. (puklaus, this is why you have to subtract your values from width and height.) Is this the intended behavior for PointToClient? I would think the origin should be in either the top-left (consistent with windowing API's) or bottom-left (consistent with OpenGL's usual coordinate system).

Edit: After thinking about it more, I think this really should be consistent with the value returned by Mouse.X and Mouse.Y, so the origin should be in the upper-left hand corner.

puklaus's picture

" coordinates with the origin in the lower-right hand corner, with positive X going left and positive Y going up."

I havent checked never that, thats why must decrase from width(and height) position.
Dont get it why this the behavior, but no more about that if it works :)

Mac OSX support is the one what I need (so crossplatform support) on that axiom platform.input plugin,
thats the method i use to "mouse grabbing" on window and fullscreen. ..

m wondering maybe code check if its mac then not use that method and old way (which isnt grabbing on window)
but else using that... havent patched my code yet but maybe we correct this on mac first so no need to make "hack".

Sorry, any help on that issue, i cannot provide :/

(if i can get my brother here with mac (now he is little time on town), someday, i will try make this work, but i dont know if he have time,wants come here, so ...)

kanato's picture

Ok, I've fixed PointToClient in the trunk. The coordinates are correctly relative to the upper-left hand corner of the window, so you don't need to subtract them from width and height. I've tested this on Windows, Linux and Mac OS X. I also implemented PointToScreen to do the inverse transform.