Re: [Mono-dev] AppActivate and System.Windows.Forms.SendKeys on Ubuntu 10.10
To make a long mail short, that's incorrect. When you look at xvkbd-3.0, focus a window and simulate alt+f4, it closes, and with simulated alt + tab, it switches windows. Looking at its sources, it's not working with XSendEvent there however, it uses some magic in libxtst, which however, just all comes back to some wrapping around base X11 calls. I didn't look any closer at it, as I don't deem ALT+TAB and ALT+F4 as important in respect to SendKeys. Sending key combinations + key modifiers (ALT/CTRL) to other application however, is. Thus I attached fixme.c, a basic key dispatch implementation for Linux/X11 in C using XSendEvent. It's probably still a bit buggy, especially in respect to "UNICODE"/KeyboardInternationalization (not really important in this respect IMHO). I'll probably port it to CS next weekend. Note that it also contains an AppActivate implementation for Linux ! (It doesn't yet switch to the appropriate workspace, but fixing that is rather simple, but unfortunately time-consuming, and as I don't need it, I have just commented that part out for now) AppActivate for Windows is simple, just pinvoke SetActiveWindow. I don't have a Mac, but the simplest way to activate a window there I found to be so easy I can implement it blindly: [System.Runtime.InteropServices.DllImport("libc", EntryPoint = "system")] internal extern static int system(string strCommand); Note that in the below C snippet, one would still need to check for malicious \n\r or semicolons when the application title is being supplied as parameter. - #include #include int main(int argc, char* argv[]) { // http://stackoverflow.com/questions/3313332/bringing-another-apps-window-to-front-on-mac-in-c system("osascript -e \"tell application \\\"Address Book\\\" to activate\""); return EXIT_SUCCESS; } On 03/17/2011 03:19 AM, Jonathan Pryor wrote: > Now, what does X11 provide? A cursory glance shows XSendEvent: > http://tronche.com/gui/x/xlib/event-handling/XSendEvent.html > > This allows passing an XEvent, such as an XKeyEvent, to a given window. > > Problem: In Windows, it's the operating system which handles the input, which > thus allows OS "capturing" of Alt+Tab so that the active application is > switched. In X11, XSendEvent() requires that you explicitly specify both the > Display and Window that the event is being passed to. Consequently, there is > NO MECHANISM to have Alt+Tab "captured" by the OS and thus change windows > (even if Alt+Tab _will_ change windows when typed via the keyboard). This is > because the WIndow Manager is grabbing Alt+Tab, but the Window Manager is a > completely separate process, and there's not necessarily an easy way to grab > the Display+Window for the Window Manager (which might not have a Window to > begin with). #include #include #include #include #include //#include //#include #include // xprop // Compile using: // gcc -o sendmsg sendmsg.c -L/usr/X11R6/lib -lX11 #define _NET_WM_STATE_REMOVE0/* remove/unset property */ #define _NET_WM_STATE_ADD 1/* add/set property */ #define _NET_WM_STATE_TOGGLE2/* toggle property */ static int client_msg(Display *disp, Window win, char *msg, unsigned long data0, unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4) { XEvent event; long mask = SubstructureRedirectMask | SubstructureNotifyMask; event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.message_type = XInternAtom(disp, msg, False); event.xclient.window = win; event.xclient.format = 32; event.xclient.data.l[0] = data0; event.xclient.data.l[1] = data1; event.xclient.data.l[2] = data2; event.xclient.data.l[3] = data3; event.xclient.data.l[4] = data4; if (XSendEvent(disp, DefaultRootWindow(disp), False, mask, &event)) { return EXIT_SUCCESS; } else { fprintf(stderr, "Cannot send %s event.\n", msg); return EXIT_FAILURE; } } static int activate_window (Display *disp, Window win) // , gboolean switch_desktop) { unsigned long *desktop; /* // desktop ID if ((desktop = (unsigned long *)get_property(disp, win, XA_CARDINAL, "_NET_WM_DESKTOP", NULL)) == NULL) { if ((desktop = (unsigned long *)get_property(disp, win, XA_CARDINAL, "_WIN_WORKSPACE", NULL)) == NULL) { p_verbose("Cannot find desktop ID of the window.\n"); } } if (switch_desktop && desktop) { if (client_msg(disp, DefaultRootWindow(disp), "_NET_CURRENT_DESKTOP", *desktop, 0, 0, 0, 0) != EXIT_SUCCESS) { p_verbose("Cannot switch desktop.\n"); } g_free(desktop); } */ client_msg(disp, win, "_NET_ACTIVE_WINDOW", 0, 0, 0, 0, 0); XMapRaised(disp, win); return EX
Re: [Mono-dev] AppActivate and System.Windows.Forms.SendKeys on Ubuntu 10.10
On Mar 16, 2011, at 4:07 PM, Quandary wrote: > What, only SendKeys to WinForms, are you serious ? > That doesn't make much sense. It makes perfect sense. > It sends KeyEvents to the Windowing system, which happens to be the > WinAPI on Windows, or X11 on Linux for all intents and purposes. > GTK has nothing to do with it. > > You send the keyboard keys as simulated input to X11, and before that, > you set the focus window. The problem is that there is no such mechanism in X11, at least not in a way that can be used in a straightforward fashion. For example, Microsoft's SendKeys.Send() method is _probably_ implemented in terms of the SendInput() WinAPI function: http://msdn.microsoft.com/en-us/library/ms646310(VS.85).aspx So SendKeys.Send() presumably maps the input string into a set of INPUT structures, then sends the structures to SendInput() so that the operating system will interpret them. Note that this is _very_ low level, working at the keyboard level, not the thread event loop level. One of the things that this allows is that SendKeys.Send("%{TAB}") (aka Alt+Tab) will change the active window. Now, what does X11 provide? A cursory glance shows XSendEvent: http://tronche.com/gui/x/xlib/event-handling/XSendEvent.html This allows passing an XEvent, such as an XKeyEvent, to a given window. Problem: In Windows, it's the operating system which handles the input, which thus allows OS "capturing" of Alt+Tab so that the active application is switched. In X11, XSendEvent() requires that you explicitly specify both the Display and Window that the event is being passed to. Consequently, there is NO MECHANISM to have Alt+Tab "captured" by the OS and thus change windows (even if Alt+Tab _will_ change windows when typed via the keyboard). This is because the WIndow Manager is grabbing Alt+Tab, but the Window Manager is a completely separate process, and there's not necessarily an easy way to grab the Display+Window for the Window Manager (which might not have a Window to begin with). In short, you can't get there from here, as the entire X11 architecture is ~completely different. > At least on Windows. Exactly. On Windows, everything uses the same WinAPI message looping mechanism. On X11, very little is consistent across toolkits, and X11 doesn't specify much (leaving it up to the Window Manager + applications + ... to work out the details). Then there's OSX, which uses yet another completely different mechanism. SendKeys.Send() is inherently Windows specific; you should be glad it works for System.Windows.Forms apps at all. - Jon ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list
Re: [Mono-dev] AppActivate and System.Windows.Forms.SendKeys on Ubuntu 10.10
What, only SendKeys to WinForms, are you serious ? That doesn't make much sense. The SendKeys function is just a static method that resides in System.Windows.Forms, and has nothing to do with WinForms otherwise. It sends KeyEvents to the Windowing system, which happens to be the WinAPI on Windows, or X11 on Linux for all intents and purposes. GTK has nothing to do with it. You send the keyboard keys as simulated input to X11, and before that, you set the focus window. X11 processes it, and forwards the input to the respective application's handlers/callbacks. Using it works with everything, GTK+/WinForms/QT/wxWidgets/Java etc., since it's just the same as if you press a keyboard key. At least on Windows. And if mono doesn't, that's a bug and needs to be fixed. SendKeys is the only way to steer a 3rd party applications if every other method fails or isn't implemented applicationwise. If it was a WinForms application, it would mean it's written in C#, which would mean I could just automagically reverse engineer it and recreate a console application instead of resorting to sendkeys. On 03/16/2011 08:07 PM, Bojan Rajkovic wrote: > > Erm, I don't think SendKeys for WinForms is going to work against !WinForms > apps on Linux. gEdit is GTK+, so the mainloops don't match at all, and gEdit > likely isn't expecting any keys from Mono. > > —Bojan ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list
Re: [Mono-dev] AppActivate and System.Windows.Forms.SendKeys on Ubuntu 10.10
On Mar 16, 2011, at 8:37 AM, Quandary wrote: > Hi, > > Question: > Is System.Windows.Forms.SendKeys implemented and working on Ubuntu Linux ? > > I try to control JD-GUI with it, but the keys don't arrive, neither do they > arrive in gedit. > They do arrive in Notepad on Windows using the same program, and they work > with JD-GUI on Windows, using the same program. > > Or does it need any library installed, such as XTest/XFakeEvent ? > > > And BTW, Microsoft.VisualBasic.Interaction.AppActivate("Window Title") throws > not implemented... > > You can use the functions: > static Window FindWindow(Window top, char *name) > static void GetFocusedWindow(void) > From xvkbd -> in file xvkbd.c > Basically, all you need to do is save the mouse position, find the target > window position & rectangle, and press the left mousebutton somewhere on it > with mousedown & mouseup via xsendevent, then restore the mouse position. > > I can supply left + right mousedown + mouseup, > I have appended cMouse.cs and the dependencies: XorgAPI + XorgStructs. > > And when I loop through all processes, as shown below, I don't get a > WindowTitle anywhere... > (using mono 2.10.1 on Ubuntu) > > > public void GetProcesses() > { > System.Diagnostics.Process[] processlist = > System.Diagnostics.Process.GetProcesses(); > > string str = ""; > foreach(System.Diagnostics.Process theprocess in processlist) > { > Console.WriteLine("Process: {0} ID: {1} WindowTitle: {2}", > theprocess.ProcessName, theprocess.Id, theprocess.MainWindowTitle); > str += string.Format("Process: {0} ID: {1} WindowTitle: {2}", > theprocess.ProcessName, theprocess.Id, theprocess.MainWindowTitle); > str += Environment.NewLine; > } > MessageBox.Show(str); > } > > > > ___ > Mono-devel-list mailing list > Mono-devel-list@lists.ximian.com > http://lists.ximian.com/mailman/listinfo/mono-devel-list Erm, I don't think SendKeys for WinForms is going to work against !WinForms apps on Linux. gEdit is GTK+, so the mainloops don't match at all, and gEdit likely isn't expecting any keys from Mono. —Bojan ___ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list