Board index » cppbuilder » Tab and arrow keys not working in TActiveForm in BCB6

Tab and arrow keys not working in TActiveForm in BCB6

This is a very large problem that I have not found a satisfactory solution
for as of yet.  I am creating a test application which is the groundwork for
future development of an ActiveX library that will be launched via the web.
In my simple testing I have placed two buttons and an edit box on a
TActiveForm descendant and deployed the library.  When I test my control on
my server and attempt to tab between any of the focused controls the focus
instead changes to the IE address bar and back again.

From my readings on this subject using Google this is a well known bug (at
least to the Borland users it is) and exists in BCB5, BCB6, Delphi 5, and
Delphi 6.  However, I have never found one recommendation that solves this
problem (at least not with the instructions provided).  I have read many
posts that claim to solve the problem but when I implement these workarounds
there is either no change or I receive an AV within IE.

The BDN article on this subject leaves a lot to be desired with its one
sentence "solution" which basically says I will need to create custom
controls for every control I intend to use (TEdit, TButton, TCombo, etc) and
add a CM_WANTSPECIALKEY message handler.  Though, I doubt this solution will
actually work since controls that already respond to this message (TMemo for
example) also suffer from the same problem of not being able to capture Tab
or arrow key messages.

Can anyone direct me to a link or posting that definitively works around
this bug?  This is a show-stopper for this development project and I
appreciate any assistance that can be provided.

TIA,
- Clayton

 

Re:Tab and arrow keys not working in TActiveForm in BCB6


Quote
"Clayton Arends" <claytonare...@hotmail.com> wrote in message

news:3eb897bc$1@newsgroups.borland.com...

Quote
> I have never found one recommendation that solves
> this problem (at least not with the instructions provided).

I've seen examples posted many times before over the years.  Have you tried
going to http://www.deja.com and searching through the archives of these
groups?  This topic has been discussed many many times before.

If that doesn't help then please post examples of the things you've actually
tried that don't work for you.

Quote
> The BDN article on this subject leaves a lot to be desired
> with its one sentence "solution"

Which article are you referring to exactly?  Please be more specific.

Quote
> which basically says I will need to create custom
> controls for every control I intend to use
> (TEdit, TButton, TCombo, etc) and add a
> CM_WANTSPECIALKEY message handler.

You don't need to create new controls in order to do that.  Just subclass
the WindowProc property of the existing controls instead.

Gambit

Re:Tab and arrow keys not working in TActiveForm in BCB6


"Remy Lebeau (TeamB)" <gambi...@yahoo.com> wrote in message
news:3eb8a96f$1@newsgroups.borland.com...

Quote
> I've seen examples posted many times before over the years.  Have you
> tried going to http://www.deja.com and searching through the archives of
> these groups?  This topic has been discussed many many times before.

The research I performed on Google is what I mentioned in the second
paragraph of my post.  I have tried all proposed fixes with no success.

Quote
> If that doesn't help then please post examples of the things you've
> actually tried that don't work for you.

It is a hello world application with three controls (Edit, Button, Memo).
The only code that I've tried adding are the suggestions to fix the problem.
Here are my reference links on Google listed with the results (some of the
links wrap lines so reconstruct as necessary):

Suggestion: Add message handler for CN_KEYDOWN to active form
Reference: http://groups.google.com/groups?selm=3cc54f84_2%40dnews
Result: Message handler for active form is never invoked.  It is invoked for
the control but changing the message result has no effect.

Suggestion: Reimplement some OLE methods?
Reference:
http://groups.google.com/groups?selm=7ng8qb%24fmc%241%40nnrp1.deja.com
Result: The suggestion is quite incomplete.  No helpful code or reference.

Suggestion: Override WantChildKey() in active form and return false.
Reference: (can't find the original Google reference)
Result: WantChildKey() does not appear to ever be invoked.

Suggestion: Read the article for the three suggestions.
Reference:
http://groups.google.com/groups?selm=8e05kb%24p8r%241%40dcaparas550.i...
Result: This one is an overview of why the problem exists and discusses some
potential solutions.  Again, no code and no steps.

Suggestion: Several notes in this thread (which really are referring to
another thread).  Chris mentions a windows hook approach which isn't
referenced.  Alex refers to a subclassing approach (which I found ... see
below).
Reference:
http://groups.google.com/groups?threadm=8l6qrm%24iff1%40bornews.borla...
Result: Alex's approach doesn't appear to work for this scenario according
to Richard.

Suggestion: This is the subclass method mentioned above.
Reference:
http://groups.google.com/groups?&selm=3952806C.187FEAE0%40jetsuite.com
Result: Alex's suggestion is for mouse wheel message.  It also doesn't
appear to really apply to TActiveForm since it uses a FormShow method which
doesn't exist to an active form.  I tried the modified code supplied by
Richard which didn't appear to solve the problem either.  If I subclass the
wrong parent then an AV will occur.

Suggestion: Look at referenced Microsoft articles to fix the problem.
Reference: http://groups.google.com/groups?selm=3afa3b23_1%40dnews
Result: This looks promising however I can't find the InPlaceActivate()
function mentioned in the first article.  And I cannot interpret the ATL in
the second article to add the code to my Borland project.  I have searched
for the Borland converted code for this second article and have been
unsuccessful.

Many of the articles that I found are for Delphi developers.  Some of the
fixes mention TOleContainer or TOleControl as the base class for the active
form.  This is not the base class that BCB uses so I do not know if the
suggestions apply or where the code should be added.  Though I did try them
with no success.

Quote
> Which article are you referring to exactly?  Please be more specific.

It is the only article I have found on BDN that refers to this problem.  Use
the following link to see it:
http://bdn.borland.com/article/0,1410,29013,00.html

There is a second article that is referred to in the Google links above but
it applies to the reverse scenario ... placing an IE ActiveX control onto a
Borland application form.

Quote
> You don't need to create new controls in order to do that.  Just subclass
> the WindowProc property of the existing controls instead.

Quite true, however, even when I did create a test control that handled this
message I couldn't get any of the special keys to act correctly.
Additionally, if you read the article above you will see that it doesn't
describe what to do with the message.

- Clayton

Re:Tab and arrow keys not working in TActiveForm in BCB6


Quote
"Clayton Arends" <claytonare...@hotmail.com> wrote in message

news:3eb897bc$1@newsgroups.borland.com...

Quote
> This is a very large problem that I have not found a satisfactory solution
> for as of yet.

I found a reference which discusses creating a keyboard hook and sniffing
for the problematic keys (Tab, Arrow, etc).  If the key is one that
we care about then create the appropriate window message and send to the
appropriate focused control.  The following link is the author's
original code.

http://groups.google.com/groups?&selm=8jarid%249n1%40bornews.borland....

I have simplified/optimized the author's code and I believe made a potential
bug fix (which I will discuss later).

  // H file
  class TMainForm : public TActiveForm
  {
    ...
    private:
      HHOOK fHook;
      static LRESULT CALLBACK KeyProc(int nCode, WPARAM wp, LPARAM lp);
    ...
  }

  // CPP file
  ...
  #include <bitset>
  #include <map>

  typedef std::map<HANDLE, TMainForm*> TInstMap;
  TInstMap MapOfInst;

  void __fastcall TMainForm::ActiveFormCreate(TObject *Sender)
  {
    MapOfInst.insert(TInstMap::value_type(HInstance, this));
    fHook = ::SetWindowsHookEx(
      WH_KEYBOARD, (HOOKPROC) KeyProc, HInstance, GetCurrentThreadId());
  }

  __fastcall TMainForm::~TMainForm()
  {
    if (::UnhookWindowsHookEx(fHook) == NULL)
      Application->MessageBox("Failed to unhook keyboard messages.",
        AppName, MB_OK | MB_ICONERROR);
  }

  LRESULT CALLBACK TMainForm::KeyProc(int nCode, WPARAM wp, LPARAM lp)
  {
    TMainForm*  form = MapOfInst.find(HInstance)->second;

    // check for exception cases...
    if (nCode < 0 || nCode == HC_NOREMOVE)
      return ::CallNextHookEx(form->fHook, nCode, wp, lp);

    bool result = false;

    // ok to process message...retrieve instance information
    std::bitset<32> prevstate(lp);
    switch(wp)
    {
      case VK_TAB:
      case VK_LEFT:
      case VK_RIGHT:
      case VK_UP:
      case VK_DOWN:
      case VK_HOME:
      case VK_END:
      case VK_PRIOR:
      case VK_NEXT:
      case VK_BACK:
        if (prevstate[31] == 0) // (*) potential bug fix
          form->ActiveControl->Perform(WM_KEYDOWN, wp, lp);
        else
          form->ActiveControl->Perform(WM_KEYUP, wp, lp);
        result = true;
        break;
    }

    return result;
  }
  // end of code

The original code referred to prevstate[30] which according to API
documentation is the "Previous Key State".  Bit 31 is the state that is
causing the current message.  I could be wrong about the change but it
doesn't seem to make any difference in my limited testing.  Also, I added a
WM_KEYUP message that didn't exist in the original code.

One problem I am still having with this code (if someone can help me find
the problem) is backspace and tab keys are captured from IE but the key
doesn't appear to do anything in the control.  Memo (with WantTabs set to
true) does not place a tab into the memo area.  And both Memo and Edit won't
delete existing text when backspace is pressed.

So, the above code appears to work-around the problem (as soon as I can fix
the backspace and tab issue).  However, I do not believe this is the
best/correct solution.  According to the Microsoft articles on this topic
(see below) the problem really has to do with IE translation keys snagging
the message before the active control can get it.  So, if Microsoft decides
to add another hot-key to IE in the future then the message would end up
going to IE instead of the focused control until the keyboard hook can be
updated.

  Microsoft references:
    http://support.microsoft.com/support/kb/articles/Q190/0/44.ASP
    http://support.microsoft.com/support/kb/articles/Q179/6/96.ASP

Does anybody have anything to add to this or another appropriate
work-around?

- Clayton

Re:Tab and arrow keys not working in TActiveForm in BCB6


Quote
"Clayton Arends" <claytonare...@hotmail.com> wrote in message

news:3eb970c4$1@newsgroups.borland.com...

Quote
> However, I do not believe this is the best/correct solution.

I found a definite bug in the code.  In the initial "check for exception
cases" area the if-statement needs to read:

  if (nCode < 0 || nCode == HC_NOREMOVE ||
      (!form->ActiveControl || !form->ActiveControl->Focused()))

This is necessary for the case where a control outside of the active form
has focus.  Otherwise the keyboard hook will trap all of these messages as
well never allowing the special keys to work correctly.

- Clayton

Other Threads