layouts.lisp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. ;;; layouts.lisp --- Switching keyboard layouts
  2. ;; Copyright © 2013-2016 Alex Kost <alezost@gmail.com>
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;;
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;; This file uses xkeyboard extension
  17. ;; <https://github.com/filonenko-mikhail/clx-xkeyboard> (i installed it
  18. ;; with quicklisp and compiled stumpwm with it). A big part of the
  19. ;; following code came from the stumpwm example of that extension.
  20. ;; This file provides some functions and commands for working with
  21. ;; layouts. I use it for:
  22. ;;
  23. ;; - different key bindings for different layouts,
  24. ;; - different layouts for different windows,
  25. ;; - setting internal input method in emacs if it is the current window
  26. ;; (by sending a specified key sequence to it) instead of the global
  27. ;; layout switching.
  28. ;;; Code:
  29. (in-package :stumpwm)
  30. ;; We need it because stumpwm opens display before extension definition.
  31. (xlib::initialize-extensions *display*)
  32. (xlib:enable-xkeyboard *display*)
  33. (defun layout-get-current-layout (display)
  34. "Return current keyboard layout."
  35. (xlib:device-state-locked-group (xlib:get-state display)))
  36. (defun layout-get-window-layout (win &optional (default nil))
  37. "Return keyboard layout of a specified window WIN.
  38. If a window does not have a layout property, return DEFAULT."
  39. (getf (xlib:window-plist (window-xwin win))
  40. :keyboard-layout default))
  41. (defun layout-window-changed (window previous-window)
  42. (let ((current-layout (layout-get-current-layout *display*)))
  43. (when previous-window
  44. (setf (getf (xlib:window-plist (window-xwin previous-window))
  45. :keyboard-layout)
  46. current-layout)
  47. (when window
  48. (let ((window-layout (layout-get-window-layout window current-layout)))
  49. (when (not (equal current-layout window-layout))
  50. (xlib:lock-group *display* :group window-layout)))))))
  51. (defun layout-group-changed (group previous-group)
  52. (let ((previous-window (group-current-window previous-group))
  53. (window (group-current-window group)))
  54. (layout-window-changed window previous-window)))
  55. (defcommand layout-enable-per-window () ()
  56. "Enable changing keyboard layouts per window."
  57. (add-hook *focus-window-hook* 'layout-window-changed)
  58. (add-hook *focus-group-hook* 'layout-group-changed))
  59. (defcommand layout-disable-per-window () ()
  60. "Disable changing keyboard layouts per window."
  61. (remove-hook *focus-window-hook* 'layout-window-changed)
  62. (remove-hook *focus-group-hook* 'layout-group-changed))
  63. (defcommand layout-set (num &optional key)
  64. ((:number "Layout number: ") :key)
  65. "Set keyboard layout to a specified layout (xkb group) number NUM.
  66. If current window is emacs, send a key sequence KEY to it (if specified)."
  67. (and (al/emacs-window-p)
  68. key
  69. (setq num 0)
  70. (al/send-key key))
  71. (xlib:lock-group *display* :group num)
  72. (xlib:display-finish-output *display*))
  73. ;;; layouts.lisp ends here