diff options
Diffstat (limited to 'minui')
-rw-r--r-- | minui/events.cpp | 124 | ||||
-rw-r--r-- | minui/graphics.cpp | 4 | ||||
-rw-r--r-- | minui/graphics_drm.cpp | 4 | ||||
-rw-r--r-- | minui/include/minui/minui.h | 1 | ||||
-rw-r--r-- | minui/resources.cpp | 24 |
5 files changed, 129 insertions, 28 deletions
diff --git a/minui/events.cpp b/minui/events.cpp index 7d0250e97..f331ed68a 100644 --- a/minui/events.cpp +++ b/minui/events.cpp @@ -22,6 +22,7 @@ #include <stdlib.h> #include <string.h> #include <sys/epoll.h> +#include <sys/inotify.h> #include <sys/ioctl.h> #include <sys/types.h> #include <unistd.h> @@ -33,6 +34,8 @@ #include "minui/minui.h" +constexpr const char* INPUT_DEV_DIR = "/dev/input"; + constexpr size_t MAX_DEVICES = 16; constexpr size_t MAX_MISC_FDS = 16; @@ -46,6 +49,8 @@ struct FdInfo { ev_callback cb; }; +static bool g_allow_touch_inputs = true; +static ev_callback g_saved_input_cb; static android::base::unique_fd g_epoll_fd; static epoll_event g_polled_events[MAX_DEVICES + MAX_MISC_FDS]; static int g_polled_events_count; @@ -60,6 +65,78 @@ static bool test_bit(size_t bit, unsigned long* array) { // NOLINT return (array[bit / BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0; } +static bool should_add_input_device(int fd, bool allow_touch_inputs) { + // Use unsigned long to match ioctl's parameter type. + unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT + + // Read the evbits of the input device. + if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) { + return false; + } + + // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also + // allowed if allow_touch_inputs is set. + if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) { + if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) { + return false; + } + } + + return true; +} + +static int inotify_cb(int fd, __unused uint32_t epevents) { + if (g_saved_input_cb == nullptr) return -1; + + // The inotify will put one or several complete events. + // Should not read part of one event. + size_t event_len; + int ret = ioctl(fd, FIONREAD, &event_len); + if (ret != 0) return -1; + + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir); + if (!dir) { + return -1; + } + + std::vector<int8_t> buf(event_len); + + ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf.data(), event_len)); + if (r != event_len) { + return -1; + } + + size_t offset = 0; + while (offset < event_len) { + struct inotify_event* pevent = reinterpret_cast<struct inotify_event*>(buf.data() + offset); + if (offset + sizeof(inotify_event) + pevent->len > event_len) { + // The pevent->len is too large and buffer will over flow. + // In general, should not happen, just make more stable. + return -1; + } + offset += sizeof(inotify_event) + pevent->len; + + pevent->name[pevent->len] = '\0'; + if (strncmp(pevent->name, "event", 5)) { + continue; + } + + android::base::unique_fd dfd(openat(dirfd(dir.get()), pevent->name, O_RDONLY)); + if (dfd == -1) { + break; + } + + if (!should_add_input_device(dfd, g_allow_touch_inputs)) { + continue; + } + + // Only add, we assume the user will not plug out and plug in USB device again and again :) + ev_add_fd(std::move(dfd), g_saved_input_cb); + } + + return 0; +} + int ev_init(ev_callback input_cb, bool allow_touch_inputs) { g_epoll_fd.reset(); @@ -68,7 +145,16 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) { return -1; } - std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/dev/input"), closedir); + android::base::unique_fd inotify_fd(inotify_init1(IN_CLOEXEC)); + if (inotify_fd.get() == -1) { + return -1; + } + + if (inotify_add_watch(inotify_fd, INPUT_DEV_DIR, IN_CREATE) < 0) { + return -1; + } + + std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(INPUT_DEV_DIR), closedir); if (!dir) { return -1; } @@ -80,22 +166,10 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) { android::base::unique_fd fd(openat(dirfd(dir.get()), de->d_name, O_RDONLY | O_CLOEXEC)); if (fd == -1) continue; - // Use unsigned long to match ioctl's parameter type. - unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)]; // NOLINT - - // Read the evbits of the input device. - if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) { + if (!should_add_input_device(fd, allow_touch_inputs)) { continue; } - // We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed. EV_ABS is also - // allowed if allow_touch_inputs is set. - if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) { - if (!allow_touch_inputs || !test_bit(EV_ABS, ev_bits)) { - continue; - } - } - epoll_event ev; ev.events = EPOLLIN | EPOLLWAKEUP; ev.data.ptr = &ev_fdinfo[g_ev_count]; @@ -116,6 +190,11 @@ int ev_init(ev_callback input_cb, bool allow_touch_inputs) { } g_epoll_fd.reset(epoll_fd.release()); + + g_saved_input_cb = input_cb; + g_allow_touch_inputs = allow_touch_inputs; + ev_add_fd(std::move(inotify_fd), inotify_cb); + return 0; } @@ -148,6 +227,7 @@ void ev_exit(void) { } g_ev_misc_count = 0; g_ev_dev_count = 0; + g_saved_input_cb = nullptr; g_epoll_fd.reset(); } @@ -170,13 +250,17 @@ void ev_dispatch(void) { } int ev_get_input(int fd, uint32_t epevents, input_event* ev) { - if (epevents & EPOLLIN) { - ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev))); - if (r == sizeof(*ev)) { - return 0; - } + if (epevents & EPOLLIN) { + ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev))); + if (r == sizeof(*ev)) { + return 0; } - return -1; + } + if (epevents & EPOLLHUP) { + // Delete this watch + epoll_ctl(g_epoll_fd, EPOLL_CTL_DEL, fd, nullptr); + } + return -1; } int ev_sync_key_state(const ev_set_key_callback& set_key_cb) { diff --git a/minui/graphics.cpp b/minui/graphics.cpp index 4d1f9b2d2..d34da5674 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -209,7 +209,7 @@ void gr_texticon(int x, int y, const GRSurface* icon) { void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) { uint32_t r32 = r, g32 = g, b32 = b, a32 = a; - if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) { + if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) { gr_current = (a32 << 24) | (r32 << 16) | (g32 << 8) | b32; } else { gr_current = (a32 << 24) | (b32 << 16) | (g32 << 8) | r32; @@ -348,6 +348,8 @@ int gr_init() { pixel_format = PixelFormat::ABGR; } else if (format == "RGBX_8888") { pixel_format = PixelFormat::RGBX; + } else if (format == "ARGB_8888") { + pixel_format = PixelFormat::ARGB; } else if (format == "BGRA_8888") { pixel_format = PixelFormat::BGRA; } else { diff --git a/minui/graphics_drm.cpp b/minui/graphics_drm.cpp index 7b2eed15d..95759e382 100644 --- a/minui/graphics_drm.cpp +++ b/minui/graphics_drm.cpp @@ -62,6 +62,8 @@ static int drm_format_to_bpp(uint32_t format) { case DRM_FORMAT_ABGR8888: case DRM_FORMAT_BGRA8888: case DRM_FORMAT_RGBX8888: + case DRM_FORMAT_RGBA8888: + case DRM_FORMAT_ARGB8888: case DRM_FORMAT_BGRX8888: case DRM_FORMAT_XBGR8888: case DRM_FORMAT_XRGB8888: @@ -87,6 +89,8 @@ std::unique_ptr<GRSurfaceDrm> GRSurfaceDrm::Create(int drm_fd, int width, int he format = DRM_FORMAT_ARGB8888; } else if (pixel_format == PixelFormat::RGBX) { format = DRM_FORMAT_XBGR8888; + } else if (pixel_format == PixelFormat::ARGB) { + format = DRM_FORMAT_BGRA8888; } else { format = DRM_FORMAT_RGB565; } diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h index 36bdcf103..163e41dc6 100644 --- a/minui/include/minui/minui.h +++ b/minui/include/minui/minui.h @@ -101,6 +101,7 @@ enum class PixelFormat : int { ABGR = 1, RGBX = 2, BGRA = 3, + ARGB = 4, }; // Initializes the graphics backend and loads font file. Returns 0 on success, or -1 on error. Note diff --git a/minui/resources.cpp b/minui/resources.cpp index 069a49529..f635acd1a 100644 --- a/minui/resources.cpp +++ b/minui/resources.cpp @@ -199,7 +199,7 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) { } PixelFormat pixel_format = gr_pixel_format(); - if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) { + if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) { png_set_bgr(png_ptr); } @@ -271,7 +271,7 @@ int res_create_multi_display_surface(const char* name, int* frames, int* fps, surface[i] = created_surface.release(); } - if (gr_pixel_format() == PixelFormat::ABGR || gr_pixel_format() == PixelFormat::BGRA) { + if (gr_pixel_format() == PixelFormat::ARGB || gr_pixel_format() == PixelFormat::BGRA) { png_set_bgr(png_ptr); } @@ -317,7 +317,7 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) { } PixelFormat pixel_format = gr_pixel_format(); - if (pixel_format == PixelFormat::ABGR || pixel_format == PixelFormat::BGRA) { + if (pixel_format == PixelFormat::ARGB || pixel_format == PixelFormat::BGRA) { png_set_bgr(png_ptr); } @@ -347,6 +347,10 @@ bool matches_locale(const std::string& prefix, const std::string& locale) { // match the locale string without the {script} section. // For instance, prefix == "en" matches locale == "en-US", prefix == "sr-Latn" matches locale // == "sr-Latn-BA", and prefix == "zh-CN" matches locale == "zh-Hans-CN". + if (prefix.empty()) { + return false; + } + if (android::base::StartsWith(locale, prefix)) { return true; } @@ -414,12 +418,18 @@ int res_create_localized_alpha_surface(const char* name, __unused int len = row[4]; char* loc = reinterpret_cast<char*>(&row[5]); - if (y + 1 + h >= height || matches_locale(loc, locale)) { + // We need to include one additional line for the metadata of the localized image. + if (y + 1 + h > height) { + printf("Read exceeds the image boundary, y %u, h %d, height %u\n", y, h, height); + return -8; + } + + if (matches_locale(loc, locale)) { printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y); auto surface = GRSurface::Create(w, h, w, 1); if (!surface) { - return -8; + return -9; } for (int i = 0; i < h; ++i, ++y) { @@ -428,7 +438,7 @@ int res_create_localized_alpha_surface(const char* name, } *pSurface = surface.release(); - break; + return 0; } for (int i = 0; i < h; ++i, ++y) { @@ -436,7 +446,7 @@ int res_create_localized_alpha_surface(const char* name, } } - return 0; + return -10; } void res_free_surface(GRSurface* surface) { |