@@ -9,21 +9,21 @@ namespace
9
9
constexpr auto STARTUP_REGISTRY_KEY = L" SOFTWARE\\ Microsoft\\ Windows\\ CurrentVersion\\ Run" ;
10
10
constexpr auto PROGRAM_NAME = L" ThreeFingerDrag" ;
11
11
constexpr auto UPDATE_SETTINGS_PERIOD_MS = std::chrono::milliseconds(2000 );
12
- constexpr auto TOUCH_ACTIVITY_PERIOD_MS = std::chrono::milliseconds(50 );
12
+ constexpr auto TOUCH_ACTIVITY_PERIOD_MS = std::chrono::milliseconds(1 );
13
13
constexpr auto MAX_LOAD_STRING_LENGTH = 100 ;
14
14
15
15
constexpr auto SETTINGS_WINDOW_WIDTH = 456 ;
16
16
constexpr auto SETTINGS_WINDOW_HEIGHT = 170 ;
17
- constexpr auto MIN_SKIPPED_FRAMES = 3 ;
18
- constexpr auto MAX_SKIPPED_FRAMES = 25 ;
17
+ constexpr auto MIN_CANCELLATION_DELAY_MS = 100 ;
18
+ constexpr auto MAX_CANCELLATION_DELAY_MS = 2000 ;
19
19
constexpr auto MIN_GESTURE_SPEED = 1 ;
20
20
constexpr auto MAX_GESTURE_SPEED = 100 ;
21
21
constexpr auto ID_SETTINGS_MENUITEM = 10000 ;
22
22
constexpr auto ID_QUIT_MENUITEM = 10001 ;
23
23
constexpr auto ID_RUN_ON_STARTUP_CHECKBOX = 10002 ;
24
24
constexpr auto ID_GESTURE_SPEED_TRACKBAR = 10003 ;
25
25
constexpr auto ID_TEXT_BOX = 10004 ;
26
- constexpr auto ID_SKIPPED_FRAMES_SPINNER = 10005 ;
26
+ constexpr auto ID_CANCELLATION_DELAY_SPINNER = 10005 ;
27
27
}
28
28
29
29
// Global Variables
@@ -56,73 +56,49 @@ LRESULT CALLBACK SettingsWndProc(HWND, UINT, WPARAM, LPARAM);
56
56
57
57
void CreateTrayMenu (HWND hWnd);
58
58
void ShowSettingsWindow ();
59
- void AddStartupRegistryKey ();
59
+ void AddStartupTask ();
60
+ void RemoveStartupTask ();
60
61
void RemoveStartupRegistryKey ();
61
62
void ReadPrecisionTouchPadInfo ();
62
63
void ReadCursorSpeed ();
63
- void UpdateGestureProcessor ();
64
64
void StartPeriodicUpdateThreads ();
65
65
void HandleUncaughtExceptions ();
66
+ void PerformAdditionalSteps ();
67
+ void PromptUserForStartupPreference ();
68
+ void InitializeConfiguration ();
66
69
bool InitializeWindowsNotifications ();
67
70
bool StartupRegistryKeyExists ();
68
71
bool RegisterRawInputDevices ();
72
+ bool CheckSingleInstance ();
69
73
bool InitializeGUI ();
70
74
71
75
int APIENTRY wWinMain (_In_ HINSTANCE hInstance,
72
76
_In_opt_ HINSTANCE hPrevInstance,
73
77
_In_ LPWSTR lpCmdLine,
74
78
_In_ int nCmdShow)
75
79
{
80
+ current_instance = hInstance;
76
81
UNREFERENCED_PARAMETER (hPrevInstance);
77
82
UNREFERENCED_PARAMETER (lpCmdLine);
78
83
79
84
std::set_terminate (HandleUncaughtExceptions);
80
85
81
- // Single application instance check
82
- const HANDLE hMutex = CreateMutex (nullptr , TRUE , PROGRAM_NAME);
83
- if (GetLastError () == ERROR_ALREADY_EXISTS)
84
- {
85
- Popups::DisplayErrorMessage (" Another instance of Three Finger Drag is already running." );
86
- CloseHandle (hMutex);
86
+ if (!CheckSingleInstance ()) {
87
87
return FALSE ;
88
88
}
89
89
90
- // Read user configuration values
91
- Application::ReadConfiguration ();
92
- ReadPrecisionTouchPadInfo ();
93
- ReadCursorSpeed ();
94
-
95
- // Initialize global strings
96
- LoadStringW (hInstance, IDS_APP_TITLE, title_bar_text, MAX_LOAD_STRING_LENGTH);
97
- LoadStringW (hInstance, IDS_SETTINGS_TITLE, settings_title_text, MAX_LOAD_STRING_LENGTH);
98
- LoadStringW (hInstance, IDC_THREEFINGERDRAG, main_window_class_name, MAX_LOAD_STRING_LENGTH);
99
- LoadStringW (hInstance, IDC_SETTINGS, settings_window_class_name, MAX_LOAD_STRING_LENGTH);
90
+ InitializeConfiguration ();
100
91
101
- // Register window classes
102
- RegisterWindowClass (hInstance, main_window_class_name, WndProc);
103
- RegisterWindowClass (hInstance, settings_window_class_name, SettingsWndProc);
104
-
105
- // Perform application initialization:
106
- if (!InitInstance (hInstance))
92
+ if (!InitInstance (current_instance))
107
93
{
108
94
ERROR (" Application initialization failed." );
109
95
return FALSE ;
110
96
}
111
97
112
- // Start threads
113
98
StartPeriodicUpdateThreads ();
114
-
115
- // First time running application
116
- if (Application::IsInitialStartup ()) {
117
- bool result = Popups::DisplayPrompt (" Would you like run ThreeFingerDrag on startup of Windows?" , " ThreeFingerDrag" );
118
- if (result)
119
- AddStartupRegistryKey ();
120
- Popups::ShowToastNotification (L" You can access the program in the system tray." , L" Welcome to ThreeFingerDrag!" );
121
- }
122
-
99
+ PerformAdditionalSteps ();
100
+
123
101
MSG msg;
124
-
125
- // Enter message loop and process incoming messages until WM_QUIT is received
126
102
while (GetMessage (&msg, nullptr , 0 , 0 ))
127
103
{
128
104
TranslateMessage (&msg);
@@ -142,8 +118,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
142
118
143
119
BOOL InitInstance (const HINSTANCE hInstance)
144
120
{
145
- current_instance = hInstance;
146
-
147
121
// Initialize WinToast notifications
148
122
if (!InitializeWindowsNotifications ()) {
149
123
ERROR (" Failed to initialize WinToast." );
@@ -235,9 +209,8 @@ LRESULT CALLBACK SettingsWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
235
209
case ID_TEXT_BOX:
236
210
wchar_t buffer[64 ];
237
211
GetWindowText ((HWND)lParam, buffer, 64 ); // get textbox text
238
- config->SetSkippedGestureFrames (_wtoi (buffer));// convert to integer (only numerical values are entered)
212
+ config->SetCancellationDelayMs (_wtoi (buffer));// convert to integer (only numerical values are entered)
239
213
Application::WriteConfiguration ();
240
- UpdateGestureProcessor ();
241
214
break ;
242
215
}
243
216
}
@@ -247,9 +220,9 @@ LRESULT CALLBACK SettingsWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
247
220
case ID_RUN_ON_STARTUP_CHECKBOX:
248
221
// Run on startup checkbox clicked
249
222
if (SendMessage (GetDlgItem (hWnd, ID_RUN_ON_STARTUP_CHECKBOX), BM_GETCHECK, 0 , 0 ) == BST_CHECKED)
250
- AddStartupRegistryKey ();
223
+ AddStartupTask ();
251
224
else
252
- RemoveStartupRegistryKey ();
225
+ RemoveStartupTask ();
253
226
break ;
254
227
}
255
228
break ;
@@ -264,7 +237,6 @@ LRESULT CALLBACK SettingsWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
264
237
265
238
config->SetGestureSpeed (tbPos);
266
239
Application::WriteConfiguration ();
267
- UpdateGestureProcessor ();
268
240
}
269
241
}
270
242
break ;
@@ -295,7 +267,7 @@ LRESULT CALLBACK SettingsWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
295
267
}
296
268
297
269
/* *
298
- * \brief Initializes window handles for GUI .
270
+ * \brief Create the main application window and the settings window .
299
271
*/
300
272
bool InitializeGUI () {
301
273
tray_icon_hwnd = CreateWindowEx (
@@ -371,18 +343,18 @@ bool InitializeGUI() {
371
343
HWND settings_spinner_hwnd = CreateWindowW (L" msctls_updown32" , NULL ,
372
344
WS_CHILD | WS_VISIBLE | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_SETBUDDYINT | UDS_NOTHOUSANDS,
373
345
pos_x, pos_y, 0 , label_height, // Adjust the height as needed
374
- settings_hwnd, (HMENU)ID_SKIPPED_FRAMES_SPINNER , current_instance, NULL ); // Spinner Controls ID as per your request.
346
+ settings_hwnd, (HMENU)ID_CANCELLATION_DELAY_SPINNER , current_instance, NULL );
375
347
376
348
SendMessage (settings_spinner_hwnd, UDM_SETBUDDY, (WPARAM)hwndTextBox, 0 );
377
- SendMessage (settings_spinner_hwnd, UDM_SETRANGE, 0 , MAKELONG (MAX_SKIPPED_FRAMES, MIN_SKIPPED_FRAMES ));
378
- SendMessage (settings_spinner_hwnd, UDM_SETPOS, 0 , MAKELONG (config->GetSkippedGestureFrames (), 0 ));
349
+ SendMessage (settings_spinner_hwnd, UDM_SETRANGE, 0 , MAKELONG (MAX_CANCELLATION_DELAY_MS, MIN_CANCELLATION_DELAY_MS ));
350
+ SendMessage (settings_spinner_hwnd, UDM_SETPOS, 0 , MAKELONG (config->GetCancellationDelayMs (), 0 ));
379
351
380
352
pos_x += 60 ;
381
353
382
354
// Label for numeric textbox
383
- HWND hwnd_spinner_label = CreateWindowW (L" STATIC" , L" Skipped initial frames of gesture movement " ,
355
+ HWND hwnd_spinner_label = CreateWindowW (L" STATIC" , L" Cancellation Delay (milliseconds) " ,
384
356
WS_CHILD | WS_VISIBLE | SS_LEFT,
385
- pos_x, pos_y, SETTINGS_WINDOW_WIDTH - margin, label_height, // Adjust these values as per your UI layout requirement.
357
+ pos_x, pos_y, SETTINGS_WINDOW_WIDTH - margin, label_height,
386
358
settings_hwnd, NULL , NULL , NULL );
387
359
388
360
SendMessage (hwnd_spinner_label, WM_SETFONT, reinterpret_cast <WPARAM>(normal_font), TRUE );
@@ -458,7 +430,7 @@ void CreateTrayMenu(const HWND hWnd)
458
430
void ShowSettingsWindow ()
459
431
{
460
432
// Update run on startup checkbox
461
- if (StartupRegistryKeyExists ())
433
+ if (TaskScheduler::TaskExists ( " ThreeFingerDrag " ))
462
434
SendMessage (settings_checkbox_hwnd, BM_SETCHECK, BST_CHECKED, 0 );
463
435
else
464
436
SendMessage (settings_checkbox_hwnd, BM_SETCHECK, BST_UNCHECKED, 0 );
@@ -501,10 +473,18 @@ void StartPeriodicUpdateThreads()
501
473
while (application_running)
502
474
{
503
475
std::this_thread::sleep_for (TOUCH_ACTIVITY_PERIOD_MS);
504
- if (!gesture_processor. IsDragging ())
476
+ if (!config-> IsCancellationStarted ()) {
505
477
continue ;
506
-
507
- gesture_processor.CheckDragInactivity ();
478
+ }
479
+ const auto now = std::chrono::high_resolution_clock::now ();
480
+ const std::chrono::duration<float > duration = now - config->GetCancellationTime ();
481
+ const float ms_since_cancellation = duration.count () * 1000 .0f ;
482
+ if (ms_since_cancellation < config->GetCancellationDelayMs ()) {
483
+ continue ;
484
+ }
485
+ Cursor::LeftMouseUp ();
486
+ config->SetDragging (false );
487
+ config->SetCancellationStarted (false );
508
488
}
509
489
});
510
490
}
@@ -541,7 +521,7 @@ void ReadPrecisionTouchPadInfo()
541
521
return ;
542
522
}
543
523
// Changes value from range [0, 20] to range [0.0 -> 1.0]
544
- gesture_processor. SetTouchSpeed (touch_speed * 5 / 100 .0f );
524
+ config-> SetPrecisionTouchCursorSpeed (touch_speed * 5 / 100 .0f );
545
525
}
546
526
547
527
/* *
@@ -561,15 +541,7 @@ void ReadCursorSpeed()
561
541
}
562
542
563
543
// Changes value from range [0, 20] to range [0.0 -> 1.0]
564
- gesture_processor.SetMouseSpeed (mouse_speed * 5 / 100 .0f );
565
- }
566
-
567
- /* *
568
- * \brief Updates the gesture processor with known config values
569
- */
570
- void UpdateGestureProcessor () {
571
- gesture_processor.SetGestureSpeed (config->GetGestureSpeed ());
572
- gesture_processor.SetSkippedFrameAmount (config->GetSkippedGestureFrames ());
544
+ config->SetMouseCursorSpeed (mouse_speed * 5 / 100 .0f );
573
545
}
574
546
575
547
@@ -614,8 +586,37 @@ bool InitializeWindowsNotifications() {
614
586
}
615
587
616
588
/* *
617
- * \brief Checks if the registry key for starting the program at system startup exists.
618
- * \return True if the registry key exists, false otherwise.
589
+ * \brief Adds the registry key for starting the program at system startup.
590
+ */
591
+ void AddStartupTask ()
592
+ {
593
+ // Remove possible existing registry key from previous version of application
594
+ if (StartupRegistryKeyExists ())
595
+ RemoveStartupRegistryKey ();
596
+
597
+ if (TaskScheduler::CreateLoginTask (" ThreeFingerDrag" , Application::ExePath ().u8string ()))
598
+ Popups::DisplayInfoMessage (" Startup task has been created successfully." );
599
+ else
600
+ Popups::DisplayErrorMessage (" An error occurred while trying to create the login task." );
601
+ }
602
+
603
+ /* *
604
+ * \brief Removes the registry key for starting the program at system startup. Displays a message box on success.
605
+ */
606
+ void RemoveStartupTask ()
607
+ {
608
+ // Remove possible existing registry key from previous version of application
609
+ if (StartupRegistryKeyExists ())
610
+ RemoveStartupRegistryKey ();
611
+
612
+ TaskScheduler::DeleteTask (" ThreeFingerDrag" );
613
+ if (!TaskScheduler::TaskExists (" ThreeFingerDrag" ))
614
+ Popups::DisplayInfoMessage (" Startup task has been removed successfully." );
615
+ }
616
+
617
+
618
+ /* *
619
+ * \return True if the registry key for the startup program name exists.
619
620
*/
620
621
bool StartupRegistryKeyExists ()
621
622
{
@@ -630,48 +631,63 @@ bool StartupRegistryKeyExists()
630
631
}
631
632
632
633
/* *
633
- * \brief Adds the registry key for starting the program at system startup.
634
+ * \brief Removes the registry key for starting the program at system startup. Displays a message box on success .
634
635
*/
635
- void AddStartupRegistryKey ()
636
+ void RemoveStartupRegistryKey ()
636
637
{
637
638
HKEY hKey;
638
- WCHAR app_path[MAX_PATH];
639
- const DWORD path_len = GetModuleFileName (nullptr , app_path, MAX_PATH);
640
- if (path_len == 0 || path_len == MAX_PATH)
641
- {
642
- ERROR (" Could not retrieve the application path!" );
643
- return ;
644
- }
645
639
LONG result = RegOpenKeyEx (HKEY_CURRENT_USER, STARTUP_REGISTRY_KEY, 0 , KEY_WRITE, &hKey);
646
640
if (result != ERROR_SUCCESS)
647
641
return ;
648
- result = RegSetValueEx (hKey, PROGRAM_NAME, 0 , REG_SZ, (BYTE*)app_path,
649
- (DWORD)(wcslen (app_path) + 1 ) * sizeof (wchar_t ));
650
- if (result == ERROR_SUCCESS)
651
- Popups::DisplayInfoMessage (" Startup task has been created successfully." );
652
- else
653
- Popups::DisplayErrorMessage (" An error occurred while trying to set the registry value." );
654
-
642
+ RegDeleteValue (hKey, PROGRAM_NAME);
655
643
RegCloseKey (hKey);
656
644
}
657
645
658
- /* *
659
- * \brief Removes the registry key for starting the program at system startup. Displays a message box on success.
660
- */
661
- void RemoveStartupRegistryKey ()
662
- {
663
- HKEY hKey;
664
- LONG result = RegOpenKeyEx (HKEY_CURRENT_USER, STARTUP_REGISTRY_KEY, 0 , KEY_WRITE, &hKey);
665
- if (result != ERROR_SUCCESS)
646
+ bool CheckSingleInstance () {
647
+ const HANDLE hMutex = CreateMutex (nullptr , TRUE , PROGRAM_NAME);
648
+ if (GetLastError () == ERROR_ALREADY_EXISTS)
666
649
{
667
- Popups::DisplayErrorMessage (" Registry key could not be found." );
668
- return ;
650
+ Popups::DisplayErrorMessage (" Another instance of Three Finger Drag is already running." );
651
+ CloseHandle (hMutex);
652
+ return false ;
669
653
}
670
- result = RegDeleteValue (hKey, PROGRAM_NAME);
671
- if (result == ERROR_SUCCESS)
672
- Popups::DisplayInfoMessage (" Startup task has been removed successfully." );
654
+ return true ;
655
+ }
673
656
674
- RegCloseKey (hKey);
657
+ void InitializeConfiguration () {
658
+ // Read user configuration values
659
+ Application::ReadConfiguration ();
660
+ ReadPrecisionTouchPadInfo ();
661
+ ReadCursorSpeed ();
662
+
663
+ // Initialize global strings
664
+ LoadStringW (current_instance, IDS_APP_TITLE, title_bar_text, MAX_LOAD_STRING_LENGTH);
665
+ LoadStringW (current_instance, IDS_SETTINGS_TITLE, settings_title_text, MAX_LOAD_STRING_LENGTH);
666
+ LoadStringW (current_instance, IDC_THREEFINGERDRAG, main_window_class_name, MAX_LOAD_STRING_LENGTH);
667
+ LoadStringW (current_instance, IDC_SETTINGS, settings_window_class_name, MAX_LOAD_STRING_LENGTH);
668
+
669
+ // Register window classes
670
+ RegisterWindowClass (current_instance, main_window_class_name, WndProc);
671
+ RegisterWindowClass (current_instance, settings_window_class_name, SettingsWndProc);
672
+ }
673
+
674
+ void PromptUserForStartupPreference () {
675
+ bool result = Popups::DisplayPrompt (" Would you like run ThreeFingerDrag on startup of Windows?" , " ThreeFingerDrag" );
676
+ if (result)
677
+ AddStartupTask ();
678
+ Popups::ShowToastNotification (L" You can access the program in the system tray." , L" Welcome to ThreeFingerDrag!" );
679
+ }
680
+
681
+ void PerformAdditionalSteps () {
682
+ // First time running application
683
+ if (Application::IsInitialStartup ())
684
+ PromptUserForStartupPreference ();
685
+
686
+ // Replace legacy startup registry key with login task automatically for previous users
687
+ if (StartupRegistryKeyExists ()) {
688
+ RemoveStartupRegistryKey ();
689
+ TaskScheduler::CreateLoginTask (" ThreeFingerDrag" , Application::ExePath ().u8string ());
690
+ }
675
691
}
676
692
677
693
ATOM RegisterWindowClass (HINSTANCE hInstance, WCHAR* className, WNDPROC wndProc)
0 commit comments