Is it not possible to use the Pause/Break key in keyboard shortcuts?
I know I can respond to the Pause/Break key, e.g.
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if Key = VK_PAUSE then
ShowMessage('VK_PAUSE pressed');
end;
However, I am unable to respond to the Pause/Break key using the TShortCut properties, e.g. in menu items and action lists. The Object Inspector lets me enter Pause, Shift + Pause, Ctrl + Pause, Alt + Pause, Ctrl + Shift + Pause etc. so it clearly recognizes the Pause key. But when I run the application, the menu item/action is not triggered on the specified shortcut. Is there a known workaround?
With D2007, a quick workaround seems to be assigning it in the run-time;
Action1.ShortCut := VK_PAUSE;
For some reason if assigned in design-time, VK_PAUSE (19) seems to mutate to VK_NUMLOCK (144).
When a shortcut is assigned in design time the IDE has to convert a string to a shortcut. The problem is TextToShortCut('Pause'); returns 144 instead of 19. Though I'm not sure I believe the error is with Delphi; With 'Pause', retrieving a shortcut finds its way to menus.GetSpecialName, I think it should not.
On another note, while the workaround mentioned above works with 'Alt' and 'Shift' modifiers, it doesn't work with the 'Ctrl' modifier. The reason is, the OS assings 'Ctrl+Break' processing a special code: VK_CANCEL. To use 'Ctrl+Pause' as a shortcut one have to code;
Action1.ShortCut := menus.Shortcut(VK_CANCEL, [ssCtrl]);
Related
In a search form I have two components, a TEdit and and TDBGrid. The user enters text into the TEditand in the TEdit.OnChange event I search for matching items in a table using a query. These are displayed in a TDGrid. The event only triggers when the user has entered more than three characters in the TEdit.Textto cut down the overhead.
The problem occurs when the search has returned all possible records and the user wants to select one of the records displayed in the TDBGrid. While I told the users to use the Tab key (or the mouse) to switch from the TEdit to the TDBGrid, they use the return key to do this in another application and are insisting that they should be able to do the same thing in the application I'm altering/adding to. I can understand this, but the problem is that if I use
if (key = VK_RETURN) then key := VK_TAB;
in the TEdit.OnKeyUp event, the original value of the last key pressed in the TEdit is "remembered" as VK_RETURN and is passed to the TDBGrid's OnKeyUp event. Since I have other actions triggered in that event, I get undesired things happening as soon the the TDBGrid gains focus because they also want to select the correct row in the grid by pressing the return key again.
Therefore what I want to do is to "cancel" the key value passed to the TDBGrid from the TEdit. I tried using if (Sender = TEdit) then Key := VK_CANCEL; in the DGBrid's OnKeyUp event but I get a compiler "Incompatible types" error and I can't find anything to tell me how I should use it in this situation.
Is this possible? Or am I going about this the wrong way?
Thanks in advance!
I believe the following approach satisfies your needs and I suspect it to be the shortest such approach:
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
if Key = #13 then
Key := #0;
end;
procedure TForm1.Edit1KeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_RETURN then
begin
PostMessage(Handle, WM_NEXTDLGCTL, 0, 0);
Key := 0;
end;
end;
This will make Enter, in Edit1, move focus to the next control. This is accomplished by posting the form a WM_NEXTDLGCTL message. The OnKeyPress handler is needed to suppress the "invalid input" message beep.
For bonus points, do
PostMessage(Handle, WM_NEXTDLGCTL, Ord(ssShift in Shift), 0);
instead to have Shift+Enter correspond to Shift+Tab.
I'm not quite sure I like this entire idea, though. I think I prefer to have Enter act on key down instead. The target control shoudn't care about this key up message.
Just to add to Andreas answer, I have used the same approach. There are 3 events you can play around with, onkeydown, onkeypress, onkeyup. At some point you will probably have to assign the key to null to avoid the "beep". The other thing to watch out for are unintended side effects, like moving 2 fields instead of one as has happened to me in the past.
I'm trying to replicate something similar to the Inkscape Zoom shortcuts shown below. Note that these Inkscape shortcuts work whether or not the number pad is used.
The first problem is that setting the shortcuts via the Object Inspector isn't possible, as there are no options for these keys on their own without modifier keys. I then tried setting the shortcuts at runtime as shown below. This shows the shortcut numbers in the menu, but the shortcuts don't work. I press the number key and nothing happens, whether or not the num pad is used (the menu items do work if I click them). The + and - shortcuts don't work, either.
Another problem is that the - shortcut is shown as '-' in the menu for some reason, and the + shortcut is shown as '=' because it's the same key. I have also tried using TextToShortcut(), but no luck.
Is this possible in FMX, or will I have to resort to using the function keys? I'd prefer to have consistency with Inkscape. I could handle the key presses in the Form's OnKeyDown event, but then how would I show the shortcut keys in the menu correctly (right hand side of the menu item)?
MenuItem1.ShortCut := vkEqual;
MenuItem2.ShortCut := vkMinus;
MenuItem3.ShortCut := vk1;
MenuItem4.ShortCut := vk2;
MenuItem5.ShortCut := vk5;
MenuItem6.ShortCut := vk3;
MenuItem7.ShortCut := vk4;
You can do it from source :
item1.ShortCut := 8299;
Becouse Shortcut of TmenuItem is of TShortCut and this is
TShortCut = Low(Word)..High(Word);
its simple sum of key and Fkey :
Shift - 8192
Ctrl - 16384
Alt - 32768
So we have 8299 =
"numpad +" = 107 +
Shift = 8192
For using "+" and "Numeric +", use Action connected to Menu item:
procedure TForm1.FormCreate(Sender: TObject);
begin
Action1.Caption := 'Click'+#9+'+';
Action1.SecondaryShortCuts.Add('Shift+=');
Action1.SecondaryShortCuts.Add('Num +');
end;
best regards
Moskw#
In my application, when I press CTRL + S, my form (with Key Preview enabled) captures this and saves the document. But when the focus is in, for example, an edit control, I get an annoying "Ding" sound, or in general, windows sounds. How do I avoid this sound?
Here's my form's capture of this key event...
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
C: String;
begin
if not fChanging then
Modified;
if ssCtrl in Shift then begin
C:= LowerCase(Char(Key));
if C = 's' then begin
DoSave;
Key:= 0; //Tried this but didn't work
end else
if C = 'c' then begin
//Copy selected item(s)
end;
end;
end;
PS - Is there a more standard way of capturing these events? Because I'm sure I'm doing something wrong, and I'm sure there's another way I should be getting these key events without sounds.
A couple of things:
Try putting your code into FormKeyPress instead of FormKeyDown. This will make the Key := 0; code work... You will need to handle the CTRL checking manually though, by using something like GetKeyState() (I originally had GetAsyncKeyState() here, but as Rob Kennedy points out, GetKeyState() is a much better option).
Use an Action instead. Plop a TActionList on your form, double click on it, add an action and set it's hot key to CTRL-S. Add your save code to it's OnExecute event handler. This is the "proper" way to do it I believe.
Hope this helps.
Why don't you use Actions? That is the best way to handle shortcuts.
Here is some Delphi code to disable the system beep.
I have an Edit Control on a DevExpress Ribbon of type TcxBarEditItem which I am recording the keypresses of to update a "floating" listbox of possible functionality to fire.
For some reason, the TcxBarEditItem and it's parent classes' event handler's do not work at all like Delphi's vanilla equivalents, meaning I have to record these keypresses.
My question however, is how to record/or prohibit, the user doing things like pasting in loads of text, or highlighting and deleting loads of text?
The way in which these controls seem to work means using String(TcxBarEditItem(control).EditValue) (which is how I would access the control as it is a member of a Command class - TS8RibbonCommand) isn't actually indicative of the text in the edit control until the user clicks out of it. I've tried doing loads of things like programmatically setting focus elsewhere and refocusing but nothing else seems to work bar recording the keypresses.
In the code snippet mirroredJumpStart is my copy of what the user is typing. The RefreshJumpStart function takes a string value and iterates over all the different string values in a list and populates a Listbox using AnsiContainsString.
procedure TS8RibbonJumpStartEdit.KeyPress(Sender: TObject; var Key: Char);
begin
if (Key in ['a'..'z']) or (Key in ['A'..'Z']) or (Key in ['0'..'9']) or (Key = ' ') then
manager.mirroredJumpStart := manager.mirroredJumpStart + Key
else if (Key = Chr(VK_BACK)) and (Length(manager.mirroredJumpStart) <> 0) then
Delete(manager.mirroredJumpStart, Length(manager.mirroredJumpStart), 1);
manager.RefreshJumpStart(manager.mirroredJumpStart);
end;
Any help would be great!
Assuming this is a standard TEdit control...
You can limit the amount of text by using MaxLength property
You can catch individual keystrokes by observing Key parameter in the event OnKeyDown
Just a couple little tips, not sure if it will help, because you don't say you're using the TEdit
In code I have developed some years ago I have been using this a lot to close the current form on pressing the Escape key at any moment:
procedure TSomeForm.FormKeyPress(Sender: TObject; var Key: Char);
begin
if key = #27 then close;
end;
This behaviour is defined for the TForm. The form's KeyPreview property is be set to True to let the form react to key presses before any other components. It all works perfectly well for the best part of the program, however, when the Escape key is pressed while a TEdit component is focused a sound (a ding sound used by Windows to signify invalid operation) is issued. It still works fine but I have never quite managed to get rid of the sound.
What's the problem with this?
Steps to recreate:
new VCL Forms application, set the form's KeyPreview to true
on the Events tab double-click the onKeyPress event and enter dummy code:
if key=#27 then ;
add a TListBox, TCheckBox, TEdit to the form and run the application
in the application try pressing Esc and NOTHING happens, as specified by the dummy code
focus the TEdit and press Esc. Nothing happens but the sound is played.
You get the ding because you left the ESC in the input. See how Key is a var? Set it to #0 and you eliminate the ding. That removes it from further processing.
procedure TSomeForm.FormKeyPress(Sender: TObject; var Key: Char);
begin
if key = #27 then
begin
key := #0;
close;
end;
end;
KeyPreview is just that, a preview of what will be passed to the controls unless you stop it.
Starting from Jim's answer (thanks Jim) I had to make it work for me. What I needed was to make a dropped down combobox close keeping the selected item and move to the next/previous control when TAB/shift+TAB was pressed. Everytime I did press TAB the annoying sound filled the room. My work arroud was using onKeyDown event to catch the shiftstate, declaring var aShift: boolean; in form's interface and use the following code:
procedure TForm2.StComboKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if ssShift in Shift then aShift := true else aShift := false;
end;
procedure TForm2.StComboKeyPress(Sender: TObject; var Key: Char);
begin
if Key=char(VK_TAB) then
begin
Key := #0;
StCombo.DroppedDown := false;
if aShift
then previousControl.SetFocus
else nextControl.SetFocus;
end;
end;
Using the menu items and setting them to invisible, and using the shortcut, is a quick workaround that I've just stumbled across, but won't work if you need a shortcut that uses a character that is used in the first letter of an existing shortcut: For example for Alt+ENTER, you need to add something like this to the form create procedure:
MainMenu1.Items[0].ShortCut:=TextToShortCut('Alt+e');
However it's probably easier to use TActionList instead, and even though something like Alt+E is not listed you can add it.
It's an old thread... but anyway, here's a far better one: catching Alt-C!
Unlike ESC, Alt-C isn't serviced by KeyPress, so setting Key to #0 in KeyPress doesn't work, and the horrendous "ding!" is issued every time.
After hours of trying, here's the workaround I found:
- create a main menu option to service the request
- set its ShortCut to Alt+C - yes indeed, that is NOT one of the available ShortCut choices(!!)... but it does work anyway!
- do the processing in that menu option's OnClick
- you may even make in "in the background": you may set the menu option's Visible to false - as long as its Enabled stays true, it will be activated by Alt-C even though it will not be visible in the menu.
Hope that may help! And if you have something more elegant, please advise.