Add CLI interface

Fixes #5
This commit is contained in:
Johannes Marbach 2021-09-23 21:05:36 +02:00
parent 09061a5978
commit 51b1945744
8 changed files with 348 additions and 11 deletions

View file

@ -53,6 +53,21 @@ Below is a summary of contributions upstreamed thus far.
- [Automatic device discovery via libinput] (✅ merged)
- [Make it possible to use multiple devices with the libinput and XKB drivers] (⏳ in review)
# Usage
For an overview of available command line options, run unl0kr with the `-h` or `--help` argument.
```
$ unl0kr --help
Usage: unl0kr [OPTION]
Mandatory arguments to long options are mandatory for short options too.
-g, --geometry=NxM Force a display size of N horizontal times M vertical pixels
-h, --help Print this message and exit
-v, --verbose Enable more detailed logging output on STDERR
-V, --version Print the unl0kr version and exit
```
# Development
## Dependencies

108
command_line.c Normal file
View file

@ -0,0 +1,108 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "command_line.h"
#include "unl0kr.h"
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
/**
* Static prototypes
*/
/**
* Initialise a command line options struct with default values.
*
* @param opts pointer to the options struct
*/
static void init_opts(ul_cli_opts *cli_opts);
/**
* Output usage instructions.
*/
static void print_usage();
/**
* Static functions
*/
static void init_opts(ul_cli_opts *cli_opts) {
cli_opts->hor_res = -1;
cli_opts->ver_res = -1;
cli_opts->verbose = false;
}
static void print_usage() {
fprintf(stderr,
"Usage: unl0kr [OPTION]\n"
"\n"
"Mandatory arguments to long options are mandatory for short options too.\n"
" -g, --geometry=NxM Force a display size of N horizontal times M vertical pixels\n"
" -h, --help Print this message and exit\n"
" -v, --verbose Enable more detailed logging output on STDERR\n"
" -V, --version Print the unl0kr version and exit\n");
}
/**
* Public functions
*/
void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *cli_opts) {
init_opts(cli_opts);
struct option opts[] = {
{ "geometry", required_argument, NULL, 'g' },
{ "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ "version", no_argument, NULL, 'V' },
{ NULL, 0, NULL, 0 }
};
int opt, index = 0;
while ((opt = getopt_long(argc, argv, "g:hvV", opts, &index)) != -1) {
switch (opt) {
case 'g':
if (sscanf(optarg, "%ix%i", &(cli_opts->hor_res), &(cli_opts->ver_res)) != 2) {
fprintf(stderr, "Error: invalid geometry argument \"%s\"\n", optarg);
exit(EXIT_FAILURE);
}
break;
case 'h':
print_usage();
exit(EXIT_SUCCESS);
case 'v':
cli_opts->verbose = true;
break;
case 'V':
fprintf(stderr, "unl0kr %s\n", UL_VERSION);
exit(0);
default:
print_usage();
exit(EXIT_FAILURE);
}
}
}

47
command_line.h Normal file
View file

@ -0,0 +1,47 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_COMMAND_LINE_H
#define UL_COMMAND_LINE_H
#include <stdbool.h>
/**
* Options parsed from command line arguments
*/
typedef struct {
/* Horizontal display resolution */
int hor_res;
/* Vertical display resolution */
int ver_res;
/* Verbose mode. If true, provide more detailed logging output on STDERR. */
bool verbose;
} ul_cli_opts;
/**
* Parse command line arguments and exit on failure.
*
* @param argc number of provided command line arguments
* @param argv arguments as an array of strings
* @param cli_opts pointer for writing the parsed options into
*/
void ul_cli_parse_opts(int argc, char *argv[], ul_cli_opts *cli_opts);
#endif /* UL_COMMAND_LINE_H */

54
log.c Normal file
View file

@ -0,0 +1,54 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "log.h"
#include <stdarg.h>
/**
* Static variables
*/
static ul_log_level log_level = UL_LOG_LEVEL_ERROR;
/**
* Public functions
*/
void ul_set_log_level(ul_log_level level) {
log_level = level;
}
void ul_log(ul_log_level level, const char *format, ...) {
if (level > log_level) {
return;
}
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
}
void ul_print_cb(const char *msg) {
ul_log(UL_LOG_LEVEL_VERBOSE, "%s\n", msg);
}

59
log.h Normal file
View file

@ -0,0 +1,59 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_LOG_H
#define UL_LOG_H
#include <stdio.h>
/**
* Log levels
*/
typedef enum {
/* Errors only */
UL_LOG_LEVEL_ERROR = 0,
/* Include non-errors in log */
UL_LOG_LEVEL_VERBOSE = 1
} ul_log_level;
/**
* Set the log level.
*
* @param level new log level value
*/
void ul_set_log_level(ul_log_level level);
/**
* Log a message.
*
* @param level log level of the message
* @param format message format string
* @param ... parameters to fill into the format string
*/
void ul_log(ul_log_level level, const char *format, ...);
/**
* Handle an LVGL log message.
*
* @param msg message to print
*/
void ul_print_cb(const char *msg);
#endif /* UL_LOG_H */

42
main.c
View file

@ -18,9 +18,12 @@
*/
#include "command_line.h"
#include "cursor.h"
#include "libinput_multi.h"
#include "libinput_xkb.h"
#include "log.h"
#include "unl0kr.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/libinput_drv.h"
@ -329,17 +332,36 @@ static void keyboard_ready_cb(lv_event_t *event) {
* Main
*/
int main(void) {
/* Initialise lvgl and framebuffer driver */
lv_init();
fbdev_init();
int main(int argc, char *argv[]) {
/* Parse command line options */
ul_cli_opts opts;
ul_cli_parse_opts(argc, argv, &opts);
/* Query display size */
/* Set up log level */
if (opts.verbose) {
ul_set_log_level(UL_LOG_LEVEL_VERBOSE);
}
/* Announce ourselves */
ul_log(UL_LOG_LEVEL_VERBOSE, "unl0kr %s", UL_VERSION);
/* Initialise LVGL and set up logging callback */
lv_init();
lv_log_register_print_cb(ul_print_cb);
/* Initialise framebuffer driver and query display size */
fbdev_init();
uint32_t hor_res;
uint32_t ver_res;
fbdev_get_sizes(&hor_res, &ver_res);
fbdev_get_sizes(&hor_res, &ver_res);
// hor_res = ver_res * 0.6; /* Simulate mobile screen */
/* Override display size with command line options if necessary */
if (opts.hor_res > 0) {
hor_res = LV_MIN(hor_res, opts.hor_res);
}
if (opts.ver_res > 0) {
ver_res = LV_MIN(ver_res, opts.ver_res);
}
/* Prepare display buffer */
const size_t buf_size = hor_res * ver_res / 10; /* At least 1/10 of the display size is recommended */
@ -364,7 +386,7 @@ int main(void) {
lv_indev_t *keyboard_indevs[MAX_KEYBOARDS] = { NULL, NULL, NULL };
size_t num_keyboards = libinput_find_devs(LIBINPUT_CAPABILITY_KEYBOARD, keyboard_devices, MAX_KEYBOARDS, false);
for (int i = 0; i < num_keyboards; ++i) {
printf("found keyboard device %s\n", keyboard_devices[i]);
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting keyboard device %s\n", keyboard_devices[i]);
lv_indev_drv_init(&keyboard_indev_drvs[i]);
keyboard_indev_drvs[i].type = LV_INDEV_TYPE_KEYPAD;
keyboard_indev_drvs[i].read_cb = libinput_multi_read;
@ -385,7 +407,7 @@ int main(void) {
lv_indev_t *pointer_indevs[MAX_POINTER_DEVICES] = { NULL, NULL, NULL, NULL };
size_t num_pointer_devices = libinput_find_devs(LIBINPUT_CAPABILITY_POINTER, pointer_devices, MAX_POINTER_DEVICES, false);
for (int i = 0; i < num_pointer_devices; ++i) {
printf("found pointer device %s\n", pointer_devices[i]);
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting pointer device %s\n", pointer_devices[i]);
lv_indev_drv_init(&pointer_indev_drvs[i]);
pointer_indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
pointer_indev_drvs[i].read_cb = libinput_multi_read;
@ -410,7 +432,7 @@ int main(void) {
lv_indev_drv_t touchscreen_indev_drvs[MAX_TOUCHSCREENS];
size_t num_touchscreens = libinput_find_devs(LIBINPUT_CAPABILITY_TOUCH, touchscreens, MAX_TOUCHSCREENS, false);
for (int i = 0; i < num_touchscreens; ++i) {
printf("found touchscreen %s\n", touchscreens[i]);
ul_log(UL_LOG_LEVEL_VERBOSE, "Connecting touchscreen device %s\n", touchscreens[i]);
lv_indev_drv_init(&touchscreen_indev_drvs[i]);
touchscreen_indev_drvs[i].type = LV_INDEV_TYPE_POINTER;
touchscreen_indev_drvs[i].read_cb = libinput_multi_read;

View file

@ -24,11 +24,15 @@ project(
meson_version: '>=0.53.0'
)
add_project_arguments('-DUL_VERSION="@0@"'.format(meson.project_version()), language: ['c'])
unl0kr_sources = [
'command_line.c',
'cursor.c',
'main.c',
'log.c',
'libinput_multi.c',
'libinput_xkb.c',
'main.c',
'montserrat_extended_32.c',
'sq2lv_layouts.c',
]

28
unl0kr.h Normal file
View file

@ -0,0 +1,28 @@
/**
* Copyright 2021 Johannes Marbach
*
* This file is part of unl0kr, hereafter referred to as the program.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef UL_UNL0KR_H
#define UL_UNL0KR_H
#ifndef UL_VERSION
#define UL_VERSION "?" /* Just to silence IDE warning. Real version injected by meson during build. */
#endif
#endif /* UL_UNL0KR_H */