Add feature: quit button, customize lock keys display
authorAdrian Iain Lam <adrianiainlam@gmail.com>
Mon, 29 Aug 2016 04:06:27 +0000 (12:06 +0800)
committerAdrian Iain Lam <adrianiainlam@gmail.com>
Mon, 29 Aug 2016 04:06:27 +0000 (12:06 +0800)
README.md
indicator-keyboard-led.py
screenshots/sc2.png
screenshots/sc4.png [new file with mode: 0644]
screenshots/sc5.png [new file with mode: 0644]
screenshots/sc6.png [new file with mode: 0644]

index 345b077..581faca 100644 (file)
--- a/README.md
+++ b/README.md
@@ -19,10 +19,6 @@ 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 (*)
@@ -40,7 +36,8 @@ distributions. To install the rest, run:
  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.)
+    appearance; use option `--order` to customize the order of the locks
+    displayed. See [Examples](#examples))
  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
@@ -49,6 +46,32 @@ distributions. To install the rest, run:
  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.
 
+## Examples
+
+![indicator default][sc1]  
+Default appearance. `python3 indicator-keyboard-led.py`
+
+![indicator short][sc3]  
+Short appearance. `python3 indicator-keyboard-led.py --short`
+
+![indicator CNS][sc4]  
+Order changed to Caps Num Scroll.
+`python3 indicator-keyboard-led.py --order CNS`
+
+![indicator NC][sc5]  
+Hide Scroll lock. `python3 indicator-keyboard-led.py --order NC`
+
+![indicator C short][sc6]
+Show Caps lock only, short appearance.
+`python3 indicator-keyboard-led.py --short --order C`
+
+[sc1]: screenshots/sc1.png
+[sc2]: screenshots/sc2.png
+[sc3]: screenshots/sc3.png
+[sc4]: screenshots/sc4.png
+[sc5]: screenshots/sc5.png
+[sc6]: screenshots/sc6.png
+
 ## Known bugs
 
 It seems to be a common problem that Scroll Lock is not usable in Ubuntu.
index 4d73f14..42b4161 100755 (executable)
@@ -30,6 +30,7 @@ import signal
 import subprocess
 from os import path
 import argparse
+import sys
 import gi
 gi.require_version('Gdk', '3.0')
 gi.require_version('Gtk', '3.0')
@@ -37,60 +38,83 @@ gi.require_version('AppIndicator3', '0.1')
 from gi.repository import Gdk, Gtk, AppIndicator3
 
 class IndicatorKeyboardLED:
-    locks = { 'num': 'Num', 'caps': 'Caps', 'scr': 'Scroll' }
+    locks = { 'N': 'Num', 'C': 'Caps', 'S': 'Scroll' }
     
-    def __init__(self, short=False):
+    def __init__(self, short=False, order='NCS'):
         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 = { 'num': 'N', 'caps': 'C', 'scr': 'S' }
+            self.locks = { 'N': 'N', 'C': 'C', 'S': 'S' }
 
         keymap = Gdk.Keymap.get_default()
-        keymap.connect('state-changed', self.update_indicator)
-        self.update_indicator(keymap)
+        keymap.connect('state-changed', self.update_indicator, order)
+        self.update_indicator(keymap, order)
 
         menu = Gtk.Menu()
         items = {
-            'num'  : Gtk.MenuItem.new_with_label('Num Lock'),
-            'caps' : Gtk.MenuItem.new_with_label('Caps Lock'),
-            'scr'  : Gtk.MenuItem.new_with_label('Scroll Lock')
+            'N': Gtk.MenuItem.new_with_label('Num Lock'),
+            'C': Gtk.MenuItem.new_with_label('Caps Lock'),
+            'S': Gtk.MenuItem.new_with_label('Scroll Lock')
         }
-        menu.append(items['num'])
-        menu.append(items['caps'])
-        menu.append(items['scr'])
+        items['N'].connect('activate', self.send_keypress, 'Num_Lock')
+        items['C'].connect('activate', self.send_keypress, 'Caps_Lock')
+        items['S'].connect('activate', self.send_keypress, 'Scroll_Lock')
+
+        for i in order:
+            menu.append(items[i])
 
-        items['num' ].connect('activate', self.send_keypress, 'Num_Lock')
-        items['caps'].connect('activate', self.send_keypress, 'Caps_Lock')
-        items['scr' ].connect('activate', self.send_keypress, 'Scroll_Lock')
+        quit_item = Gtk.MenuItem.new_with_label('Quit')
+        menu.append(Gtk.SeparatorMenuItem())
+        menu.append(quit_item)
+        quit_item.connect('activate', Gtk.main_quit)
 
         self.indicator.set_menu(menu)
         menu.show_all()
 
-    def update_indicator(self, keymap):
-        label = '⚫' if keymap.get_num_lock_state() else '⚪'
-        label += self.locks['num'] + ' '
-        label += '⚫' if keymap.get_caps_lock_state() else '⚪'
-        label += self.locks['caps'] + ' '
-        label += '⚫' if keymap.get_scroll_lock_state() else '⚪'
-        label += self.locks['scr']
-        self.indicator.set_label(label, '')
+    def update_indicator(self, keymap, order):
+        labels = []
+        for i in order:
+            if i == 'N':
+                state = keymap.get_num_lock_state()
+            elif i == 'C':
+                state = keymap.get_caps_lock_state()
+            elif i == 'S':
+                state = keymap.get_scroll_lock_state()
+            else:
+                raise ValueError('Invalid value in ORDER')
+            labels += [('⚫' if state else '⚪') + self.locks[i]]
+        self.indicator.set_label(' '.join(labels), '')
 
     def send_keypress(self, menuitem, keystroke):
         subprocess.call(['xdotool', 'key', keystroke])
 
+def validate_order(args):
+    args.order = args.order.upper()
+    for i in args.order:
+        if i not in ['N', 'C', 'S']:
+            sys.exit('Illegal character in ORDER. (Choices: [N, C, S])')
+    if len(args.order) != len(set(args.order)):
+        sys.exit('Repeated character in ORDER. '
+                 'Please specify each lock at most once.')
+
 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',
+        description='indicator-keyboard-led - simulate keyboard lock keys LED',
+        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+    parser.add_argument('-s', '--short', action='store_true',
         help='use short label, i.e. ⚫N ⚫C ⚫S instead of ⚫Num ⚫Caps ⚫Scroll',
         required=False)
+    parser.add_argument('-o', '--order', required=False, default='NCS',
+        help='specify the order of the locks displayed, e.g. CSN for '
+             '⚫Caps ⚫Scroll ⚫Num, or NC for ⚫Num ⚫Caps without Scroll lock')
     args = parser.parse_args()
-    
-    IndicatorKeyboardLED(short=args.short)
+    validate_order(args)
+
+    IndicatorKeyboardLED(short=args.short, order=args.order)
     Gtk.main()
index 67fdd98..228adee 100644 (file)
Binary files a/screenshots/sc2.png and b/screenshots/sc2.png differ
diff --git a/screenshots/sc4.png b/screenshots/sc4.png
new file mode 100644 (file)
index 0000000..8852e62
Binary files /dev/null and b/screenshots/sc4.png differ
diff --git a/screenshots/sc5.png b/screenshots/sc5.png
new file mode 100644 (file)
index 0000000..ca10484
Binary files /dev/null and b/screenshots/sc5.png differ
diff --git a/screenshots/sc6.png b/screenshots/sc6.png
new file mode 100644 (file)
index 0000000..b7db313
Binary files /dev/null and b/screenshots/sc6.png differ