From 09fbae8eabd8f65245a519207c6139bd9c4945fd Mon Sep 17 00:00:00 2001 From: hanez Date: Mon, 13 Jan 2025 06:07:48 +0100 Subject: [PATCH] Initial commit. --- LICENSE | 13 ++++++ Makefile | 6 +++ xtimer.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 xtimer.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..247aa29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2024 Johannes Findeisen + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7e6e97a --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +all: + $(CC) -Wall -o xtimer xtimer.c -lX11 -lXi + +clean: + rm -f xtimer + diff --git a/xtimer.c b/xtimer.c new file mode 100644 index 0000000..e421eb2 --- /dev/null +++ b/xtimer.c @@ -0,0 +1,121 @@ +/** + * xtimer is a program that executes a givin program after a given time if no + * X11 keybord or mouse input happend in the given time. + * + * Author: Johannes Findeisen - 2025 + * License: Apache-2.0 (see LICENSE) + */ + +#include +#include +#include +#include +#include +#include +#include // For INT_MAX and INT_MIN + +int main(int argc, char *argv[]) +{ + if (argc < 3) { + fprintf(stderr, "Usage: %s [arguments...]\n", + argv[0]); + return EXIT_FAILURE; + } + + // Validate the first parameter (wait time) + char *endptr; + long wait_time = strtol(argv[1], &endptr, 10); + + // Check for valid integer input + if (*endptr != '\0' || wait_time <= 0 || wait_time > INT_MAX) { + fprintf(stderr, +"Error: First argument must be a positive integer within the range 1 to %d.\n", +INT_MAX); + return EXIT_FAILURE; + } + + // Safely cast the wait_time to an int (it's safe after the above check) + int wait_time_seconds = (int)wait_time; + + // Initialize X11 display + Display *display = XOpenDisplay(NULL); + if (!display) { + fprintf(stderr, "Error: Unable to open X display.\n"); + return EXIT_FAILURE; + } + + // Check for XInput2 support + int opcode, event, error; + if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) { + fprintf(stderr, + "Error: X Input Extension is not supported on this display.\n"); + XCloseDisplay(display); + return EXIT_FAILURE; + } + + // Select events to monitor (keyboard, mouse clicks, and motion) + Window root = DefaultRootWindow(display); + XIEventMask evmask; + unsigned char mask[(XI_LASTEVENT + 7) / 8] = {0}; + evmask.deviceid = XIAllDevices; + evmask.mask_len = sizeof(mask); + evmask.mask = mask; + + XISetMask(mask, XI_KeyPress); + XISetMask(mask, XI_KeyRelease); + XISetMask(mask, XI_ButtonPress); + XISetMask(mask, XI_ButtonRelease); + XISetMask(mask, XI_Motion); // Listen for mouse motion events + + if (XISelectEvents(display, root, &evmask, 1) != Success) { + fprintf(stderr, "Error: Unable to select input events.\n"); + XCloseDisplay(display); + return EXIT_FAILURE; + } + + // Timer logic with input monitoring + time_t start_time, current_time; + start_time = time(NULL); + + while (1) { + current_time = time(NULL); + + // Check if the timer has expired + if (current_time - start_time >= wait_time_seconds) { + break; + } + + // Check for input events + while (XPending(display) > 0) { + XEvent event; + XNextEvent(display, &event); + + if (event.xcookie.type == GenericEvent && + event.xcookie.extension == opcode && // Use the opcode obtained earlier + XGetEventData(display, &event.xcookie)) { + XIDeviceEvent *xi_event = (XIDeviceEvent *)event.xcookie.data; + if (xi_event->evtype == XI_KeyPress || + xi_event->evtype == XI_ButtonPress || + xi_event->evtype == XI_Motion) { + // Reset the timer on input or mouse movement + start_time = time(NULL); + } + XFreeEventData(display, &event.xcookie); + } + } + + // Sleep briefly to reduce CPU usage + usleep(10000); // 10 milliseconds + } + + // Close the X display + XCloseDisplay(display); + + // Execute the program with optional arguments + execvp(argv[2], &argv[2]); + + // If execvp returns, an error occurred + perror("Error executing program"); + return EXIT_FAILURE; +} +