├── README.md └── k480_conf.c /README.md: -------------------------------------------------------------------------------- 1 | # k480_conf 2 | Configuration utility for setting up function keys on ubuntu for Logitech k480 keyboard. 3 | 4 | Inspiration came from this place: 5 | 6 | http://www.trial-n-error.de/posts/2012/12/31/logitech-k810-keyboard-configurator/ 7 | 8 | Mario made this tool for k810, I simply re-traced his steps for k480. 9 | My current configuration is Ubuntu 14.10 with k480 connected through some old d-link bluetooth adapter (on a desktop machine). 10 | 11 | ## Building the Tool 12 | 13 | To build the tool, first run the following command: 14 | 15 | `$ ./build.sh` 16 | 17 | ## Enable \ Disable Fn Keys 18 | 19 | This tool can automatically scan all of your blutooth devices for a K480 keyboard. 20 | 21 | To do so, run: 22 | 23 | `$ sudo ./k480_conf -f on` 24 | 25 | Or 26 | 27 | `$ sudo ./k480_conf -f off` 28 | 29 | To revert this behavior. 30 | 31 | ## Specifying a Device 32 | 33 | If you wish to specify the device to toggle, you can check which hidraw device is your logitech keyboard: 34 | 35 | `$ cat /sys/class/hidraw/hidraw*/device/uevent` 36 | 37 | Identify which one it is, e.g. hidraw2 (It might be any other, be sure which one it is before you proceed). 38 | 39 | 2) Then run following files to make function keys behave as function keys by default. (after downloading/cloning files from here): 40 | 41 | `$ sudo ./k480_conf -d /dev/hidraw2 -f on` 42 | 43 | You can also revert this behaviour by running: 44 | 45 | `$ sudo ./k480_conf -d /dev/hidraw2 -f off` 46 | which will make media keys default and function keys accessible by (fn + function key). 47 | 48 | To keep this setting after a restart you need to tell Ubuntu to run the script for you. 49 | 50 | 51 | Here is one of possible rules to be put in /etc/udev/rules.d/99-k480.rules: 52 | 53 | `SUBSYSTEM=="hidraw", ACTION=="add", SUBSYSTEMS=="bluetooth", ATTRS{address}=="00:1f:20:e3:6c:b6", RUN+="/opt/bin/k480_conf -d /dev/%k -f on"` 54 | -------------------------------------------------------------------------------- /k480_conf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 Emir Bucalovic www.betoneful.com 3 | * based on: 4 | * k810_conf.c by Mario Scholz 5 | * and pairing_tool.c from Benjamin Tissoires 6 | * see also https://lkml.org/lkml/2011/9/22/367 7 | * 8 | * This program is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * This program is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with this program. If not, see . 20 | */ 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #define HID_VENDOR_ID_LOGITECH (__u32)0x046d 33 | //If using k810 #define HID_DEVICE_ID_K810 (__s16)0xb319 34 | #define HID_DEVICE_ID_K480 (__s16)0xb330 35 | #define HID_DEVICE_ID_K480_ALT (__s16)0xb33c 36 | // The folowing HID_DEVICE_ID_K480_ALT2 uses the k380 key sequences! 37 | #define HID_DEVICE_ID_K480_ALT2 (__s16)0xb33d 38 | 39 | 40 | const char k480_seq_fkeys_on[] = {0x10, 0xff, 0x08, 0x1c, 0x00, 0x00, 0x00}; 41 | const char k480_seq_fkeys_off[] = {0x10, 0xff, 0x08, 0x1c, 0x01, 0x00, 0x00}; 42 | 43 | // from: https://github.com/jergusg/k380-function-keys-conf/blob/master/k380_conf.c 44 | const char k380_seq_fkeys_on[] = {0x10, 0xff, 0x0b, 0x1e, 0x00, 0x00, 0x00}; 45 | const char k380_seq_fkeys_off[] = {0x10, 0xff, 0x0b, 0x1e, 0x01, 0x00, 0x00}; 46 | 47 | //const char k810_seq_fkeys_on[] = {0x10, 0xff, 0x06, 0x15, 0x00, 0x00, 0x00}; 48 | //const char k810_seq_fkeys_off[] = {0x10, 0xff, 0x06, 0x15, 0x01, 0x00, 0x00}; 49 | 50 | const char opt_on[] = "on"; 51 | const char opt_off[] = "off"; 52 | 53 | void send(const int fd, const char * buf, const int len) 54 | { 55 | int res; 56 | 57 | /* Send sequence to the Device */ 58 | res = write(fd, buf, len); 59 | 60 | if (res < 0) 61 | { 62 | printf("Error: %d\n", errno); 63 | perror("write"); 64 | } 65 | else if (res == len) 66 | { 67 | printf("Configuration sent.\n"); 68 | } 69 | else 70 | { 71 | errno = ENOMEM; 72 | printf("write: %d were written instead of %d.\n", res, len); 73 | } 74 | } 75 | 76 | int main(int argc, char **argv) 77 | { 78 | int fd; 79 | int res; 80 | struct hidraw_devinfo info; 81 | const char * seq; 82 | char *dev = NULL; 83 | int flag_fkeys = 1; 84 | int c; 85 | 86 | if (argc < 5) 87 | { 88 | printf("Logitech K810 Keyboard Configurator (by trial-n-error)\n\n"); 89 | printf("Usage: %s -d /dev/hidraw{0,1,...} -f {on|off}:\n\n", argv[0]); 90 | printf("-d /dev/hidrawX\n" 91 | " Path to hidraw device. Determine by e.g.:\n" 92 | " ls /sys/class/hidraw/hidraw*/device/uevent\n" 93 | " and/or\n" 94 | " cat /sys/class/hidraw/hidraw*/device/uevent\n"); 95 | printf("-f \n" 96 | " To enable direct access to F-keys.\n"); 97 | printf("\n"); 98 | } 99 | 100 | while ((c = getopt (argc, argv, "d:f:")) != -1) 101 | { 102 | switch (c) 103 | { 104 | case 'd': 105 | dev = optarg; 106 | break; 107 | case 'f': 108 | if (strcmp(opt_on, optarg) == 0) 109 | { 110 | flag_fkeys = 1; 111 | } 112 | else if (strcmp(opt_off, optarg) == 0) 113 | { 114 | flag_fkeys = 0; 115 | } 116 | else 117 | { 118 | fprintf (stderr, "Option -%c requires argument '%s' or '%s'.\n", optopt, opt_on, opt_off); 119 | return 1; 120 | } 121 | break; 122 | case '?': 123 | if (optopt == 'f') 124 | { 125 | fprintf (stderr, "Option -%c requires an argument.\n", optopt); 126 | } 127 | else if (isprint (optopt)) 128 | { 129 | fprintf (stderr, "Unknown option `-%c'.\n", optopt); 130 | } 131 | else 132 | { 133 | fprintf (stderr, 134 | "Unknown option character `\\x%x'.\n", 135 | optopt); 136 | } 137 | return 1; 138 | default: 139 | abort (); 140 | } 141 | } 142 | 143 | char devPath [30]; 144 | 145 | /* TODO: get real device count? */ 146 | for (int i = 0; i < 10; i++) { 147 | printf("\n Trying device %d\n\n", i); 148 | snprintf(devPath, 30, "/dev/hidraw%d", i); 149 | dev = devPath; 150 | 151 | /* Open the Device with non-blocking reads. */ 152 | fd = open(dev, O_RDWR|O_NONBLOCK); 153 | if (fd < 0) 154 | { 155 | perror("Unable to open device"); 156 | continue; 157 | } 158 | 159 | /* Get Raw Info */ 160 | res = ioctl(fd, HIDIOCGRAWINFO, &info); 161 | if (res < 0) 162 | { 163 | perror("error while getting info from device"); 164 | continue; 165 | } 166 | else 167 | { 168 | if (info.bustype != BUS_BLUETOOTH || 169 | info.vendor != HID_VENDOR_ID_LOGITECH || 170 | (info.product != HID_DEVICE_ID_K480 && 171 | info.product != HID_DEVICE_ID_K480_ALT && 172 | info.product != HID_DEVICE_ID_K480_ALT2)) 173 | { 174 | errno = EPERM; 175 | perror("The given device is not a supported " 176 | "Logitech keyboard"); 177 | printf("Product : %x\n", info.product); 178 | 179 | continue; 180 | } 181 | } 182 | 183 | if (flag_fkeys) 184 | { 185 | printf("Sending ON: \n"); 186 | if (info.product == HID_DEVICE_ID_K480_ALT2) 187 | send(fd, k380_seq_fkeys_on, sizeof(k380_seq_fkeys_on)); 188 | else 189 | send(fd, k480_seq_fkeys_on, sizeof(k480_seq_fkeys_on)); 190 | } 191 | else 192 | { 193 | printf("Sending OFF: \n"); 194 | if (info.product == HID_DEVICE_ID_K480_ALT2) 195 | send(fd, k380_seq_fkeys_off, sizeof(k380_seq_fkeys_off)); 196 | else 197 | send(fd, k480_seq_fkeys_off, sizeof(k480_seq_fkeys_off)); 198 | } 199 | 200 | close(fd); 201 | return 0; 202 | } 203 | 204 | return 1; 205 | } 206 | --------------------------------------------------------------------------------