Skip to content

Instantly share code, notes, and snippets.

@Foxite

Foxite/g502.c Secret

Created November 18, 2020 17:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Foxite/0436ccf2be19002651079679e6284dff to your computer and use it in GitHub Desktop.
Save Foxite/0436ccf2be19002651079679e6284dff to your computer and use it in GitHub Desktop.
// Based on this program for G600:
// https://github.com/mafik/logitech-g600-linux
// It's 99% the same program except for the fact that it looks for a G502 instead of G600, and some other minor changes I couldn't be bothered to write down.
#include <linux/input.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
struct input_event events[256];
const char kDir[] = "/dev/input/by-id/";
const char kPrefix[] = "usb-Logitech_Gaming_Mouse_G502_";
const char kSuffix[] = "-if01-event-kbd";
// ADD KEY->COMMAND MAPPINGS HERE:
const char *downCommands[] = {
//[scancode] = "command to run",
[4] = "xdotool mousedown 8", // G4 (mouse button 4 / backward)
[5] = "xdotool mousedown 9", // G5 (mouse button 5 / forward)
[6] = "xdotool key ctrl+w", // G7
[7] = "xdotool key ctrl+t", // G8
[8] = "xdotool mousedown 6", // Scroll left (not useful in current state)
[9] = "xdotool mousedown 7", // Scroll right (not useful in current state)
//[10] = "", // G+G4 (not practical)
//[11] = "", // G+G5 (not practical)
//[12] = "", // G+G7
[13] = "xdotool key ctrl+shift+t", // G+G8
[14] = "xdotool key ctrl+shift+Tab", // G+Scroll left
[15] = "xdotool key ctrl+Tab", // G+Scroll right
};
const char *upCommands[] = {
//[scancode] = "command to run",
[4] = "xdotool mouseup 8", // G4
[5] = "xdotool mouseup 9", // G5
[8] = "xdotool mouseup 6", // Scroll left (not useful in current state)
[9] = "xdotool mouseup 7", // Scroll right (not useful in current state)
};
int starts_with(const char* haystack, const char* prefix) {
size_t prefix_length = strlen(prefix), haystack_length = strlen(haystack);
if (haystack_length < prefix_length) return 0;
return strncmp(prefix, haystack, prefix_length) == 0;
}
int ends_with(const char* haystack, const char* suffix) {
size_t suffix_length = strlen(suffix), haystack_length = strlen(haystack);
if (haystack_length < suffix_length) return 0;
size_t haystack_end = haystack + haystack_length - suffix_length;
return strncmp(suffix, haystack_end, suffix_length) == 0;
}
// Returns non-0 on error.
int find_g600(char *path) {
//*path = kDir;
DIR *dir;
struct dirent *ent;
if (!(dir = opendir(kDir))) {
return 1;
}
while ((ent = readdir(dir))) {
if (starts_with(ent->d_name, kPrefix) && ends_with(ent->d_name, kSuffix)) {
strcpy(path, kDir);
strcat(path, ent->d_name);
printf("full path is %s\n", path);
//*path += ent->d_name;
closedir(dir);
return 0;
}
}
closedir(dir);
return 2;
}
int main() {
printf("Starting G502 Linux controller.\n\n");
printf("It's a good idea to configure G502 with Logitech Gaming Software before running this program:\n");
printf(" - assign left, right, middle mouse button and vertical mouse wheel to their normal functions\n");
printf(" - assign the G-Shift button to \"G-Shift\"\n");
printf(" - assign all other keys (including horizontal mouse wheel) to arbitrary (unique) keyboard keys\n");
printf("\n");
char path[1024];
int find_error = find_g600(&path);
if (find_error) {
printf("Error: Couldn't find G502 input device.\n");
switch(find_error) {
case 1:
printf("Suggestion: Maybe the expected directory (%s) is wrong. Check whether this directory exists and fix it by editing \"g600.c\".\n", kDir);
break;
case 2:
printf("Suggestion: Maybe the expected device prefix (%s) is wrong. Check whether a device with this prefix exists in %s and fix it by editing \"g600.cpp\".\n", kPrefix, kDir);
break;
}
printf("Suggestion: Maybe a permission is missing. Try running this program with with sudo.\n");
return 1;
}
int fd = open(path, O_RDONLY);
if (fd < 0) {
printf("Error: Couldn't open \"%s\" for reading.\n", path);
printf("Reason: %s.\n", strerror(errno));
printf("Suggestion: Maybe a permission is missing. Try running this program with with sudo.\n");
return 1;
}
ioctl(fd, EVIOCGRAB, 1);
printf("G502 controller started successfully.\n\n");
while (1) {
size_t n = read(fd, events, sizeof(events));
if (n <= 0) return 2;
if (n < sizeof(struct input_event) % 2) continue;
if (events[0].type != 4 || events[0].code != 4 || events[1].type != 1)
continue;
/*
for (int i = 0; i < 2; i++) {
printf("type %d, code %d, value %d (%d)\n", events[i].type, events[i].code, events[i].value, events[i].value & ~0x70000);
}
/*/
int pressed = events[1].value;
int scancode = events[0].value & ~0x70000;
const char* actionStr = (pressed) ? "+" : "-";
printf("%s %d.\n", actionStr, scancode);
const char *downCommand = downCommands[scancode], *upCommand = upCommands[scancode];
const char *cmdToRun = (pressed) ? downCommand : upCommand;
if (!cmdToRun || !strlen(cmdToRun)) continue;
printf("Executing: \"%s\"\n", cmdToRun);
system(cmdToRun);
//*/
}
close(fd);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment