kenknight
  • kenknight
  • 51.2% (Neutral)
  • Nestling Topic Starter
2008-10-03T20:47:50Z
Hi Timothy,


Quick question which you obviously have figured out the answer to. I use your RD tabs on a daily basis and have to say it is absolutely stellar. I'm writing an msrdp based app and have encountered and issue when minimizing the app and coming back the activex of rdp loses focus and you have to hit the tab key to get into control. I have tried to issue a sendkey function, but this appears to cause the program to hang after you minimize and restore a few times. How do you handle getting focus back into the control.

I apologize if this isn't the type of question you'd normally answer, so just let me know.

Thanks,
Ken
Timothy
  • Timothy
  • 100% (Exalted)
  • Flock Leader
2008-10-04T08:25:42Z
That particular problem stumped me for quite a while. I had a very elaborate set of catches before finally coming up with an elegant solution.

What you want to do is invoke focus on the RDP ActiveX control directly. I'm not sure what language you are using, but if you are using .Net, let's say your control is named AXRdpControl. You would then simply do AXRdpControl.Focus(). This restores input focus to the client session.

Now, the best way to detect when you need to do this is by listening for when the hosting application is activated. Activation is different from listening for input focus (which is a normal .Net event called GotFocus). Activation is global to the app. Anytime a user clicks into an app that they were not already inside, it will fire this event. However, this event is not wrapped by .Net, so you have to listen to the message pump directly. The best way to do that is to override WndProc on your application's form. The event to listen for is WM_ACTIVATE, which is numerically 6. This event fires anytime the application's activation state changes, so you need to analyze what the state is when the event fires, which is stored in the WParam. Look for any value other than WA_INACTIVE (which is 0) to fire the .Focus(). (There can be multiple ways to activate the form, so it's easier to look for NOT WA_INACTIVE.)

Hope this helps!
kenknight
  • kenknight
  • 51.2% (Neutral)
  • Nestling Topic Starter
2008-10-04T22:10:18Z
Thanks a bunch. Yes this does indeed help, however, I'm curious. I'm instantiating the "Microsoft Terminal Services Client Control (redist)" and I don't see the .focus() .... actually I'm not finding any focus. I wonder if it is an inherited method from windows control.

I develop in a few different languages, Delphi / Windev / Visual Studio. This project is in WinDev, however, you're pointer to WM_ACTIVATE, has allowed me to solve the problem. Although it is not as elegant as the simple .getFocus() call. I am essentially wParam = 2097153 OR wParam = 2097152 and then I use a function in WinDev SetFocus(AXRDPControl) and then SendKey("{TAB}").

Thanks for the pointer.

Cheers!
Ken
Timothy
  • Timothy
  • 100% (Exalted)
  • Flock Leader
2008-10-05T01:11:36Z
If you are using .Net, all controls inherit from a control base class that contains .Focus and it becomes a part of the Terminal Services Client Control via the COM wrapper class (which inherits from the control base class).

Good luck with everything!
Timothy
  • Timothy
  • 100% (Exalted)
  • Flock Leader
2008-10-06T14:39:38Z
I was wrong a little bit. I was confusing two different parts of RD Tabs. I checked the source and here's what I'm doing for focus.

.Net has OnActivated() and OnDeactivate() events in all Windows Forms. I'm using the OnActivated to set focus to the current control inside the current form. The WndProc stuff I showed above is for activation and deactivation of the entire application. In other words, when all RD Tabs forms are deactivated or when any RD Tabs form is activated.

Here's the code for the OnActivated() and OnDeactivate() events...


  Protected Overrides Sub OnActivated(ByVal e As System.EventArgs)
    MyBase.OnActivated(e)

    If Me.TabManagerMain IsNot Nothing Then
      Me.TabManagerMain.IsThisPanelActivated = True   ' Property which notifies the tab manager control that it has been activated

      ' If the parent page group inside the tab manager is created...
      If Me.TabManagerMain.PageGroupSplitter1 IsNot Nothing Then
        ' Set focus from the top control down in the tab split tree
        Me.TabManagerMain.PageGroupSplitter1.SetFocusFromTopControl()
      End If

      ' Notify the active page (from the above step) to force itself to grab input focus 
      If Me.TabManagerMain.ActivePage IsNot Nothing Then
        Me.TabManagerMain.ActivePage.RaiseSetFocusToMeEvent()
      End If
      
      ' Refresh all the tab panels since some of the drawing code may have been suspended partially above
      Me.TabManagerMain.RefreshAllTabPanels()
    End If
  End Sub

  Protected Overrides Sub OnDeactivate(ByVal e As System.EventArgs)
    MyBase.OnDeactivate(e)

    If Me.TabManagerMain IsNot Nothing Then
      Me.TabManagerMain.IsThisPanelActivated = False
    End If
  End Sub


The latter is useful for other scenarios (such as knowing when to unhook the keyboard/mouse, which is how I'm using it), so here's the code...


  Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
    If m.Msg = &H1C Then ' This message (&H1C) indicates that the app went active or inactive
      Me._appActive = (m.WParam.ToInt32() <> 0)
      If Me._inputHook IsNot Nothing AndAlso My.Application.FinishedLoading Then
        If Me._appActive Then
          Me._inputHook.Start(My.Settings.EnableMouseHook, My.Settings.EnableKeyboardHook)
        Else
          Me._inputHook.Stop(True, True, False)
        End If
      End If
    End If
    MyBase.WndProc(m)
  End Sub