Initial commit
authorAdrian Iain Lam <adrianiainlam@gmail.com>
Wed, 24 Aug 2016 20:15:26 +0000 (04:15 +0800)
committerAdrian Iain Lam <adrianiainlam@gmail.com>
Wed, 24 Aug 2016 20:15:26 +0000 (04:15 +0800)
README.md [new file with mode: 0644]
icon.svg [new file with mode: 0644]
indicator-keyboard-led.py [new file with mode: 0755]
screenshots/sc1.png [new file with mode: 0644]
screenshots/sc2.png [new file with mode: 0644]
screenshots/sc3.png [new file with mode: 0644]

diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..86240b9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,86 @@
+# indicator-keyboard-led - simulate keyboard lock keys LED
+
+This is a Unity application indicator designed for keyboards without lock
+keys LED. It allows the user to check the state of the three locks (Caps lock,
+Num lock and Scroll lock) without requiring any mouse or keyboard action. It
+also allows the lock keys to be toggled with mouse clicks, which could be
+useful for keyboards without Scroll lock keys or malfunctioning keyboards.
+
+## Screenshots
+
+![indicator default][sc1]
+Default appearance of the indicator with Num lock on and Caps and Scroll locks
+off.
+
+![indicator menu][sc2]
+Menu of the indicator, shown on click. The locks can be toggled by clicking
+the respective item in the menu.
+
+![indicator short][sc3]
+Alternative (short) appearance of the indicator.
+
+[sc1]: screenshots/sc1.png
+[sc2]: screenshots/sc2.png
+[sc3]: screenshots/sc3.png
+
+## Dependencies
+ - Python 3 (*)
+ - GTK+ 3 (*)
+ - AppIndicator 3 (*)
+ - Python 3 GObject introspection (python3-gi)
+ - xdotool
+
+Those marked with (*) are probably installed by default in recent Ubuntu
+distributions. To install the rest, run:
+
+    sudo apt-get install python3-gi xdotool
+
+## Usage
+
+ 1. Install the dependencies listed above.
+ 2. Clone this repository.
+ 3. Add the script as a startup application. (Use option `--short` for short
+    appearance if desired.)
+ 4. Run the script manually for the first time. (Alternatively, log out
+    and log in again.)
+ 5. The indicator should be shown at the top right corner, with a filled circle
+    representing a lock turned on and an unfilled circle representing a lock
+    turned off.
+ 6. Clicking on the indicator should result in a menu with the three locks.
+    Clicking on the menu item would cause the corresponding lock to toggle.
+
+## License
+
+The program "indicator-keyboard-led.py" is released under the MIT License.
+Please refer to the file for the full text of the license.
+
+The icon "icon.svg" is released to the public domain.
+
+## Credits
+
+I would like to thank [Tobias Schlitt](https://github.com/tobyS), who wrote
+[indicator-chars](https://github.com/tobyS/indicator-chars) which I used
+as a reference when writing this software.
+
+The icon used in the indicator (icon.svg) is modified from the file
+"emblem-readonly.svg" by [Jakub Steiner](http://jimmac.musichall.cz)
+who released it to the public domain for the
+[Tango Icon Library](http://tango.freedesktop.org/Tango_Icon_Library).
+
+---
+
+## Motivation
+
+I was a user of [indicator-keylock][ind-kl], but only one key lock can be shown
+on the panel. I didn't like the Notify OSD events either.
+
+I then came across [lks-indicator][lks] and [indicator-xbdmod][xbdmod], but
+I didn't like the fact that they refresh the indicator on a regular time
+interval (every *x* milliseconds) rather than on state changes (only when
+the locks are toggled).
+
+I also thought it would be fun to be able to toggle the locks on-screen.
+
+[ind-kl]: https://launchpad.net/~tsbarnes/+archive/ubuntu/indicator-keylock
+[lks]: https://github.com/SergKolo/lks-indicator
+[xbdmod]: https://github.com/sneetsher/indicator-xkbmod
diff --git a/icon.svg b/icon.svg
new file mode 100644 (file)
index 0000000..d711e58
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg11300"
+   sodipodi:version="0.32"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="icon.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   version="1.1">
+  <metadata
+     id="metadata4">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:creator>
+          <dc:Agent>
+            <dc:title>Jakub Steiner</dc:title>
+          </dc:Agent>
+        </dc:creator>
+        <dc:contributor>Adrian I Lam</dc:contributor>
+        <dc:source>http://jimmac.musichall.cz</dc:source>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+        <dc:title>Caps Lock icon</dc:title>
+        <dc:subject>caps lock</dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/publicdomain/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="fill:#dfdbd2;"
+       d="M 22.9375 3.0058594 C 15.653591 3.2371063 10.824219 6.7870543
+          10.824219 14.107422 L 10.824219 21.578125 L 9.1855469 21.578125 C
+          7.9827519 21.578125 7 22.41744 7 23.46875 L 7 43.109375 C 7 44.160685
+          7.9827519 45.000002 9.1855469 45 L 38.84375 45 C 40.046563 45 41
+          44.160684 41 43.109375 L 41 23.46875 C 41 22.417442 40.046563
+          21.578125 38.84375 21.578125 L 37.175781 21.578125 L 37.205078
+          14.228516 C 37.205078 6.4577795 31.964524 3.1017737 24.03125
+          3.0058594 C 23.661384 3.0013294 23.295735 2.9944354 22.9375 3.0058594
+          z M 23.666016 7.9160156 C 23.79987 7.9129356 23.953309 7.9160156
+          24.091797 7.9160156 C 32.893949 7.9160156 32.217687 14.260075
+          32.347656 16.150391 L 32.347656 21.578125 L 15.773438 21.578125 L
+          15.773438 16.181641 C 15.742128 14.306334 15.227932 8.1089033
+          23.666016 7.9160156 z M 22.21875 24 L 25.75 24 C 26.442384 25.281385
+          27.114759 26.580467 27.767578 27.896484 C 28.420397 29.212502
+          29.073744 30.598189 29.726562 32.052734 C 30.399164 33.50728
+          31.083007 35.048076 31.775391 36.675781 C 32.487557 38.303487
+          33.228487 40.077922 34 42 L 29.964844 42 C 29.68789 41.290043
+          29.400252 40.589125 29.103516 39.896484 C 28.80678 39.203844
+          28.521094 38.492898 28.244141 37.765625 L 19.578125 37.765625 C
+          19.301171 38.492898 19.015486 39.211918 18.71875 39.921875 L
+          17.886719 42 L 14 42 C 14.771513 40.077922 15.502929 38.303487
+          16.195312 36.675781 C 16.887696 35.048076 17.560072 33.50728
+          18.212891 32.052734 C 18.885492 30.598189 19.548353 29.212502
+          20.201172 27.896484 C 20.853991 26.580467 21.526366 25.281385
+          22.21875 24 z M 23.910156 27.480469 C 23.455161 28.398218 22.931362
+          29.516014 22.337891 30.832031 C 21.764201 32.148049 21.16038
+          33.576062 20.527344 35.117188 L 27.292969 35.117188 C 26.659932
+          33.576062 26.046597 32.138021 25.453125 30.804688 C 24.859653
+          29.471354 24.345369 28.363586 23.910156 27.480469 z "
+       id="path2086" />
+  </g>
+</svg>
diff --git a/indicator-keyboard-led.py b/indicator-keyboard-led.py
new file mode 100755 (executable)
index 0000000..44e02a0
--- /dev/null
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# indicator-keyboard-led - simulate keyboard lock keys LED
+# Copyright (c) 2016 Adrian I Lam <adrianiainlam@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHOR OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+# I would like to thank Tobias Schlitt <toby@php.net>, who wrote
+# indicator-chars <https://github.com/tobyS/indicator-chars> which I used
+# as a reference when writing this software.
+
+import signal
+import subprocess
+from os import path
+import argparse
+import gi
+gi.require_version('Gdk', '3.0')
+gi.require_version('Gtk', '3.0')
+gi.require_version('AppIndicator3', '0.1')
+from gi.repository import Gdk, Gtk, AppIndicator3
+
+class IndicatorKeyboardLED:
+    locks = { 'caps': 'Caps', 'num': 'Num', 'scr': 'Scroll' }
+    
+    def __init__(self, short=False):
+        self.indicator = AppIndicator3.Indicator.new(
+            'indicator-keyboard-led',
+            path.join(path.dirname(path.realpath(__file__)), 'icon.svg'),
+            AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
+        self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
+        
+        if short:
+            self.locks = { 'caps': 'C', 'num': 'N', 'scr': 'S' }
+
+        keymap = Gdk.Keymap.get_default()
+        keymap.connect('state-changed', self.update_indicator)
+        self.update_indicator(keymap)
+
+        menu = Gtk.Menu()
+        items = {
+            'caps' : Gtk.MenuItem.new_with_label('Caps Lock'),
+            'num'  : Gtk.MenuItem.new_with_label('Num Lock'),
+            'scr'  : Gtk.MenuItem.new_with_label('Scroll Lock')
+        }
+        menu.append(items['caps'])
+        menu.append(items['num'])
+        menu.append(items['scr'])
+
+        items['caps'].connect('activate', self.send_keypress, 'Caps_Lock')
+        items['num' ].connect('activate', self.send_keypress, 'Num_Lock')
+        items['scr' ].connect('activate', self.send_keypress, 'Scroll_Lock')
+
+        self.indicator.set_menu(menu)
+        menu.show_all()
+
+    def update_indicator(self, keymap):
+        label = '⚫' if keymap.get_caps_lock_state() else '⚪'
+        label += self.locks['caps'] + ' '
+        label += '⚫' if keymap.get_num_lock_state() else '⚪'
+        label += self.locks['num'] + ' '
+        label += '⚫' if keymap.get_scroll_lock_state() else '⚪'
+        label += self.locks['scr']
+        self.indicator.set_label(label, '')
+
+    def send_keypress(self, menuitem, keystroke):
+        subprocess.call(['xdotool', 'key', keystroke])
+
+if __name__ == '__main__':
+    signal.signal(signal.SIGINT, lambda signum, frame: Gtk.main_quit())
+    
+    parser = argparse.ArgumentParser(
+        description='indicator-keyboard-led - simulate keyboard lock keys LED')
+    parser.add_argument('-s', '--short', dest='short', action='store_true',
+        help='use short label, i.e. ⚫C ⚫N ⚫S instead of ⚫Caps ⚫Num ⚫Scroll',
+        required=False)
+    args = parser.parse_args()
+    
+    IndicatorKeyboardLED(short=args.short)
+    Gtk.main()
diff --git a/screenshots/sc1.png b/screenshots/sc1.png
new file mode 100644 (file)
index 0000000..394422e
Binary files /dev/null and b/screenshots/sc1.png differ
diff --git a/screenshots/sc2.png b/screenshots/sc2.png
new file mode 100644 (file)
index 0000000..da9d3b5
Binary files /dev/null and b/screenshots/sc2.png differ
diff --git a/screenshots/sc3.png b/screenshots/sc3.png
new file mode 100644 (file)
index 0000000..2424054
Binary files /dev/null and b/screenshots/sc3.png differ