├── LICENSE
├── README.md
├── install.cpp
└── uninstall.cpp
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 hex
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cursor Context Menu Installer
2 |
3 | This project provides a simple way to add and remove a context menu item in Windows Explorer for opening directories with the Cursor application.
4 |
5 |
6 |
7 | 🤝 Show your support - give a ⭐️ if you liked the tool 🤝
8 |
9 |
10 |
11 |
12 |
13 |
14 | ---
15 |
16 | ## Installation
17 |
18 | To install the context menu item, run the `install` executable. By default, it will use the path `C:\Users\%USERNAME%\AppData\Local\Programs\cursor\Cursor.exe` for the Cursor application. You can also provide a custom path to the Cursor executable as a command-line argument.
19 |
20 | ## Compilation
21 | I used MinGW to compile this project, but you can use any other compiler that supports C++. Example commands:
22 |
23 | ```bash
24 | g++ -o install install.cpp -static
25 | g++ -o uninstall uninstall.cpp -static
26 | ```
27 |
28 | ## Usage Instructions
29 |
30 | To use the context menu item, follow these steps:
31 |
32 | 1. **Download the Executables:**
33 | - Visit the [releases page](https://github.com/hexcreator/open-with-cursor/releases) of this project.
34 | - Download the `install.exe` and `uninstall.exe` files from the latest release.
35 |
36 | 2. **Install the Context Menu Item:**
37 | - Run the `install.exe` file.
38 | - By default, it will use the path `C:\Users\%USERNAME%\AppData\Local\Programs\cursor\Cursor.exe` for the Cursor application.
39 | - If you want to use a custom path for the Cursor executable, provide the path as a command-line argument when running `install.exe`.
40 | - You can also provide the command-line argument `-a` to install the context menu item for all files, not just directories.
41 |
42 | 3. **Uninstall the Context Menu Item:**
43 | - Run the `uninstall.exe` file to remove the context menu item.
44 |
45 |
--------------------------------------------------------------------------------
/install.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | // Function to check if the current process is running with elevated privileges
8 | bool IsElevated()
9 | {
10 | BOOL isElevated = FALSE;
11 | HANDLE token = NULL;
12 |
13 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
14 | {
15 | TOKEN_ELEVATION elevation;
16 | DWORD size;
17 | if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size))
18 | {
19 | isElevated = elevation.TokenIsElevated;
20 | }
21 | CloseHandle(token);
22 | }
23 | return isElevated;
24 | }
25 |
26 | // Function to run a process as an administrator
27 | void RunAsAdmin(const char* path, const char* params)
28 | {
29 | SHELLEXECUTEINFOA sei = { sizeof(sei) };
30 | sei.lpVerb = "runas";
31 | sei.lpFile = path;
32 | sei.lpParameters = params;
33 | sei.hwnd = NULL;
34 | sei.nShow = SW_SHOWNORMAL;
35 |
36 | if (!ShellExecuteExA(&sei))
37 | {
38 | DWORD dwError = GetLastError();
39 | if (dwError == ERROR_CANCELLED)
40 | {
41 | std::cerr << "The operation was cancelled by the user." << std::endl;
42 | }
43 | else
44 | {
45 | std::cerr << "Error running as admin: " << dwError << std::endl;
46 | }
47 | exit(1);
48 | }
49 | }
50 |
51 | // Function to create a registry key and set its value
52 | bool CreateRegistryKey(HKEY hKeyParent, LPCSTR subKey, LPCSTR valueName, LPCSTR data)
53 | {
54 | HKEY hKey;
55 | LONG result = RegCreateKeyExA(hKeyParent, subKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
56 | if (result != ERROR_SUCCESS)
57 | {
58 | std::cerr << "Error creating registry key: " << result << std::endl;
59 | return false;
60 | }
61 |
62 | result = RegSetValueExA(hKey, valueName, 0, REG_SZ, (const BYTE*)data, strlen(data) + 1);
63 | if (result != ERROR_SUCCESS)
64 | {
65 | std::cerr << "Error setting registry value: " << result << std::endl;
66 | RegCloseKey(hKey);
67 | return false;
68 | }
69 |
70 | RegCloseKey(hKey);
71 | return true;
72 | }
73 |
74 | std::string GetCursorPath()
75 | {
76 | char path[MAX_PATH];
77 | if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, path)))
78 | {
79 | std::string fullPath = std::string(path) + "\\Programs\\cursor\\Cursor.exe";
80 | return fullPath;
81 | }
82 | return "";
83 | }
84 |
85 | bool FileExists(const std::string& path)
86 | {
87 | DWORD attrib = GetFileAttributesA(path.c_str());
88 | return (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
89 | }
90 |
91 | bool InstallContextMenu(const std::string& exePath, bool installForAllFiles)
92 | {
93 | if (!FileExists(exePath))
94 | {
95 | std::cerr << "Error: File not found: " << exePath << std::endl;
96 | return false;
97 | }
98 |
99 | // Add context menu for right-clicking inside a folder (existing behavior)
100 | std::string insideFolderSubKey = "Directory\\Background\\shell\\Open with Cursor";
101 | std::string insideFolderCommandKey = insideFolderSubKey + "\\command";
102 |
103 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, insideFolderSubKey.c_str(), NULL, "Open with Cursor"))
104 | {
105 | return false;
106 | }
107 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, insideFolderSubKey.c_str(), "Icon", exePath.c_str()))
108 | {
109 | return false;
110 | }
111 | std::string insideFolderCommandValue = "\"" + exePath + "\" \"%V\"";
112 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, insideFolderCommandKey.c_str(), NULL, insideFolderCommandValue.c_str()))
113 | {
114 | return false;
115 | }
116 |
117 | // Add context menu for right-clicking on a folder
118 | std::string onFolderSubKey = "Directory\\shell\\Open with Cursor";
119 | std::string onFolderCommandKey = onFolderSubKey + "\\command";
120 |
121 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, onFolderSubKey.c_str(), NULL, "Open with Cursor"))
122 | {
123 | return false;
124 | }
125 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, onFolderSubKey.c_str(), "Icon", exePath.c_str()))
126 | {
127 | return false;
128 | }
129 | std::string onFolderCommandValue = "\"" + exePath + "\" \"%1\"";
130 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, onFolderCommandKey.c_str(), NULL, onFolderCommandValue.c_str()))
131 | {
132 | return false;
133 | }
134 |
135 | // Add context menu for all files if requested
136 | if (installForAllFiles)
137 | {
138 | std::string allFilesSubKey = "*\\shell\\Open with Cursor";
139 | std::string allFilesCommandKey = allFilesSubKey + "\\command";
140 |
141 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, allFilesSubKey.c_str(), NULL, "Open with Cursor"))
142 | {
143 | return false;
144 | }
145 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, allFilesSubKey.c_str(), "Icon", exePath.c_str()))
146 | {
147 | return false;
148 | }
149 | std::string allFilesCommandValue = "\"" + exePath + "\" \"%1\"";
150 | if (!CreateRegistryKey(HKEY_CLASSES_ROOT, allFilesCommandKey.c_str(), NULL, allFilesCommandValue.c_str()))
151 | {
152 | return false;
153 | }
154 | }
155 |
156 | return true;
157 | }
158 |
159 | int main(int argc, char* argv[])
160 | {
161 | bool installForAllFiles = false;
162 | if (!IsElevated())
163 | {
164 | RunAsAdmin(argv[0], (argc > 1) ? argv[1] : "");
165 | return 0;
166 | }
167 |
168 | std::string exePath = GetCursorPath();
169 | for (int i = 1; i < argc; i++)
170 | {
171 | const std::string arg = std::string(argv[i]);
172 | if (arg == "-a" || arg == "--all")
173 | {
174 | installForAllFiles = true;
175 | }
176 | else {
177 | exePath = arg;
178 | }
179 | }
180 |
181 | if (exePath.empty())
182 | {
183 | MessageBoxA(NULL, "Failed to determine Cursor.exe path.", "Error", MB_OK | MB_ICONERROR);
184 | return 1;
185 | }
186 |
187 | if (InstallContextMenu(exePath, installForAllFiles))
188 | {
189 | std::string successMsg = "Context menu item installed successfully.\nPath: " + exePath;
190 | MessageBoxA(NULL, successMsg.c_str(), "Success", MB_OK | MB_ICONINFORMATION);
191 | }
192 | else
193 | {
194 | std::string errorMsg = "Failed to install context menu item.\nAttempted path: " + exePath;
195 | MessageBoxA(NULL, errorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
196 | }
197 |
198 | return 0;
199 | }
200 |
--------------------------------------------------------------------------------
/uninstall.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | bool IsElevated()
6 | {
7 | BOOL isElevated = FALSE;
8 | HANDLE token = NULL;
9 |
10 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
11 | {
12 | TOKEN_ELEVATION elevation;
13 | DWORD size;
14 | if (GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &size))
15 | {
16 | isElevated = elevation.TokenIsElevated;
17 | }
18 | CloseHandle(token);
19 | }
20 | return isElevated;
21 | }
22 |
23 | void RunAsAdmin(const char* path, const char* params)
24 | {
25 | SHELLEXECUTEINFOA sei = { sizeof(sei) };
26 | sei.lpVerb = "runas";
27 | sei.lpFile = path;
28 | sei.lpParameters = params;
29 | sei.hwnd = NULL;
30 | sei.nShow = SW_SHOWNORMAL;
31 |
32 | if (!ShellExecuteExA(&sei))
33 | {
34 | DWORD dwError = GetLastError();
35 | if (dwError == ERROR_CANCELLED)
36 | {
37 | std::cerr << "The operation was cancelled by the user." << std::endl;
38 | }
39 | else
40 | {
41 | std::cerr << "Error running as admin: " << dwError << std::endl;
42 | }
43 | exit(1);
44 | }
45 | }
46 |
47 | bool DeleteRegistryKey(HKEY hKeyParent, LPCSTR subKey) {
48 | LONG result = RegDeleteTreeA(hKeyParent, subKey);
49 | if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
50 | std::cerr << "Error deleting registry key: " << result << std::endl;
51 | return false;
52 | }
53 | return true;
54 | }
55 |
56 | bool UninstallContextMenu() {
57 | bool success = true;
58 |
59 | // Remove context menu for right-clicking inside a folder
60 | std::string insideFolderSubKey = "Directory\\Background\\shell\\Open with Cursor";
61 | success &= DeleteRegistryKey(HKEY_CLASSES_ROOT, insideFolderSubKey.c_str());
62 |
63 | // Remove context menu for right-clicking on a folder
64 | std::string onFolderSubKey = "Directory\\shell\\Open with Cursor";
65 | success &= DeleteRegistryKey(HKEY_CLASSES_ROOT, onFolderSubKey.c_str());
66 |
67 | // Remove context menu for all files
68 | std::string allFilesSubKey = "*\\shell\\Open with Cursor";
69 | success &= DeleteRegistryKey(HKEY_CLASSES_ROOT, allFilesSubKey.c_str());
70 |
71 | return success;
72 | }
73 |
74 | int main(int argc, char* argv[]) {
75 | if (!IsElevated())
76 | {
77 | RunAsAdmin(argv[0], (argc > 1) ? argv[1] : "");
78 | return 0;
79 | }
80 |
81 | if (UninstallContextMenu()) {
82 | std::string successMsg = "Context menu items uninstalled successfully.";
83 | MessageBoxA(NULL, successMsg.c_str(), "Success", MB_OK | MB_ICONINFORMATION);
84 | } else {
85 | std::string errorMsg = "Failed to uninstall some or all context menu items.";
86 | MessageBoxA(NULL, errorMsg.c_str(), "Error", MB_OK | MB_ICONERROR);
87 | }
88 |
89 | return 0;
90 | }
91 |
--------------------------------------------------------------------------------