Initial commit
[indicator-keyboard-led.git] / indicator-keyboard-led.py
CommitLineData
fc1c0791
AIL
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# indicator-keyboard-led - simulate keyboard lock keys LED
5# Copyright (c) 2016 Adrian I Lam <adrianiainlam@gmail.com>
6#
7# Permission is hereby granted, free of charge, to any person obtaining a
8# copy of this software and associated documentation files (the "Software"),
9# to deal in the Software without restriction, including without limitation
10# the rights to use, copy, modify, merge, publish, distribute, sublicense,
11# and/or sell copies of the Software, and to permit persons to whom the
12# Software is furnished to do so, subject to the following conditions:
13#
14# The above copyright notice and this permission notice shall be included in
15# all copies or substantial portions of the Software.
16#
17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20# THE AUTHOR OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23# IN THE SOFTWARE.
24#
25# I would like to thank Tobias Schlitt <toby@php.net>, who wrote
26# indicator-chars <https://github.com/tobyS/indicator-chars> which I used
27# as a reference when writing this software.
28
29import signal
30import subprocess
31from os import path
32import argparse
33import gi
34gi.require_version('Gdk', '3.0')
35gi.require_version('Gtk', '3.0')
36gi.require_version('AppIndicator3', '0.1')
37from gi.repository import Gdk, Gtk, AppIndicator3
38
39class IndicatorKeyboardLED:
40 locks = { 'caps': 'Caps', 'num': 'Num', 'scr': 'Scroll' }
41
42 def __init__(self, short=False):
43 self.indicator = AppIndicator3.Indicator.new(
44 'indicator-keyboard-led',
45 path.join(path.dirname(path.realpath(__file__)), 'icon.svg'),
46 AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
47 self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
48
49 if short:
50 self.locks = { 'caps': 'C', 'num': 'N', 'scr': 'S' }
51
52 keymap = Gdk.Keymap.get_default()
53 keymap.connect('state-changed', self.update_indicator)
54 self.update_indicator(keymap)
55
56 menu = Gtk.Menu()
57 items = {
58 'caps' : Gtk.MenuItem.new_with_label('Caps Lock'),
59 'num' : Gtk.MenuItem.new_with_label('Num Lock'),
60 'scr' : Gtk.MenuItem.new_with_label('Scroll Lock')
61 }
62 menu.append(items['caps'])
63 menu.append(items['num'])
64 menu.append(items['scr'])
65
66 items['caps'].connect('activate', self.send_keypress, 'Caps_Lock')
67 items['num' ].connect('activate', self.send_keypress, 'Num_Lock')
68 items['scr' ].connect('activate', self.send_keypress, 'Scroll_Lock')
69
70 self.indicator.set_menu(menu)
71 menu.show_all()
72
73 def update_indicator(self, keymap):
74 label = '⚫' if keymap.get_caps_lock_state() else '⚪'
75 label += self.locks['caps'] + ' '
76 label += '⚫' if keymap.get_num_lock_state() else '⚪'
77 label += self.locks['num'] + ' '
78 label += '⚫' if keymap.get_scroll_lock_state() else '⚪'
79 label += self.locks['scr']
80 self.indicator.set_label(label, '')
81
82 def send_keypress(self, menuitem, keystroke):
83 subprocess.call(['xdotool', 'key', keystroke])
84
85if __name__ == '__main__':
86 signal.signal(signal.SIGINT, lambda signum, frame: Gtk.main_quit())
87
88 parser = argparse.ArgumentParser(
89 description='indicator-keyboard-led - simulate keyboard lock keys LED')
90 parser.add_argument('-s', '--short', dest='short', action='store_true',
91 help='use short label, i.e. ⚫C ⚫N ⚫S instead of ⚫Caps ⚫Num ⚫Scroll',
92 required=False)
93 args = parser.parse_args()
94
95 IndicatorKeyboardLED(short=args.short)
96 Gtk.main()