From: Jonathan S. <jso...@al...> - 2001-03-14 21:08:04
|
has anyone been successful in getting Accelerators to work? Jonathan Southwick Technical & Network Services Allegheny College, Meadsville, PA jso...@al... |
From: Glenn W M. <gwm...@gm...> - 2006-01-08 16:26:45
|
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 have also tried to handle the "KeyUp/KeyDown" events, but they don't ever seem to fire. To which controls do those events apply? 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? Glenn |
From: Robert M. <rm...@po...> - 2006-01-09 23:24:40
|
This was menat to go to the lit as well as to Glenn M. Regards, Rob. Robert May wrote: > Glenn W Munroe wrote: >=20 >> It would be useful to be able to define handlers for key presses on a=20 >> per-control basis. For example, it is common to end text entry with a=20 >> press of the =93Enter=94 key; the action on that key press could be=20 >> different depending on the control. I have tried to define different=20 >> accelerator tables for different controls, but that doesn=92t work. Is= =20 >> this something that is broken, hasn=92t yet been implemented or is tha= t=20 >> way by design? I see that there is an {-accel} key for every control=92= s=20 >> hash, but I haven=92t figured out how to use it. >=20 > I've had a quick look through the code, and it looks like it was never=20 > intended that the -accel option was used on anything other than a=20 > top-level window. >=20 > I don't think it would be hard to have it work on a per control basis=20 > (although I would assume that we would want it to fall through to the=20 > top level windows, so that we don't have to define menu accelerators fo= r=20 > each control accelerator table). >=20 > If you think this would be useful, could you raise an RFE. >=20 >> I have also tried to handle the =93KeyUp/KeyDown=94 events, but they d= on=92t=20 >> ever seem to fire. To which controls do those events apply? >=20 > Pretty much all of them. The code below shows them working for a butto= n=20 > controls. >=20 >> The only way I have found to do this is to define a window-level=20 >> accelerator table and perform the relevant action depending on which=20 >> control has focus. That=92s ugly and it=92s a pain to get the control=92= s=20 >> name from its handle (perhaps that would be a useful method to build=20 >> into the module). Even that is not trivial in the case of, say, a=20 >> combobox, where it isn=92t the combobox itself that has focus, but the= =20 >> dynamically created child edit control. >> >> Has anybody come up with an elegant solution for this? >=20 >=20 > Is this elegant enough for you? >=20 > Regards, > Rob. >=20 > #!perl -w > use strict; > use warnings; >=20 > use Win32::GUI qw(WM_SETFOCUS); >=20 > my $mw =3D Win32::GUI::Window->new( > -title =3D> "Accel Tables", > -pos =3D> [100,100], > -size =3D> [400,300], > #-dialogui =3D> 1, > ); > $mw->Hook(WM_SETFOCUS, \&setAccel); >=20 > # When -dialoui =3D> 1 is specified on the window, then button > # will stop recieiving WM_CHAR (onChar) events; read about > # WM_GETDLGCODE for why. > my $but =3D $mw->AddButton( > -text =3D> "Button", > -pos =3D> [10,10], > -tabstop =3D> 1, > -notify =3D> 1, > -onGotFocus =3D> \&setAccel, > -onKeyDown =3D> sub {print "Button onKeyDown, $_[2]\n"}, > -onChar =3D> sub {print "Button onChar, $_[2]\n"}, > -onKeyUp =3D> sub {print "Button onKeyUp $_[2]\n"}, > ); >=20 > my $com =3D $mw->AddCombobox( > -text =3D> "Default", > -pos =3D> [10,40], > -size =3D> [100,100], > -tabstop =3D> 1, > -onGotFocus =3D> \&setAccel, > ); >=20 > # A set of accelerator tables, keyed by the stringified object referenc= e, > # allows for simple lookup in a common GotFocus handler > my %accels =3D ( > $mw =3D> Win32::GUI::AcceleratorTable->new( > "A" =3D> sub{print "Accel a pressed\n";1;}, > ), > $but =3D> Win32::GUI::AcceleratorTable->new( > "B" =3D> sub{print "Accel b pressed\n";1;}, > ), > $com =3D> Win32::GUI::AcceleratorTable->new( > "C" =3D> sub{print "Accel c pressed\n";1;}, > ), > ); >=20 > $mw->Show(); > Win32::GUI::Dialog(); >=20 > exit(0); >=20 > sub setAccel > { > my ($self) =3D @_; >=20 > # Really should cope with there not being a handler in the hash > # better. > $mw->Change(-accel =3D> $accels{$self}) if exists $accels{$self}; >=20 > return 1; > } > __END__ |
From: Glenn W M. <gwm...@gm...> - 2006-01-10 13:03:27
|
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:rm...@po...] 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__ |
From: Robert M. <rm...@po...> - 2006-01-10 22:21:37
|
Glenn W Munroe wrote: > 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, That depends on the control and what it returns from the WM_GETDLGCODE message sent to it when it has focus by the IsDialogMessage() call in the message pump. For example WM_CHAR messages are sent to Textfields. > nor do they when an > accelerator table is defined. With -dialogui => 1 all KeyUp/Char/KeyDown messages should be sent to a control, except for ones corresponing to the defined accelerators in the accelerator table, as they have been processed as accelerators. [snip] > 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. You'll need it if you need any accelerators processing when no other control has the focus. It wouldn't be difficult to add an onGotFocus event to the Win32::GUI::Window class > 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. I think we may be talking a little at cross purposes: I did not mean that MS think accelerators should only be used for top level windows; I meant that Win32::GUI::Dialog() was coded to only use accelerators from top level windows. MSDN doen't say a lot about accelerators (that I've found) - they are processed with in a message pump by the TranslateAccelerator() function. A typical message pump looks like (pseudocode) while msg=GetMessage() { if TranslateAccelerator(hwnd, acc, msg) continue; TranslateMessage(msg); DispatchMessage(msg); } TranslateAccelerator() takes a set of accelerator definitions (acc) and a message from the thread's message queue, and if the message is a key message for the accelerator definition TranslateMessage send a WM_COMMAND message to the window passed to it (hwnd) and returns non-zero to indicate that the message has been processed and should not be passed on to TranslateMessage/DispatchMessage. Win32::GUI::Dialog() get hwnd and acc for TranslateAccelerator by traversing the window hierarchy from the window to which the event is being sent, up until it finds the parent top-level window. It would be relatively easy to stop at each level, see if there was an accelerator Table object associated with each window and if so try to ue it, bailing out the first time TranslateAccelerator returns non-zero. Regards, Rob. |