Rob, Thanks for your reply. There's certainly plenty of food for thought there.
The problem I was having with the KeyUp/KeyDown events was, as you indicated, caused by the -dialogui option. Neither the 'KeyDown' nor the 'Char' event gets fired when -dialogui is used, nor do they when an accelerator table is defined. The KeyUp event is still available, but it strikes me that those events are most useful for really fine control, which isn't necessary for my purpose (a very common one, I would have thought). I would also think that the system would handle those events much better than I ever would. So, for now, I think that accelerators are the right way to go. My solution was to create a hash of subroutine references, keyed by control handle, which I got from the GetFocus() method. I think your way is better (more elegant!), as that way, the control object reference is available. (If you remember, the problem I had was getting to the control name [or object ref] from the handle). The only thing that bugs me a little is the need for the Hook call to WM_SETFOCUS. I'll have a play to see if that is necessary for my purpose. As for the RFE, I think that this functionality is definitely needed, but I'm still not 100% sure that accelerators are the best way to achieve it. It looks like they'll do the job, but I'm a bit uncomfortable changing the way the Windows GUI is supposed to work, if, in fact, they were only designed to work for top-level windows (I had a hunt on MSDN, but couldn't find the relevant bit). I'll have a play with these new techniques and think about that later. Cheers, Glenn -----Original Message----- From: Robert May [mailto:[EMAIL PROTECTED] Sent: Monday, 09 January, 2006 17:41 To: Glenn W Munroe Subject: Re: Accelerators Glenn W Munroe wrote: > It would be useful to be able to define handlers for key presses on a > per-control basis. For example, it is common to end text entry with a > press of the "Enter" key; the action on that key press could be > different depending on the control. I have tried to define different > accelerator tables for different controls, but that doesn't work. Is > this something that is broken, hasn't yet been implemented or is that > way by design? I see that there is an {-accel} key for every control's > hash, but I haven't figured out how to use it. I've had a quick look through the code, and it looks like it was never intended that the -accel option was used on anything other than a top-level window. I don't think it would be hard to have it work on a per control basis (although I would assume that we would want it to fall through to the top level windows, so that we don't have to define menu accelerators for each control accelerator table). If you think this would be useful, could you raise an RFE. > I have also tried to handle the "KeyUp/KeyDown" events, but they don't > ever seem to fire. To which controls do those events apply? Pretty much all of them. The code below shows them working for a button controls. > The only way I have found to do this is to define a window-level > accelerator table and perform the relevant action depending on which > control has focus. That's ugly and it's a pain to get the control's name > from its handle (perhaps that would be a useful method to build into the > module). Even that is not trivial in the case of, say, a combobox, where > it isn't the combobox itself that has focus, but the dynamically created > child edit control. > > Has anybody come up with an elegant solution for this? Is this elegant enough for you? Regards, Rob. #!perl -w use strict; use warnings; use Win32::GUI qw(WM_SETFOCUS); my $mw = Win32::GUI::Window->new( -title => "Accel Tables", -pos => [100,100], -size => [400,300], #-dialogui => 1, ); $mw->Hook(WM_SETFOCUS, \&setAccel); # When -dialoui => 1 is specified on the window, then button # will stop recieiving WM_CHAR (onChar) events; read about # WM_GETDLGCODE for why. my $but = $mw->AddButton( -text => "Button", -pos => [10,10], -tabstop => 1, -notify => 1, -onGotFocus => \&setAccel, -onKeyDown => sub {print "Button onKeyDown, $_[2]\n"}, -onChar => sub {print "Button onChar, $_[2]\n"}, -onKeyUp => sub {print "Button onKeyUp $_[2]\n"}, ); my $com = $mw->AddCombobox( -text => "Default", -pos => [10,40], -size => [100,100], -tabstop => 1, -onGotFocus => \&setAccel, ); # A set of accelerator tables, keyed by the stringified object reference, # allows for simple lookup in a common GotFocus handler my %accels = ( $mw => Win32::GUI::AcceleratorTable->new( "A" => sub{print "Accel a pressed\n";1;}, ), $but => Win32::GUI::AcceleratorTable->new( "B" => sub{print "Accel b pressed\n";1;}, ), $com => Win32::GUI::AcceleratorTable->new( "C" => sub{print "Accel c pressed\n";1;}, ), ); $mw->Show(); Win32::GUI::Dialog(); exit(0); sub setAccel { my ($self) = @_; # Really should cope with there not being a handler in the hash # better. $mw->Change(-accel => $accels{$self}) if exists $accels{$self}; return 1; } __END__