Skip to content

Commit 4e53a74

Browse files
committed
🆕 Add delay to activate menu. Mouse gesture double move (knock-knock) to show menu.
1 parent 638e5db commit 4e53a74

File tree

5 files changed

+228
-34
lines changed

5 files changed

+228
-34
lines changed

‎menu.dfm

+6
Original file line numberDiff line numberDiff line change
@@ -257,4 +257,10 @@ object frmMenu: TfrmMenu
257257
Left = 384
258258
Top = 152
259259
end
260+
object tmrDelayAction: TTimer
261+
Enabled = False
262+
OnTimer = tmrDelayActionTimer
263+
Left = 648
264+
Top = 368
265+
end
260266
end

‎menu.pas

+143-32
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ TfrmMenu = class(TForm)
4747
ActionList1: TActionList;
4848
actSwitchAIChats: TAction;
4949
JvApplicationHotKey3: TJvApplicationHotKey;
50+
tmrDelayAction: TTimer;
5051

5152
procedure FormCreate(Sender: TObject);
5253
procedure FormDestroy(Sender: TObject);
@@ -82,6 +83,7 @@ TfrmMenu = class(TForm)
8283
procedure JvApplicationHotKey3HotKeyRegisterFailed(Sender: TObject;
8384
var HotKey: TShortCut);
8485
procedure JvApplicationHotKey3HotKey(Sender: TObject);
86+
procedure tmrDelayActionTimer(Sender: TObject);
8587
// procedure FormPaint(Sender: TObject);
8688
private
8789
{ Private declarations }
@@ -94,6 +96,15 @@ TfrmMenu = class(TForm)
9496
FHookWndHandle: THandle;
9597
FHookMsg: Integer;
9698

99+
{ Mouse gestures }
100+
FHotSpotEntered: Boolean;
101+
FFirstKnockTime: TDateTime;
102+
FKnockEnabled: Boolean;
103+
FDelayEnabled: Boolean;
104+
FActionPending: Boolean; // Prevent overlapping actions
105+
FMousePosition: TPoint;
106+
const KnockInteval = 0.5 / (24 * 60 * 60); // 500 milliseconds as TDateTime
107+
97108
procedure CreateParams(var Params: TCreateParams); override;
98109
procedure HideMenu(Sender: TObject);
99110
procedure RestoreRequest(var message: TMessage); message WM_USER + $1000;
@@ -139,8 +150,13 @@ TfrmMenu = class(TForm)
139150

140151
procedure OnAppLostFocus(Sender: TObject);
141152

153+
{ Tightly coupled procedures for mouse actions }
142154
procedure HotSpotAction(MousePos: TPoint);
155+
function IsInHotSpot(const MPos: TPoint): Boolean;
156+
procedure StartDelayedAction;
143157
property OnMenuArea: Boolean read FOnMenuArea write FOnMenuArea;
158+
property MouseDelay: Boolean read FDelayEnabled write FDelayEnabled;
159+
property MouseGesture: Boolean read FKnockEnabled write FKnockEnabled;
144160
end;
145161

146162
var
@@ -391,6 +407,19 @@ procedure TfrmMenu.SiteContextPopup(Sender: TObject; MousePos: TPoint;
391407
end;
392408
end;
393409

410+
procedure TfrmMenu.StartDelayedAction;
411+
begin
412+
if not FDelayEnabled then
413+
HotSpotAction(FMousePosition)
414+
else
415+
if not FActionPending then
416+
begin
417+
FActionPending := True;
418+
tmrDelayAction.Interval := Settings.MouseDelayValue;
419+
tmrDelayAction.Enabled := True;
420+
end;
421+
end;
422+
394423
procedure TfrmMenu.WMDisplayChange(var message: TMessage);
395424
begin
396425
// Resolution changed
@@ -497,8 +526,8 @@ procedure TfrmMenu.HideMenu(Sender: TObject);
497526
end;
498527

499528
procedure TfrmMenu.HotSpotAction(MousePos: TPoint);
500-
var
501-
TypesAniPlugin: TAQPSystemTypesAnimations;
529+
//var
530+
// TypesAniPlugin: TAQPSystemTypesAnimations;
502531
begin
503532
if Settings.DisableOnFullScreenDirectX and DetectFullScreen3D then Exit;
504533
if Settings.DisableOnFullScreen and DetectFullScreenApp(GetForegroundWindow) then Exit;
@@ -520,18 +549,7 @@ procedure TfrmMenu.HotSpotAction(MousePos: TPoint);
520549
NewAlphaBlend := MAXBYTE;
521550
ShowMenuAnimation(ABE_LEFT);
522551
end;
523-
end
524-
else if (MousePos.X > frmMenu.Left + frmMenu.Width) and (tmrHideMenu.Enabled = False) then
525-
begin
526-
if OnMenuArea then
527-
begin
528-
OnMenuArea := False;
529-
NewWidth := 1;
530-
NewLeft := GetLeftMost;
531-
NewAlphaBlend := 0;
532-
ShowMenuAnimation(ABE_LEFT, False);
533-
end;
534-
end;
552+
end; // moved hide to rawinput
535553

536554
end;
537555
ABE_TOP:
@@ -551,18 +569,7 @@ procedure TfrmMenu.HotSpotAction(MousePos: TPoint);
551569
NewAlphaBlend := MAXBYTE;
552570
ShowMenuAnimation(ABE_RIGHT);
553571
end;
554-
end
555-
else if (MousePos.X < Left) and (tmrHideMenu.Enabled = False) then
556-
begin
557-
if OnMenuArea then
558-
begin
559-
OnMenuArea := False;
560-
NewWidth := 1;
561-
NewLeft := Screen.WorkAreaWidth - NewWidth;
562-
NewAlphaBlend := 0;
563-
ShowMenuAnimation(ABE_RIGHT, False);
564-
end;
565-
end;
572+
end; // moved hide to rawinput
566573

567574
end;
568575
ABE_BOTTOM:
@@ -866,6 +873,10 @@ procedure TfrmMenu.FormCreate(Sender: TObject);
866873
AllowSetForegroundWindow(GetCurrentProcessId);
867874

868875
Application.OnDeactivate := OnAppLostFocus;
876+
877+
{ Mouse behavior }
878+
FDelayEnabled := Settings.MouseDelay;
879+
FKnockEnabled := Settings.MouseGesture;
869880
end;
870881

871882
procedure TfrmMenu.FormDestroy(Sender: TObject);
@@ -1017,6 +1028,13 @@ procedure TfrmMenu.About1Click(Sender: TObject);
10171028

10181029
end;
10191030

1031+
procedure TfrmMenu.tmrDelayActionTimer(Sender: TObject);
1032+
begin
1033+
tmrDelayAction.Enabled := False;
1034+
FActionPending := False;
1035+
HotSpotAction(FMousePosition);
1036+
end;
1037+
10201038
procedure TfrmMenu.tmrHideMenuTimer(Sender: TObject);
10211039
begin
10221040
if not tmrShowMenu.Enabled then
@@ -1078,6 +1096,19 @@ procedure TfrmMenu.FormShow(Sender: TObject);
10781096
ShowWindow(Application.Handle, SW_HIDE);
10791097
end;
10801098

1099+
function TfrmMenu.IsInHotSpot(const MPos: TPoint): Boolean;
1100+
begin
1101+
if (GetAsyncKeyState(VK_LBUTTON) = 0) and (GetAsyncKeyState(VK_RBUTTON) = 0) then
1102+
begin
1103+
case Settings.BarPosition of
1104+
ABE_LEFT: Result := (MPos.X <= GetLeftMost + 1);
1105+
ABE_TOP:;
1106+
ABE_RIGHT: Result := (MPos.X >= GetRightMost - 1);
1107+
ABE_BOTTOM:;
1108+
end;
1109+
end;
1110+
end;
1111+
10811112
function TfrmMenu.IsStarteMenuVisible: Boolean;
10821113
var
10831114
startMenuOn: BOOL;
@@ -1353,8 +1384,8 @@ procedure TfrmMenu.ProcessRawInput(var Message: TMessage);
13531384
Mouse: RAWMOUSE;
13541385

13551386
Cur: THandle;
1356-
MPos: TPoint;
13571387

1388+
NowTime: TDateTime;
13581389
begin
13591390
if GetRawInputData(HRAWINPUT(Message.lParam), RID_INPUT, nil, DataSize, SizeOf(Header)) = 0 then
13601391
begin
@@ -1369,20 +1400,100 @@ procedure TfrmMenu.ProcessRawInput(var Message: TMessage);
13691400

13701401
Cur := 0;
13711402
try
1372-
if not Windows.GetCursorPos(MPos) then
1373-
MPos := Point(120, 120);
1403+
if not Windows.GetCursorPos(FMousePosition) then
1404+
FMousePosition := Point(120, 120);
13741405
Cur := GetForegroundWindow; // it will likely fail on windows locked (Win+L)
13751406
except
13761407
Cur := 0;
13771408
end;
13781409

13791410
if Cur <> 0 then
13801411
begin
1381-
HotSpotAction(MPos);
1412+
NowTime := Now();
1413+
1414+
if IsInHotSpot(FMousePosition) then
1415+
begin
1416+
if not FHotSpotEntered and not FActionPending then
1417+
begin
1418+
// First entry into hot spot
1419+
FHotSpotEntered := True;
1420+
1421+
if FKnockEnabled then
1422+
begin
1423+
if FFirstKnockTime = 0 then
1424+
begin
1425+
FFirstKnockTime := NowTime; // First knock time
1426+
end
1427+
else if NowTime - FFirstKnockTime <= KnockInteval then
1428+
begin
1429+
// Second knock within the interval
1430+
FFirstKnockTime := 0; // Reset knock time
1431+
StartDelayedAction;
1432+
end
1433+
else
1434+
begin
1435+
// Too late, reset knock
1436+
FFirstKnockTime := NowTime;
1437+
end;
1438+
end
1439+
else
1440+
begin
1441+
// No knock-knock, just start delay
1442+
StartDelayedAction;
1443+
end;
1444+
end;
1445+
end
1446+
else
1447+
begin
1448+
// Mouse left the hot spot
1449+
FHotSpotEntered := False;
1450+
// Hide if visible menu
1451+
case Settings.BarPosition of
1452+
ABE_LEFT:
1453+
begin
1454+
if (FMousePosition.X > frmMenu.Left + frmMenu.Width) and (tmrHideMenu.Enabled = False) then
1455+
begin
1456+
if OnMenuArea then
1457+
begin
1458+
OnMenuArea := False;
1459+
NewWidth := 1;
1460+
NewLeft := GetLeftMost;
1461+
NewAlphaBlend := 0;
1462+
ShowMenuAnimation(ABE_LEFT, False);
1463+
end;
1464+
end;
1465+
end;
1466+
ABE_TOP:
1467+
begin
1468+
1469+
end;
1470+
ABE_RIGHT:
1471+
begin
1472+
if (FMousePosition.X < Left) and (tmrHideMenu.Enabled = False) then
1473+
begin
1474+
if OnMenuArea then
1475+
begin
1476+
OnMenuArea := False;
1477+
NewWidth := 1;
1478+
NewLeft := Screen.WorkAreaWidth - NewWidth;
1479+
NewAlphaBlend := 0;
1480+
ShowMenuAnimation(ABE_RIGHT, False);
1481+
end;
1482+
end;
1483+
1484+
end;
1485+
ABE_BOTTOM:
1486+
begin
1487+
1488+
end;
1489+
end;
1490+
1491+
end;
1492+
1493+
1494+
// HotSpotAction(MPos);
13821495
end;
1383-
13841496
end;
1385-
13861497
end;
13871498
finally
13881499
FreeMem(lRawInput);

‎settings.dfm

+47-2
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ object frmSetting: TfrmSetting
129129
Top = 62
130130
Width = 641
131131
Height = 363
132-
ActivePage = TabSheet2
132+
ActivePage = TabSheet5
133133
Anchors = [akLeft, akTop, akRight, akBottom]
134134
Font.Charset = ANSI_CHARSET
135135
Font.Color = clWindowText
@@ -332,7 +332,7 @@ object frmSetting: TfrmSetting
332332
Left = 308
333333
Top = 3
334334
Width = 322
335-
Height = 235
335+
Height = 196
336336
Caption = 'Browser'
337337
TabOrder = 5
338338
object chkUseEmbeddedBrowser: TRadioButton
@@ -520,6 +520,51 @@ object frmSetting: TfrmSetting
520520
OnClick = chkWinKeyLauncherClick
521521
end
522522
end
523+
object GroupBox4: TGroupBox
524+
Left = 308
525+
Top = 205
526+
Width = 322
527+
Height = 100
528+
Caption = 'Mouse'
529+
Color = 2743985
530+
ParentBackground = False
531+
ParentColor = False
532+
TabOrder = 10
533+
object lbedMouseDelay: TLabeledEdit
534+
Left = 30
535+
Top = 48
536+
Width = 73
537+
Height = 21
538+
EditLabel.Width = 210
539+
EditLabel.Height = 13
540+
EditLabel.Caption = 'Milliseconds to wait (1000ms = 1 second)'
541+
NumbersOnly = True
542+
TabOrder = 0
543+
Text = '250'
544+
end
545+
object chkMouseDelay: TCheckBox
546+
Left = 11
547+
Top = 16
548+
Width = 129
549+
Height = 17
550+
Caption = 'Delay to show menu'
551+
TabOrder = 1
552+
OnClick = chkMouseDelayClick
553+
end
554+
object chkKnockKnock: TCheckBox
555+
Left = 11
556+
Top = 74
557+
Width = 254
558+
Height = 17
559+
Hint =
560+
'Mouse gesture: move twice to the menu'#39's screen edge as double cl' +
561+
'ick like to show the menu.'
562+
Caption = 'Knock-knock gesture to show menu'
563+
ParentShowHint = False
564+
ShowHint = True
565+
TabOrder = 2
566+
end
567+
end
523568
end
524569
object TabSheet6: TTabSheet
525570
Caption = 'About'

0 commit comments

Comments
 (0)