Global available contextual menu entry under windows possible?

Hi all,

at work we are using Grandstram IP Phones. These phones allow to start a call via a HTTP API call.

I build a small app, that allows to manually enter a phone number and the app builds the URL and calls it via a hidden HTMLViewer.LoadURL.

That works great, but I have to manually enter the phone number to call.

What I would like to achieve:

Adding a global accessible context menu under windows, that is available whatever application is currently active (Word, Outlook etc.).
When clicked, send whatever is currently selected to my app, do a bit of number formatting and initiate the call.

That would allow to call any selected phonenumber from any application (e.g. Email in outlook).

Is this possible to do?

If yes, how?

Don’t need code just pointers into the right direction.

Thanks
Stefan

You could have an app running in the background with no taskbar icon that triggers a menu when a certain key combination is used. That can be done with a simple timer that looks at Keyboard.KeyDown.

Win32 enables you to detect the screen top window/application ; it should not be too difficult to get it and look for selected text on it. All that seems possible with declares.

It may be possible to catch the selection in Win32 with EM_SETSEL https://msdn.microsoft.com/en-us/library/windows/desktop/bb761661(v=vs.85).aspx

Another, very simple approach is, upon MouseUp or Ctrl-A and other possible selection :

  • Store the content of the clipboard
  • use SendKeys to send Ctrl-C
  • Restore the previous clipboard content
  • Check the content of the catched text

You need to get the forefront window and then use Sendkey :

Declare Function GetForegroundWindow Lib "User32" () as Integer

https://forum.xojo.com/6009-sendkey-function/0

OK Thanks, will try.

looks promissing.

I am able to catch keydown in timer event. And also to get current content of clipboard.

But I am struggling to get the foreground window and send ctrl+C to copy current selection to clipboard. Can you provide a bit of code :slight_smile: As I am not used to use declares?

in timer action event I have

  If keyboard.AsyncAltKey and Keyboard.AsyncKeyDown(123)  then
    // handle the keyboard event here....    currently alt + left key for testing
    
    //Declare Function GetForegroundWindow Lib "User32" () as Integer
    
   // to do here: get foreground window an send ctrl+c to copy current selection to clipboard

    Dim c As New Clipboard
    Dim s As String
    s = c.Text
    c.Close
    
    // for test show clipboard content
    MsgBox s     

   // to do: use clipboard content, check if phonenumber / formate phonenumber
   //            use phonenumber in make call function
  end if
  

Thanks

OK I managed to get the ID of the foreground window using above declare.

What do I do with it?

How do I send ctrl+C to that window?

Thanks

[quote=257191:@Stefan Zilz]looks promissing.

I am able to catch keydown in timer event. And also to get current content of clipboard.

But I am struggling to get the foreground window and send ctrl+C to copy current selection to clipboard. Can you provide a bit of code :slight_smile: As I am not used to use declares?[/quote]

You asked for pointers, I did not realize you needed assistance with the actual code.

For declares, you may want to avail yourself of the great book from Eugene Dakin :
https://forum.xojo.com/27443-i-wish-i-knew-how-to-implement-win32-declares-with-xojo-on-wind/0

You need to use the function that is declared, then employ Sendkeys to plug Ctrl-C into the keyboard in order to copy whatever is selected.

Have you read the thread about SendKey I linked to ?

The way it goes is

  • Use Xojo Clipboard to store the current clipboard content
  • GetForegroundWindow : gives you the handle of the top window
  • GetWindowText : gives you the title of the top window
    https://msdn.microsoft.com/en-us/library/windows/desktop/ms633520(v=vs.85).aspx
  • Sendkey : send Ctrl-C to the top window
  • Use Xojo clipboard to get the selected text on the top window
  • Use Xojo ClipBoard to restore the content of the clipboard prior to Ctrl-C
  • Do whatever you need to display menu and dial

I believe WFS (Windows Functionality Suite) should have most of the needed declares. I will look into it later when I have some time.

[quote=257209:@Michel Bujardet]You asked for pointers, I did not realize you needed assistance with the actual code.
[/quote]

Yep, but now I realized, that I might need some help inf form of code :slight_smile:

Yes, I read it. But did not understand how to use it though

Done

Done: I do have the integer ID of the window now

How and why?

How?

No problem once I have ctrl+c send to the foreground window

[quote=257209:@Michel Bujardet]
I believe WFS (Windows Functionality Suite) should have most of the needed declares. I will look into it later when I have some time.[/quote]
Thanks very much

You REALLY want to read how Sendkey works at https://forum.xojo.com/6009-sendkey-function/0 and EXPERIMENT with the code marked as answer in the first post.

Sendkey needs the title of a window to send it Ctrl-C. Hence the need for GetWindowText.

I tried to describe the process. Now you got to walk the walk.

For the book “I Wish I Knew How To… Implement Win32 Declares With Xojo on Windows”, don’t simply read it. Try what is described into it.

I am sorry, but you have to learn to swim before diving into code.

OK Understand.

Just in case someone else needs to get the Title of a Window (Active or Foreground) this is the function I come up with

Function Win32GetWindowsTitle(type as string) As String
  // Function that returns the Title of a window on Windows
  // Passed Type 
  // "A" returns title of the Active Window
  // "F" returns title of the foregrounf window
  
  Declare Function GetForegroundWindow Lib "User32" () as Integer
  Declare Function GetActiveWindow Lib "User32" () as Integer
  Declare Function GetWindowText Lib "User32" Alias "GetWindowTextW" (HWND As Integer, Buffer As Ptr, BufferSize As Integer) As Integer
  
  Dim HWND As Integer
  Dim mb As New MemoryBlock(255)
  
  select case type
  case "A"
    HWND = GetActiveWindow
  case "F"
    HWND  = GetForegroundWindow
  case else
    HWND  = GetActiveWindow
  end Select
  
  
  Call GetWindowText(HWND, mb, mb.Size)
  return mb.WString(0).Trim
  
End Function

So finally I have a basic version running :slight_smile:

I use a timer in multimode to trigger special keydown (ctrl + Y).
Timer Action Event stops timer, stores current clipboardcontent for later restore, identifies foreground window and sends crtl+c to that window (using sendkey("^©") and finally fires a second timer in single mode.

singlemode timer gets the new clipboard content, restores the old clipboard content and starts time one again.

I needed to use a second timer, because otherwise, the sendkey and clipboard content was not updated correctly in all cases.

Thanks Michel for your help in pointing me to the correct direction.

Next to do:

  • some string magic to build a correct phone number (e.g. removing spaces, replace “+” with “00”, escape unneeded numbers e.g “(0)” in case string starts with 00

Using a shortcut to trigger all that is still a bit laggy (timer is set to 100 ms) and not always recognized …

So if someone has an idea how to implement a contextual menu entry, that is globally shown and useable although my app is not the active app, it is much appreciated.

Thanks
Stefan

[quote=257284:@Stefan Zilz]So finally I have a basic version running :slight_smile:
…/snip/…
So if someone has an idea how to implement a contextual menu entry, that is globally shown and useable although my app is not the active app, it is much appreciated.
[/quote]

You should be able to the code here https://forum.xojo.com/4603-make-a-window-topmost/0 to make you app top, and then reinstate the app that was top before. If all you want is to show a Contextual menu, use a 1x1 pixel window to show it from there.

Good Idea but I doubt this would work.

I want to select a bit of Text in e.g. an Outlook Mail, hit right mouse over the selection and call my Phone Function. Therefore I need a “Call with…” entry in context menu that is available whenever there is selected text and my app is not active.

Before saying something won’t work, it is usually better to try it.

That said, it may not be necessary. Apparently, displaying a contextual menu from an app that is in the background seems to work, and relinquish control to the front app after it is dismissed.

See Popup at http://documentation.xojo.com/index.php/Menuitem

Make the menuItem a property of app or window, and use addhandler to attach a method to it to get the result.

How will that integrate my menu item into the context menu of e.g. Outlook?

I do not want to replace the complete context menu of e.g. Outlook, I want to call a function of my app from the active front App.

Anyhow I will try it out

I tried with an app that has no window and used a timer. The contextual menu pops next to the cursor.

But I did not try to use right click. I would think it maybe wise to use a keyboard shortcut instead, as you won’t have access to Outlook contextual menu.

Just try.

BTW you can suppress the icon in the taskbar with the code here
https://forum.xojo.com/13817-creating-an-application-with-no-taskbar-icon/0

[quote=257319:@Michel Bujardet]I tried with an app that has no window and used a timer. The contextual menu pops next to the cursor.

But I did not try to use right click. I would think it maybe wise to use a keyboard shortcut instead, as you won’t have access to Outlook contextual menu.

Just try.[/quote]

Yeah, I feel using a shortcut is my best option. I don’t see any way to have a function of my app triggered from outside my app (Except catching a shortcut with a timer).

Anyhow thanks a lot for your help.

I just though about something else : display your contextual menu above the cursor when right click is pressed. The regular right click menu will be displayed below, so you can have both.

MenuItem.Popup has optional X and Y parameters, so you can chose where it appears.
http://documentation.xojo.com/index.php/MenuItem.Popup

Good Idea, but the Front App’s menu is positioned based on the “context” above, below, right, left from current mouse position. Where ever is enough space to show the menu…