I am trying to put form into "help mode" in Delphi 2010.
I have a button which the user clicks, and I want the cursor to change to the help cursor, then when a user clicks onto a control, the help for the control is displayed
Is there a window message that I can send?
Send a WM_SYSCOMMAND message to the form passing SC_CONTEXTHELP as lParam.
Changes the cursor to a question mark with a pointer. If the user then clicks a control in the dialog box, the control receives a WM_HELP message.
Write something like this in your button OnClick event handler:
procedure TMyForm.Button1Click(Sender: TObject);
begin
SendMessage(Handle, WM_SYSCOMMAND, SC_CONTEXTHELP, 0);
end;
Related
Is it possible to determine the source of a close request in a Windows application (Delphi)?
Background: I have an option to route close requests to minimizing the window to keep the app running "in Background".
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
... different checking stuff e.g. unsaved changes
// Redirect Close to minimize but allow close if requested from minimized state
if FMinimize and (WindowState <> wsMinimized) then
begin
logger.debug('... closing main form redirected to minimize');
WindowState := wsMinimized;
CanClose := false;
exit;
end;
end;
This works well and allows closing the window by right clicking in the taskbar if already minimized. As icing of the cake I would like to determine if the close request came from right clicking the taskbar icon to close immediately even if the window is not already minimized. Is there a way to determine the source of the close request?
There is no difference between closing a window via the X button in its top-right corner, vs the Close window option on the right-click menu of the window's Taskbar button, vs the ALT-F4 keystroke. They all represent the same close command. If any of those options are invoked, the window will receive a WM_SYSCOMMAND(SC_CLOSE) message, which if passed to DefWindowProc() will generate a WM_CLOSE message that will trigger the Form's OnCloseQuery event. So no, there is no way to differentiate the source of the initial WM_SYSCOMMAND message. Only that the user wishes for the window to close.
That being said, you might try having your Form intercept the WM_NCHITTEST and WM_SYSKEYDOWN messages to detect when the user is clicking on the X button or pressing ALT-F4 on the keyboard. You can use those messages to set flags that your OnCloseQuery event can look at. That is about the only way I can think of right now to differentiate between Taskbar vs non-Taskbar closures.
I am using Tmainform.OnKeyDown and it fires always correctly, besides the controls or frames added to the form.
I need the same behavior for OnMouseDown.
My goal is to track activity of the user. After x minutes with no keyboard nor mouse clicks I want to close the application.
Edit: TMainForm.OnMouseDown never gets fired. I don't want to do anything with the event, just know that the user is alive and clicking.
For the Form to see keystrokes prior to the active control you need to set the KeyPreview property within the forms Object Inspector.
You can also do this via code: Form1.KeyPreview := True;
There is a substantial explanation in the accepted answer here: How does Delphi's KeyPreview work?
Regarding your mouse query, how do you know it isn't working if you're not doing anything there?
Put this code into your forms OnMouseDown event;
PROCEDURE TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
BEGIN
CASE Button OF
mbLeft: showmessage('Left Mouse Button!');
mbRight: showmessage('Right Mouse Button!');
mbMiddle: showmessage('Middle Mouse Button!');
END;
END;
I hope this is helpful and answers your question.
I've built a custom control that I'm trying to send input to. It will accept mouse input and report MouseDown, MouseMove and MouseUp correctly, but for whatever reason, it won't accept keyboard input. When I click on it, it doesn't receive focus, and any keys I press get interpreted by whatever control had the focus already.
This is probably something really simple. The first place I thought to look was in the ControlStyle property, but the only thing I can see in the helpfile about keyboard input is csNoStdEvents, which disables it, and my control doesn't have that. So what do I need to do to make it so my control can receive input focus?
A few things to try:
On MouseDown, call Windows.SetFocus(Handle). In my experience, the WinAPI function SetFocus often works better than the VCL's SetFocus method.
In response to the WM_GETDLGCODE message, reply with Message.Result := Message.Result or DLGC_WANTCHARS or DLGC_WANTARROWS or DLGC_WANTTAB or DLGC_WANTALLKEYS;
Could it be as simple as calling SetFocus on mouse down?
procedure TYourCustomControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer; Y: Integer);
begin
inherited;
if CanFocus then
SetFocus;
end;
Do you have WS_TABSTOP set? You don't have input focus without that, I believe. But this is based on a recollection from nearly 10 years ago, when I was writing my own syntax-highlighting code editor, for which I have long since lost the source.
{TWinControl.}TabStop := True; ought to do. A quick test app with a do-nothing component derived from TWinControl and displaying a dialog for key events seems to show that it makes all the difference.
I've checked the code for my control and I can't see anything that might stop this working. Are you calling "inherited" in the Create procedure?
I do handle the following, but nothing special:
procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
Is the keystroke available at form level? That is, is KeyPreview turned on, and can you see the keystroke in the form's OnKeypress event? You can follow it from there in the debugger. Is the control (as Dan indicated) suitable for keyboard input? For instance, a TLabel, although it displays text, is a graphical control.
If a mouse button is pressed and a window is shown that window will receive the MouseUp event when the mouse button is released.
Is it possible to detect, once the window is shown, whether or not a mouse button is already pressed?
I would try this:
procedure TForm1.FormShow(Sender: TObject);
begin
if GetKeyState(VK_LBUTTON) and $8000 <> 0 then
ShowMessage('Left mouse button is pressed...')
else
ShowMessage('Left mouse button is not pressed...')
end;
To answer your question directly, you can test for mouse button state with GetKeyState or GetAsyncKeyState. The virtual key code you need is VK_LBUTTON.
The difference between these is that GetKeyState reports the state at the time that the currently active queued message was posted to your queue. On the other hand, GetAsynchKeyState gives you the state at the instant that you call GetAsynchKeyState.
From the documentation of GetKeyState:
The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information.
An application calls GetKeyState in response to a keyboard-input message. This function retrieves the state of the key when the input message was generated.
I suspect that you should be using GetKeyState but I can't be 100% sure because I don't actually know what you are trying to achieve with this information.
Microsoft's User Experience Interaction Guidelines give some UI guidelines for when to use a menu button:
http://i.msdn.microsoft.com/Aa511453.command51(en-us,MSDN.10).png
How do I create one of these menu buttons? I've found information on
how to create a split button in Vista and above
how to create a toolbar button with a dropdown menu
how to create a regular pushbutton and manually wire up an OnClick event handler that pops up a menu
But is there any standard way to create a button, not in a toolbar, with the little down triangle, that automatically pops up a menu when clicked?
(I'm using Delphi / C++Builder, but other solutions are welcome.)
You can use the OnClick to force the popup, and for consistency don't use the cursor position, but rather the control position.
procedure TForm1.Button1Click(Sender: TObject);
var
pt : TPoint;
begin
Pt.X := Button1.Left;
Pt.Y := Button1.Top+Button1.Height;
pt := ClientToScreen(Pt);
PopupMenu1.Popup(pt.x,pt.y);
end;
You can then add the "glyph" using either a Delphi 2010 button, or a previous version TBitBtn and assign the bitmap/glyph property to an appropriate image and align right.
You don't mention which version of Delphi you are using, but in Delphi 2010 TButton has new properties for this: DropDownList which can be associated with a TPopupMenu to define the menu items, and Style which can be set to bsSplitButton.
This produces a button that you can press that also has a dropdown arrow on the right of it, To make the menu popup when you click to the left of the arrow this code in the button click handler should do the job.
procedure TForm1.Button1Click(Sender: TObject);
var
CursorPos: TPoint;
begin
GetCursorPos(CursorPos);
PopupMenu1.Popup(CursorPos.X, CursorPos.Y);
end;
in previous versions of Delphi I think you had to use TToolBar.