diff --git a/.gitignore b/.gitignore index 78d5d3a..5e82c02 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ chiaki.rb *.jks secret.tar keystore-env.sh +compile_commands.json +.ccls-cache diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c203ef..841e1d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ if(CHIAKI_ENABLE_CLI) endif() if(CHIAKI_ENABLE_GUI) + add_subdirectory(setsu) add_subdirectory(gui) endif() diff --git a/setsu/CMakeLists.txt b/setsu/CMakeLists.txt new file mode 100644 index 0000000..e230c49 --- /dev/null +++ b/setsu/CMakeLists.txt @@ -0,0 +1,24 @@ + +cmake_minimum_required(VERSION 3.2) + +project(libsetsu) + +option(SETSU_BUILD_TEST "Build testing executable for libsetsu" OFF) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +add_library(setsu + include/setsu.h + src/setsu.c) + +target_include_directories(setsu PUBLIC include) + +find_package(UDEV REQUIRED) +target_link_libraries(setsu UDEV::libudev) + +if(SETSU_BUILD_TEST) + add_executable(setsutest + test/main.c) + target_link_libraries(setsutest setsu) +endif() + diff --git a/setsu/cmake/FindUDEV.cmake b/setsu/cmake/FindUDEV.cmake new file mode 100644 index 0000000..3b6b1e0 --- /dev/null +++ b/setsu/cmake/FindUDEV.cmake @@ -0,0 +1,26 @@ +# Provides: UDEV::libudev + +set(_prefix UDEV) +set(_target "${_prefix}::libudev") + +find_package(PkgConfig REQUIRED) + +pkg_check_modules("${_prefix}" libudev) + +function(resolve_location) + +endfunction() + +if(${_prefix}_FOUND) + add_library("${_target}" INTERFACE IMPORTED) + target_link_libraries("${_target}" INTERFACE ${${_prefix}_LIBRARIES}) + target_include_directories("${_target}" INTERFACE ${${_prefix}_INCLUDE_DIRS}) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args("${_prefix}" + REQUIRED_VARS "${_prefix}_LIBRARIES" + VERSION_VAR "${_prefix}_VERSION") + +unset(_prefix) +unset(_target) diff --git a/setsu/include/setsu.h b/setsu/include/setsu.h new file mode 100644 index 0000000..8df7536 --- /dev/null +++ b/setsu/include/setsu.h @@ -0,0 +1,26 @@ +/* + * This file is part of Chiaki. + * + * Chiaki 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. + * + * Chiaki 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 Chiaki. If not, see . + */ + +#ifndef _SETSU_H +#define _SETSU_H + +typedef struct setsu_ctx_t SetsuCtx; + +SetsuCtx *setsu_ctx_new(); +void setsu_ctx_free(SetsuCtx *ctx); + +#endif diff --git a/setsu/src/setsu.c b/setsu/src/setsu.c new file mode 100644 index 0000000..76ae7d5 --- /dev/null +++ b/setsu/src/setsu.c @@ -0,0 +1,177 @@ + +#include + +#include + +#include +#include +#include + + +#include + +typedef struct setsu_device_t +{ + struct setsu_device_t *next; + char *path; + int fd; +} SetsuDevice; + +struct setsu_ctx_t +{ + struct udev *udev_ctx; + SetsuDevice *dev; +}; + + +static void scan(SetsuCtx *ctx); +static void update_device(SetsuCtx *ctx, struct udev_device *dev, bool added); +static SetsuDevice *connect(SetsuCtx *ctx, const char *path); +static void disconnect(SetsuCtx *ctx, SetsuDevice *dev); + +SetsuCtx *setsu_ctx_new() +{ + SetsuCtx *ctx = malloc(sizeof(SetsuCtx)); + if(!ctx) + return NULL; + + ctx->dev = NULL; + + ctx->udev_ctx = udev_new(); + if(!ctx->udev_ctx) + { + free(ctx); + return NULL; + } + + // TODO: monitor + + scan(ctx); + + return ctx; +} + +void setsu_ctx_free(SetsuCtx *ctx) +{ + while(ctx->dev) + disconnect(ctx, ctx->dev); + udev_unref(ctx->udev_ctx); + free(ctx); +} + +static void scan(SetsuCtx *ctx) +{ + struct udev_enumerate *udev_enum = udev_enumerate_new(ctx->udev_ctx); + if(!udev_enum) + return; + + if(udev_enumerate_add_match_subsystem(udev_enum, "input") < 0) + goto beach; + + if(udev_enumerate_add_match_property(udev_enum, "ID_INPUT_TOUCHPAD", "1") < 0) + goto beach; + + if(udev_enumerate_scan_devices(udev_enum) < 0) + goto beach; + + for(struct udev_list_entry *entry = udev_enumerate_get_list_entry(udev_enum); entry; entry = udev_list_entry_get_next(entry)) + { + const char *path = udev_list_entry_get_name(entry); + if(!path) + continue; + struct udev_device *dev = udev_device_new_from_syspath(ctx->udev_ctx, path); + if(!dev) + continue; + update_device(ctx, dev, true); + udev_device_unref(dev); + } + +beach: + udev_enumerate_unref(udev_enum); +} + +static bool is_device_interesting(struct udev_device *dev) +{ + static const char *device_ids[] = { + // vendor id, model id + "054c", "05c4", // DualShock 4 USB + NULL + }; + + // Filter mouse-device (/dev/input/mouse*) away and only keep the evdev (/dev/input/event*) one: + if(!udev_device_get_property_value(dev, "ID_INPUT_TOUCHPAD_INTEGRATION")) + return false; + + const char *vendor = udev_device_get_property_value(dev, "ID_VENDOR_ID"); + const char *model = udev_device_get_property_value(dev, "ID_MODEL_ID"); + if(!vendor || !model) + return false; + + for(const char **dev_id = device_ids; *dev_id; dev_id += 2) + { + if(!strcmp(vendor, dev_id[0]) && !strcmp(model, dev_id[1])) + return true; + } + return false; +} + +static void update_device(SetsuCtx *ctx, struct udev_device *dev, bool added) +{ + if(!is_device_interesting(dev)) + return; + const char *path = udev_device_get_devnode(dev); + if(!path) + return; + + for(SetsuDevice *dev = ctx->dev; dev; dev=dev->next) + { + if(!strcmp(dev->path, path)) + { + if(added) + return; // already added, do nothing + disconnect(ctx, dev); + } + } + connect(ctx, path); +} + +static SetsuDevice *connect(SetsuCtx *ctx, const char *path) +{ + SetsuDevice *dev = malloc(sizeof(SetsuDevice)); + if(!dev) + return NULL; + dev->path = strdup(path); + if(!dev->path) + { + free(dev); + return NULL; + } + + printf("connect %s\n", dev->path); + //dev->fd = open(dev->path, O_RDONLY | O_NONBLOCK); + + dev->next = ctx->dev; + ctx->dev = dev; + return dev; +} + +static void disconnect(SetsuCtx *ctx, SetsuDevice *dev) +{ + if(ctx->dev == dev) + ctx->dev = dev->next; + else + { + for(SetsuDevice *pdev = ctx->dev; pdev; pdev=pdev->next) + { + if(pdev->next == dev) + { + pdev->next = dev->next; + break; + } + } + } + + free(dev->path); + free(dev); +} + diff --git a/setsu/test/main.c b/setsu/test/main.c new file mode 100644 index 0000000..823c283 --- /dev/null +++ b/setsu/test/main.c @@ -0,0 +1,25 @@ + +#include + +#include +#include + +SetsuCtx *ctx; + +void quit() +{ + setsu_ctx_free(ctx); +} + +int main() +{ + ctx = setsu_ctx_new(); + if(!ctx) + { + printf("Failed to init setsu\n"); + return 1; + } + atexit(quit); + return 0; +} +