├── 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 | X (formerly Twitter) Follow 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 | --------------------------------------------------------------------------------