refactor(cli): improve CLI UX with clearer messages and usage instructions
This commit is contained in:
6 files changed
+106
-62
No files matched your search
+2
-2
@@ -21,7 +21,7 @@ volatile sig_atomic_t reload_requested = 0;
|
||||
void cleanup_processes(int sig) {
|
||||
(void)sig;
|
||||
if (!is_daemon) {
|
||||
printf("\nShutting down VBX...\n");
|
||||
printf("\nShutting down VBX daemon...\n");
|
||||
}
|
||||
if (sound_pid > 0) {
|
||||
kill(sound_pid, SIGTERM);
|
||||
@@ -42,7 +42,7 @@ int require_running_pid(pid_t *out_pid) {
|
||||
pid_t running_pid = 0;
|
||||
if (!read_pidfile(pidfile_path, &running_pid) ||
|
||||
!process_is_running(running_pid)) {
|
||||
fprintf(stderr, "VBX: not running.\n");
|
||||
fprintf(stderr, "VBX daemon is not running.\n");
|
||||
return 0;
|
||||
}
|
||||
*out_pid = running_pid;
|
||||
|
||||
+3
-2
@@ -36,7 +36,7 @@ static void get_full_path(char *buffer, size_t buffer_size,
|
||||
int load_sound_config(const char *config_path) {
|
||||
FILE *file = fopen(config_path, "r");
|
||||
if (!file) {
|
||||
safe_fprintf(stderr, "Error: Cannot open config file: %s\n", config_path);
|
||||
safe_fprintf(stderr, "Error: Cannot open sound pack config: %s\n", config_path);
|
||||
perror("fopen");
|
||||
return -1;
|
||||
}
|
||||
@@ -69,7 +69,8 @@ int load_sound_config(const char *config_path) {
|
||||
json_object *root = json_tokener_parse(json_string);
|
||||
free(json_string);
|
||||
if (!root) {
|
||||
safe_fprintf(stderr, "Error: Invalid JSON in config file\n");
|
||||
safe_fprintf(stderr, "Error: Invalid JSON in sound pack config\n");
|
||||
safe_fprintf(stderr, "Check that the config.json file is properly formatted.\n");
|
||||
return -1;
|
||||
}
|
||||
const char *key_type = "single";
|
||||
|
||||
@@ -19,7 +19,8 @@ int init_audio() {
|
||||
if (g_sound_pack.is_multi)
|
||||
return 0;
|
||||
if (strlen(g_sound_pack.sound_file) == 0) {
|
||||
fprintf(stderr, "Error: No sound file specified in config\n");
|
||||
fprintf(stderr, "Error: No sound file specified in sound pack config\n");
|
||||
fprintf(stderr, "Check that your sound pack has a valid config.json file.\n");
|
||||
return -1;
|
||||
}
|
||||
if (access(g_sound_pack.sound_file, R_OK) != 0) {
|
||||
@@ -91,8 +92,9 @@ void *play_sound_thread(void *arg) {
|
||||
SF_INFO sf_info = {0};
|
||||
SNDFILE *sf = sf_open(file_to_play, SFM_READ, &sf_info);
|
||||
if (!sf) {
|
||||
fprintf(stderr, "Could not open sound file: %s (Error: %s)\n",
|
||||
file_to_play, sf_strerror(NULL));
|
||||
fprintf(stderr, "Error: Could not open sound file: %s\n", file_to_play);
|
||||
fprintf(stderr, "Details: %s\n", sf_strerror(NULL));
|
||||
fprintf(stderr, "Check that the audio file exists and is readable.\n");
|
||||
goto exit_cleanup;
|
||||
}
|
||||
pa_sample_spec ss = {.format = PA_SAMPLE_S16LE,
|
||||
|
||||
@@ -17,8 +17,8 @@ static int parse_device_argument(const char *optarg, const char *action,
|
||||
} else if (strcmp(optarg, "mouse") == 0) {
|
||||
*mouse_value = value;
|
||||
} else {
|
||||
safe_fprintf(stderr, "Error: Invalid %s device '%s'\n", action, optarg);
|
||||
safe_fprintf(stderr, "Use: keyboard, mouse, or both\n");
|
||||
safe_fprintf(stderr, "Error: Invalid device '%s' for %s\n", optarg, action);
|
||||
safe_fprintf(stderr, "Valid options: keyboard, mouse, or both\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -33,54 +33,54 @@ void print_usage(const char *program_name) {
|
||||
printf("VBX - Mechanical Keyboard Sound Simulator\n");
|
||||
printf("Version: %s\n\n", PROJECT_VERSION);
|
||||
|
||||
printf("DESCRIPTION:\n");
|
||||
printf(" VBX brings realistic mechanical keyboard sounds to every keystroke.\n");
|
||||
printf(" Run interactively or as a background daemon with live config reload.\n\n");
|
||||
|
||||
printf("USAGE:\n");
|
||||
printf(" %s [OPTIONS]\n\n", program_name);
|
||||
|
||||
printf("SOUND CONTROL:\n");
|
||||
printf(" -S, --sound PACK Keyboard sound pack (default: eg-oreo)\n");
|
||||
printf(" -M, --mouse PACK Mouse sound pack (default: ping)\n");
|
||||
printf(" -l, --list List available sound packs\n\n");
|
||||
printf("SOUND PACKS:\n");
|
||||
printf(" -S, --sound PACK Choose keyboard sound pack\n");
|
||||
printf(" -M, --mouse PACK Choose mouse sound pack\n");
|
||||
printf(" -l, --list Show available sound packs\n\n");
|
||||
|
||||
printf("VOLUME CONTROL:\n");
|
||||
printf(
|
||||
" -V, --volume LEVEL Set both keyboard & mouse volume [0-100]\n");
|
||||
printf(" -K, --keyboard-volume Set keyboard volume [0-100]\n");
|
||||
printf(" -O, --mouse-volume Set mouse volume [0-100]\n\n");
|
||||
printf(" -V, --volume LEVEL Set volume for both devices [0-100]\n");
|
||||
printf(" -K, --keyboard-volume Set keyboard volume only [0-100]\n");
|
||||
printf(" -O, --mouse-volume Set mouse volume only [0-100]\n\n");
|
||||
|
||||
printf("MUTE CONTROL:\n");
|
||||
printf(" -m, --mute[=DEVICE] Mute sounds (keyboard|mouse|both)\n");
|
||||
printf(" -u, --unmute[=DEVICE] Unmute sounds (keyboard|mouse|both)\n\n");
|
||||
printf("AUDIO CONTROL:\n");
|
||||
printf(" -m, --mute[=DEVICE] Mute audio (keyboard|mouse|both)\n");
|
||||
printf(" -u, --unmute[=DEVICE] Unmute audio (keyboard|mouse|both)\n");
|
||||
printf(" --enable[=DEVICE] Enable device sounds (keyboard|mouse|both)\n");
|
||||
printf(" --disable[=DEVICE] Disable device sounds (keyboard|mouse|both)\n\n");
|
||||
|
||||
printf("ENABLE/DISABLE:\n");
|
||||
printf(" --enable[=DEVICE] Enable sounds (keyboard|mouse|both)\n");
|
||||
printf(" --disable[=DEVICE] Disable sounds (keyboard|mouse|both)\n\n");
|
||||
|
||||
printf("DAEMON CONTROL:\n");
|
||||
printf(" -d, --daemon Run in background\n");
|
||||
printf("DAEMON MODE:\n");
|
||||
printf(" -d, --daemon Run in background with auto-reload\n");
|
||||
printf(" -s, --stop Stop background daemon\n\n");
|
||||
|
||||
printf("OTHER:\n");
|
||||
printf(" -v, --verbose Enable verbose output\n");
|
||||
printf(" -h, --help Show this help\n\n");
|
||||
printf("OTHER OPTIONS:\n");
|
||||
printf(" -v, --verbose Show detailed output\n");
|
||||
printf(" -h, --help Show this help message\n\n");
|
||||
|
||||
printf("EXAMPLES:\n");
|
||||
printf(" %s --list # List sound packs\n",
|
||||
printf("QUICK EXAMPLES:\n");
|
||||
printf(" %s --list # Browse sound packs\n",
|
||||
program_name);
|
||||
printf(" %s -S cherrymx-blue -V 75 # Cherry MX Blue at "
|
||||
"75%%\n",
|
||||
printf(" %s -S cherrymx-blue -V 75 # Cherry MX Blue at 75%%\n",
|
||||
program_name);
|
||||
printf(" %s --daemon # Run in background\n",
|
||||
printf(" %s --daemon # Start background service\n",
|
||||
program_name);
|
||||
printf(" %s --mute keyboard # Mute only keyboard\n",
|
||||
printf(" %s --mute keyboard # Mute keyboard only\n",
|
||||
program_name);
|
||||
printf(" %s --disable mouse # Disable mouse sounds\n",
|
||||
program_name);
|
||||
printf(
|
||||
" %s --disable mouse # Disable mouse sounds\n",
|
||||
program_name);
|
||||
printf(" %s --keyboard-volume 80 --mouse-volume 60 # Different volumes\n",
|
||||
program_name);
|
||||
printf("\n");
|
||||
printf("CONFIG: Settings are saved to ~/.vbx.json and auto-reload in "
|
||||
"daemon mode.\n");
|
||||
printf("CONFIGURATION:\n");
|
||||
printf(" Settings are saved to ~/.vbx.json and auto-reload in daemon mode.\n");
|
||||
printf(" Use --list to see available sound packs and their sources.\n");
|
||||
}
|
||||
|
||||
int parse_cli(int argc, char **argv, CliOptions *out) {
|
||||
@@ -126,7 +126,7 @@ int parse_cli(int argc, char **argv, CliOptions *out) {
|
||||
(n == 4 && strncmp(a, "help", 4) == 0) ||
|
||||
(n == 7 && strncmp(a, "verbose", 7) == 0))) {
|
||||
safe_fprintf(stderr, "Error: Unknown option '%s'\n", argv[i]);
|
||||
safe_fprintf(stderr, "Use '%s --help' for available options.\n", argv[0]);
|
||||
safe_fprintf(stderr, "Run '%s --help' to see available options.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
+43
-7
@@ -70,6 +70,9 @@ int main(int argc, char *argv[]) {
|
||||
char user_cfg_path[MAX_PATH_LENGTH];
|
||||
if (get_user_config_path(user_cfg_path, sizeof(user_cfg_path))) {
|
||||
if (access(user_cfg_path, R_OK) == 0) {
|
||||
if (verbose) {
|
||||
printf("Loading configuration from: %s\n", user_cfg_path);
|
||||
}
|
||||
char *cfg_keyboard_sound = NULL;
|
||||
char *cfg_mouse_sound = NULL;
|
||||
int cfg_keyboard_volume = volume;
|
||||
@@ -133,6 +136,14 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Show welcome message for first-time users
|
||||
if (access(user_cfg_path, F_OK) != 0 && !flag_daemon) {
|
||||
printf("\nWelcome to VBX!\n");
|
||||
printf("This appears to be your first time running VBX.\n");
|
||||
printf("A default configuration will be created at: %s\n", user_cfg_path);
|
||||
printf("\n");
|
||||
}
|
||||
build_pidfile_path(pidfile_path, 1024);
|
||||
if (flag_stop) {
|
||||
pid_t running_pid = 0;
|
||||
@@ -157,7 +168,7 @@ int main(int argc, char *argv[]) {
|
||||
for (int i = 0; i < 30; i++) {
|
||||
if (!process_is_running(running_pid)) {
|
||||
unlink(pidfile_path);
|
||||
printf("VBX stopped.\n");
|
||||
printf("VBX daemon stopped successfully.\n");
|
||||
if (sound_name_owned) {
|
||||
free(sound_name);
|
||||
}
|
||||
@@ -177,7 +188,7 @@ int main(int argc, char *argv[]) {
|
||||
if (mouse_sound_name_owned) {
|
||||
free(mouse_sound_name);
|
||||
}
|
||||
return errorf("VBX: process did not stop in time\n");
|
||||
return errorf("VBX: daemon did not stop in time. Try running 'vbx --stop' again.\n");
|
||||
}
|
||||
current_mute = read_runtime_mute_file();
|
||||
|
||||
@@ -213,18 +224,38 @@ int main(int argc, char *argv[]) {
|
||||
if (cli_opts.keyboard_mute >= 0) {
|
||||
current_keyboard_mute = cli_opts.keyboard_mute;
|
||||
config_updated = 1;
|
||||
if (current_keyboard_mute) {
|
||||
printf("Keyboard sounds muted.\n");
|
||||
} else {
|
||||
printf("Keyboard sounds unmuted.\n");
|
||||
}
|
||||
}
|
||||
if (cli_opts.mouse_mute >= 0) {
|
||||
current_mouse_mute = cli_opts.mouse_mute;
|
||||
config_updated = 1;
|
||||
if (current_mouse_mute) {
|
||||
printf("Mouse sounds muted.\n");
|
||||
} else {
|
||||
printf("Mouse sounds unmuted.\n");
|
||||
}
|
||||
}
|
||||
if (cli_opts.keyboard_enabled >= 0) {
|
||||
current_keyboard_enabled = cli_opts.keyboard_enabled;
|
||||
config_updated = 1;
|
||||
if (current_keyboard_enabled) {
|
||||
printf("Keyboard sounds enabled.\n");
|
||||
} else {
|
||||
printf("Keyboard sounds disabled.\n");
|
||||
}
|
||||
}
|
||||
if (cli_opts.mouse_enabled >= 0) {
|
||||
current_mouse_enabled = cli_opts.mouse_enabled;
|
||||
config_updated = 1;
|
||||
if (current_mouse_enabled) {
|
||||
printf("Mouse sounds enabled.\n");
|
||||
} else {
|
||||
printf("Mouse sounds disabled.\n");
|
||||
}
|
||||
}
|
||||
|
||||
write_runtime_mute_file(current_mute);
|
||||
@@ -240,6 +271,7 @@ int main(int argc, char *argv[]) {
|
||||
current_keyboard_enabled, current_mouse_enabled)) {
|
||||
safe_fprintf(stderr, "Warning: Failed to update config file %s\n",
|
||||
user_cfg_path);
|
||||
safe_fprintf(stderr, "Your settings will not be saved for next time.\n");
|
||||
} else if (verbose) {
|
||||
safe_fprintf(stderr, "Updated config file %s\n", user_cfg_path);
|
||||
}
|
||||
@@ -263,7 +295,7 @@ int main(int argc, char *argv[]) {
|
||||
current_keyboard_enabled, current_mouse_enabled)) {
|
||||
safe_fprintf(stderr, "Warning: Failed to write %s\n", user_cfg_path);
|
||||
} else if (verbose) {
|
||||
safe_fprintf(stderr, "Created default config %s\n", user_cfg_path);
|
||||
printf("Created default configuration: %s\n", user_cfg_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +346,7 @@ int main(int argc, char *argv[]) {
|
||||
free(mouse_sound_name);
|
||||
}
|
||||
safe_fprintf(stderr,
|
||||
"VBX already running (pid %ld). Use --stop to stop it.\n",
|
||||
"VBX daemon is already running (PID: %ld). Use 'vbx --stop' to stop it.\n",
|
||||
(long)existing);
|
||||
return 1;
|
||||
}
|
||||
@@ -358,7 +390,7 @@ int main(int argc, char *argv[]) {
|
||||
safe_strncpy(current_mouse_config_path, mouse_config_path, sizeof(current_mouse_config_path));
|
||||
safe_strncpy(current_mouse_sound_dir, mouse_sound_dir, sizeof(current_mouse_sound_dir));
|
||||
if (verbose && !is_daemon) {
|
||||
printf("VBX starting...\n");
|
||||
printf("Starting VBX daemon...\n");
|
||||
printf("Keyboard sound pack: %s\n", sound_name);
|
||||
printf("Mouse sound pack: %s\n", mouse_sound_name);
|
||||
printf("Keyboard config file: %s\n", config_path);
|
||||
@@ -368,7 +400,11 @@ int main(int argc, char *argv[]) {
|
||||
printf("Press Ctrl+C to exit.\n\n");
|
||||
} else {
|
||||
if (!is_daemon) {
|
||||
printf("VBX started with keyboard sound pack: %s, mouse sound pack: "
|
||||
printf("VBX daemon started successfully!\n");
|
||||
printf(" Keyboard: %s (volume: %d%%)\n", sound_name, current_keyboard_volume);
|
||||
printf(" Mouse: %s (volume: %d%%)\n", mouse_sound_name, current_mouse_volume);
|
||||
printf(" Config: ~/.vbx.json (auto-reload enabled)\n");
|
||||
printf("\nUse 'vbx --stop' to stop the daemon.\n");
|
||||
"%s\n",
|
||||
sound_name, mouse_sound_name);
|
||||
printf("Press Ctrl+C to exit.\n");
|
||||
@@ -443,7 +479,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
if (!is_daemon) {
|
||||
printf("VBX exited.\n");
|
||||
printf("VBX daemon exited.\n");
|
||||
}
|
||||
if (sound_name_owned) {
|
||||
free(sound_name);
|
||||
|
||||
+19
-14
@@ -141,10 +141,12 @@ int validate_keyboard_sound_pack(const char *sound_name) {
|
||||
basedir, sound_name) >= sizeof(config_path)) {
|
||||
fprintf(stderr, "Error: Sound pack path too long: %s/%s\n", basedir,
|
||||
sound_name);
|
||||
fprintf(stderr, "Try using a shorter sound pack name.\n");
|
||||
return 0;
|
||||
}
|
||||
if (access(config_path, R_OK) != 0) {
|
||||
fprintf(stderr, "Error: Config file not found: %s\n", config_path);
|
||||
fprintf(stderr, "Error: Sound pack config not found: %s\n", config_path);
|
||||
fprintf(stderr, "Make sure the sound pack directory contains a valid config.json file.\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -164,10 +166,12 @@ int validate_mouse_sound_pack(const char *sound_name) {
|
||||
basedir, sound_name) >= sizeof(config_path)) {
|
||||
fprintf(stderr, "Error: Sound pack path too long: %s/%s\n", basedir,
|
||||
sound_name);
|
||||
fprintf(stderr, "Try using a shorter sound pack name.\n");
|
||||
return 0;
|
||||
}
|
||||
if (access(config_path, R_OK) != 0) {
|
||||
fprintf(stderr, "Error: Config file not found: %s\n", config_path);
|
||||
fprintf(stderr, "Error: Sound pack config not found: %s\n", config_path);
|
||||
fprintf(stderr, "Make sure the sound pack directory contains a valid config.json file.\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -196,10 +200,10 @@ int list_sound_packs(void) {
|
||||
|
||||
printf("Available Sound Packs\n");
|
||||
printf("=====================\n\n");
|
||||
printf("KEYBOARD SOUNDS:\n");
|
||||
printf("----------------\n");
|
||||
printf("%-25s %-12s\n", "Name", "Source");
|
||||
printf("%-25s %-12s\n", "----", "------");
|
||||
printf("\nKEYBOARD SOUND PACKS:\n");
|
||||
printf("======================\n");
|
||||
printf("%-30s %-15s\n", "Pack Name", "Source");
|
||||
printf("%-30s %-15s\n", "---------", "------");
|
||||
if (user_keyboard_dir[0] && (dir = opendir(user_keyboard_dir)) != NULL) {
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
@@ -211,7 +215,7 @@ int list_sound_packs(void) {
|
||||
continue;
|
||||
}
|
||||
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
printf("%-25s %-12s\n", entry->d_name, "user");
|
||||
printf("%-30s %-15s\n", entry->d_name, "user");
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
@@ -228,15 +232,15 @@ int list_sound_packs(void) {
|
||||
continue;
|
||||
}
|
||||
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
printf("%-25s %-12s\n", entry->d_name, "pre-installed");
|
||||
printf("%-30s %-15s\n", entry->d_name, "system");
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
printf("\nMOUSE SOUNDS:\n");
|
||||
printf("-------------\n");
|
||||
printf("%-25s %-12s\n", "Name", "Source");
|
||||
printf("%-25s %-12s\n", "----", "------");
|
||||
printf("\nMOUSE SOUND PACKS:\n");
|
||||
printf("==================\n");
|
||||
printf("%-30s %-15s\n", "Pack Name", "Source");
|
||||
printf("%-30s %-15s\n", "---------", "------");
|
||||
if (user_mouse_dir[0] && (dir = opendir(user_mouse_dir)) != NULL) {
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
||||
@@ -248,7 +252,7 @@ int list_sound_packs(void) {
|
||||
continue;
|
||||
}
|
||||
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
printf("%-25s %-12s\n", entry->d_name, "user");
|
||||
printf("%-30s %-15s\n", entry->d_name, "user");
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
@@ -265,10 +269,11 @@ int list_sound_packs(void) {
|
||||
continue;
|
||||
}
|
||||
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
printf("%-25s %-12s\n", entry->d_name, "pre-installed");
|
||||
printf("%-30s %-15s\n", entry->d_name, "system");
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
printf("\nUsage: vbx -S <pack-name> for keyboard or vbx -M <pack-name> for mouse\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user