layoutswitch.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. layoutswitch - a simple utility that shells out to `setxkbmap` to quickly
  3. alternate between two or more predefined keyboard layouts.
  4. USAGE: layoutswitch
  5. Switches to your next X11 layout, or back to your previous one.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. // number of layouts to be used:
  11. #define NUM_LAYOUTS 2
  12. // This array holds all our "desired" keyboard layouts to be cycled.
  13. // You need, however, to initiate it with a #define directive because C
  14. // will not accept a const statement (C++ apparently does)
  15. char* layoutholder[NUM_LAYOUTS];
  16. // this function queries `setxkbmap` and parses the value in there.
  17. char *
  18. getlayout()
  19. {
  20. char* layout = malloc(3); // hard assumption that layouts are always two letters (reasonable *most* of the times)
  21. FILE *p;
  22. p = popen("setxkbmap -query | grep layout | cut -d ' ' -f 6", "r");
  23. if (p == NULL) {
  24. printf("Error: setxkbmap not found. Please install it in this system.\n");
  25. return "er";
  26. }
  27. else {
  28. int ch; // counter for chars being read...
  29. int i = 0; // counter for new chars!
  30. while ((ch = fgetc(p)) != EOF) {
  31. layout[i] = ch;
  32. i++;
  33. }
  34. pclose(p);
  35. // patch up the string with NULL before you leave:
  36. layout[2] = '\0';
  37. return layout;
  38. }
  39. }
  40. void
  41. switchlayout(char* curlayout)
  42. {
  43. FILE* p;
  44. char stmt[15] = "setxkbmap "; // "prepared statement" a-la SQl
  45. for (int i = 0; i < NUM_LAYOUTS; i++) {
  46. // if there's a match go to the next layout in the array
  47. if (strncmp(curlayout, layoutholder[i], 2) == 0) {
  48. // however, if it's the last element, switch to #1:
  49. if ((i + 1) == NUM_LAYOUTS) {
  50. printf("Switching to %s layout.\n", layoutholder[0]);
  51. strcat(stmt, layoutholder[0]);
  52. p = popen(stmt, "r");
  53. break;
  54. }
  55. else {
  56. printf("Switching to %s layout.\n", layoutholder[i+1]);
  57. strcat(stmt, layoutholder[i+1]);
  58. p = popen(stmt, "r");
  59. break;
  60. }
  61. }
  62. }
  63. pclose(p);
  64. }
  65. int
  66. main(int argc, char* argv[])
  67. {
  68. layoutholder[0] = "us";
  69. layoutholder[1] = "br";
  70. // add as many layoutN as you wish to cycle through. i.e.:
  71. // layoutholder[2] = "be";
  72. // However, if you do, make sure you change the NUM_LAYOUTS constant!
  73. char* layout = getlayout();
  74. if (strncmp(layout, "er", 2) == 0) {
  75. // not able to query value. Clean up and quit.
  76. printf("Unable to query keyboard value.\n");
  77. free(layout);
  78. return 1;
  79. }
  80. switchlayout(layout);
  81. free(layout); // NECESSARY. Avoid the leak!
  82. return 0;
  83. }