Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Python script to monitor caps lock, num lock and scroll lock keys and show a notification with their status(Qt5)
#!/usr/bin/env python3
#
# References:
# https://github.com/PyUserInput/PyUserInput
#
# Author: Alexandre C Vieira <acamargo.vieira@gmail.com>
#
# http://alexandrecvieira.droppages.com
#
# I did this little program because I didn't find any indicators that worked the way I wanted, this is the first version with kdialog
#
# Installation:
# sudo apt install kdialog
# sudo mkdir /opt/ss-key-indicator
# sudo cp super-simple-keyboard-indicator /opt/ss-key-indicator/ss-key-indicator
# Set it to boot with the system: python3 /opt/ss-key-indicator/ss-key-indicator
#
__appname__ = "Super Simple Keyboard Indicator"
__version__ = "0.10"
__author__ = "Alexandre C Vieira"
__license__ = "GNU GPL 2.0 or later"
import os, subprocess
from pykeyboard import PyKeyboardEvent
TIMEOUT = 3
class MonitorSuper(PyKeyboardEvent):
def tap(self, keycode, character, press):
if press:
None
else:
if character == 'Caps_Lock':
capsStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 5")
if capsStatus == 'off':
cmd = "kdialog --title \"%s\" --passivepopup \"<p style='text-align: center'>Caps Lock <b>OFF</b></p>\" %s" % (__appname__, TIMEOUT)
os.system(cmd)
if capsStatus == 'on':
cmd = "kdialog --title \"%s\" --passivepopup \"<p style='text-align: center'>Caps Lock <b>ON</b></p>\" %s" % (__appname__, TIMEOUT)
os.system(cmd)
if character == 'Num_Lock':
numStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 9")
if numStatus == 'off':
cmd = "kdialog --title \"%s\" --passivepopup \"<p style='text-align: center'>Num Lock <b>OFF</b></p>\" %s" % (__appname__, TIMEOUT)
os.system(cmd)
if numStatus == 'on':
cmd = "kdialog --title \"%s\" --passivepopup \"<p style='text-align: center'>Num Lock <b>ON</b></p>\" %s" % (__appname__, TIMEOUT)
os.system(cmd)
if character == 'Scroll_Lock':
scrollStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 13")
if scrollStatus == 'off':
cmd = "kdialog --title \"%s\" --passivepopup \"<p style='text-align: center'>Scroll Lock <b>OFF</b></p>\" %s" % (__appname__, TIMEOUT)
os.system(cmd)
if scrollStatus == 'on':
cmd = "kdialog --title \"%s\" --passivepopup \"<p style='text-align: center'>Scroll Lock <b>ON</b></p>\" %s" % (__appname__, TIMEOUT)
os.system(cmd)
mon = MonitorSuper()
mon.run()
#!/usr/bin/env python3
#
# References:
# https://pynput.readthedocs.io/en/latest/keyboard.html
# https://www.devdungeon.com/content/python3-qt5-pyqt5-tutorial
#
# Author: Alexandre C Vieira <acamargo.vieira@gmail.com>
#
# http://alexandrecvieira.droppages.com
#
# I did this little program because I didn't find any indicators that worked the way I wanted, this is the second version with QSystemTrayIcon message api
#
# Installation:
# sudo pip3 install pynput
# sudo mkdir /opt/ss-key-indicator
# sudo cp super-simple-keyboard-indicator2 /opt/ss-key-indicator/ss-key-indicator
# Set it to boot with the system: python3 /opt/ss-key-indicator/ss-key-indicator
#
# Signals: 0 = Off
# 1 = On
# 2 = On(startup does not show notification)
# 3 = Off(startup does not show notification)
#
__appname__ = "Super Simple Key Indicator"
__version__ = "0.20"
__author__ = "Alexandre C Vieira"
__license__ = "GNU GPL 2.0 or later"
import sys, os, subprocess
from PyQt5.QtCore import Qt, QSize, QThread, pyqtSignal, QObject
from pynput import keyboard
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QAction, QMenu, qApp
from PyQt5.QtGui import QPixmap, QPainter, QColor, QIcon, QFont
ICONSIZE = 22
FONT = "Sans"
FONTSIZE = 12
FONTCOLOR = "white"
FONTCOLORINATIVE = "gray"
CAPS_LOCK = "C"
NUM_LOCK = "N"
SCROLL_LOCK = "S"
TIMEOUT = 3000 # miliseconds
def getIcon(iconType, onOff):
pixmap = QPixmap(QSize(ICONSIZE, ICONSIZE))
pixmap.fill(QColor("transparent"))
if onOff == "on":
painter = QPainter()
painter.begin(pixmap)
font = QFont(FONT, FONTSIZE, QFont.Black)
painter.setFont(font)
painter.setPen(QColor(FONTCOLOR))
painter.drawText(pixmap.rect(), Qt.AlignCenter, iconType)
painter.end()
if onOff == "off":
painter = QPainter()
painter.begin(pixmap)
font = QFont(FONT, FONTSIZE, QFont.Normal)
painter.setFont(font)
painter.setPen(QColor(FONTCOLORINATIVE))
painter.drawText(pixmap.rect(), Qt.AlignCenter, iconType)
painter.end()
icon = QIcon(pixmap)
return icon
def getTrayMenu(object):
exit_action = QAction("Exit", object)
exit_action.triggered.connect(exit_app)
tray_menu = QMenu()
tray_menu.addAction(exit_action)
return tray_menu
def exit_app():
qApp.quit()
class KeySignal(QObject):
capsLock = pyqtSignal(int, name='caps_lock')
numLock = pyqtSignal(int, name='num_lock')
scrollLock = pyqtSignal(int, name='scroll_lock')
class CapsLockTray(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.iconOn = getIcon(CAPS_LOCK, "on")
self.iconOff = getIcon(CAPS_LOCK, "off")
self.tray_menu = getTrayMenu(self)
self.setContextMenu(self.tray_menu)
keySignal.capsLock.connect(self.showNotification)
def showNotification(self, onOff):
if onOff == 1 or onOff == 3:
self.setIcon(self.iconOn)
self.setToolTip("Caps Lock ON")
self.show()
if onOff == 1:
self.showMessage(" ",
"<p style='text-align: center'>Caps Lock <b>ON</b></p>",
QSystemTrayIcon.Information,
TIMEOUT)
if onOff == 0 or onOff == 2:
self.setIcon(self.iconOff)
self.setToolTip("Caps Lock OFF")
self.show()
if onOff == 0:
self.showMessage(" ",
"<p style='text-align: center'>Caps Lock <b>OFF</b></p>",
QSystemTrayIcon.Information,
TIMEOUT)
class NumLockTray(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.iconOn = getIcon(NUM_LOCK, "on")
self.iconOff = getIcon(NUM_LOCK, "off")
tray_menu = getTrayMenu(self)
self.setContextMenu(tray_menu)
keySignal.numLock.connect(self.showNotification)
def showNotification(self, onOff):
if onOff == 1 or onOff == 3:
self.setIcon(self.iconOn)
self.setToolTip("Num Lock ON")
self.show()
if onOff == 1:
self.showMessage(" ",
"<p style='text-align: center'>Num Lock <b>ON</b></p>",
QSystemTrayIcon.Information,
TIMEOUT)
if onOff == 0 or onOff == 2:
self.setIcon(self.iconOff)
self.setToolTip("Num Lock OFF")
self.show()
if onOff == 0:
self.showMessage(" ",
"<p style='text-align: center'>Num Lock <b>OFF</b></p>",
QSystemTrayIcon.Information,
TIMEOUT)
class ScrollLockTray(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.iconOn = getIcon(SCROLL_LOCK, "on")
self.iconOff = getIcon(SCROLL_LOCK, "off")
tray_menu = getTrayMenu(self)
self.setContextMenu(tray_menu)
keySignal.scrollLock.connect(self.showNotification)
def showNotification(self, onOff):
if onOff == 1 or onOff == 3:
self.setIcon(self.iconOn)
self.setToolTip("Scroll Lock ON")
self.show()
if onOff == 1:
self.showMessage(" ",
"<p style='text-align: center'>Scroll Lock <b>ON</b></p>",
QSystemTrayIcon.Information,
TIMEOUT)
if onOff == 0 or onOff == 2:
self.setIcon(self.iconOff)
self.setToolTip("Scroll Lock OFF")
self.show()
if onOff == 0:
self.showMessage(" ",
"<p style='text-align: center'>Scroll Lock <b>OFF</b></p>",
QSystemTrayIcon.Information,
TIMEOUT)
class MonitorThread (QThread):
def __init__(self):
QThread.__init__(self)
def on_press(self, key):
return True
def on_release(self, key):
# print('{0} released'.format(key))
if key == keyboard.Key.caps_lock:
capsStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 5")
if capsStatus == 'off':
keySignal.capsLock.emit(0)
if capsStatus == 'on':
keySignal.capsLock.emit(1)
if key == keyboard.Key.num_lock:
numStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 9")
if numStatus == 'off':
keySignal.numLock.emit(0)
if numStatus == 'on':
keySignal.numLock.emit(1)
if key == keyboard.Key.scroll_lock:
scrollStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 13")
if scrollStatus == 'off':
keySignal.scrollLock.emit(0)
if scrollStatus == 'on':
keySignal.scrollLock.emit(1)
return True
def run(self):
with keyboard.Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()
if __name__ == "__main__":
keySignal = KeySignal()
app = QApplication(sys.argv)
qApp.setApplicationDisplayName(__appname__)
capsLockTray = CapsLockTray()
numLockTray = NumLockTray()
scrollLockTray = ScrollLockTray()
capsStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 5")
if capsStatus == 'off':
capsLockTray.showNotification(2)
if capsStatus == 'on':
capsLockTray.showNotification(3)
numStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 9")
if numStatus == 'off':
numLockTray.showNotification(2)
if numStatus == 'on':
numLockTray.showNotification(3)
scrollStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 13")
if scrollStatus == 'off':
scrollLockTray.showNotification(2)
if scrollStatus == 'on':
scrollLockTray.showNotification(3)
monThread = MonitorThread()
monThread.start()
sys.exit(app.exec())
#!/usr/bin/env python3
#
# References:
# https://pynput.readthedocs.io/en/latest/keyboard.html
# https://www.devdungeon.com/content/python3-qt5-pyqt5-tutorial
#
# Author: Alexandre C Vieira <acamargo.vieira@gmail.com>
#
# http://alexandrecvieira.droppages.com
#
# I did this little program because I didn't find any indicators that worked the way I wanted, this is the third version with notify2 api
#
# Installation:
# sudo pip3 install pynput
# sudo mkdir /opt/ss-key-indicator
# sudo cp super-simple-keyboard-indicator3 /opt/ss-key-indicator/ss-key-indicator
# Set it to boot with the system: python3 /opt/ss-key-indicator/ss-key-indicator
#
# This version uses the notify2 api
#
# Signals: 0 = Off
# 1 = On
# 2 = On(startup does not show notification)
# 3 = Off(startup does not show notification)
#
__appname__ = "Super Simple Key Indicator"
__version__ = "0.30"
__author__ = "Alexandre C Vieira"
__license__ = "GNU GPL 2.0 or later"
import sys, os, subprocess, notify2
from PyQt5.QtCore import Qt, QSize, QThread, pyqtSignal, QObject
from pynput import keyboard
from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QAction, QMenu, qApp
from PyQt5.QtGui import QPixmap, QPainter, QColor, QIcon, QFont
ICONSIZE = 22
FONT = "Sans"
FONTSIZE = 12
FONTCOLOR = "white"
FONTCOLORINATIVE = "gray"
CAPS_LOCK = "C"
NUM_LOCK = "N"
SCROLL_LOCK = "S"
def getIcon(iconType, onOff):
pixmap = QPixmap(QSize(ICONSIZE, ICONSIZE))
pixmap.fill(QColor("transparent"))
if onOff == "on":
painter = QPainter()
painter.begin(pixmap)
font = QFont(FONT, FONTSIZE, QFont.Black)
painter.setFont(font)
painter.setPen(QColor(FONTCOLOR))
painter.drawText(pixmap.rect(), Qt.AlignCenter, iconType)
painter.end()
if onOff == "off":
painter = QPainter()
painter.begin(pixmap)
font = QFont(FONT, FONTSIZE, QFont.Normal)
painter.setFont(font)
painter.setPen(QColor(FONTCOLORINATIVE))
painter.drawText(pixmap.rect(), Qt.AlignCenter, iconType)
painter.end()
icon = QIcon(pixmap)
return icon
def getTrayMenu(object):
exit_action = QAction("Exit", object)
exit_action.triggered.connect(exit_app)
tray_menu = QMenu()
tray_menu.addAction(exit_action)
return tray_menu
def showMessage(message):
notify2.init('ss-keyboard-indicator')
notification = notify2.Notification("", message, "dialog-information")
notification.show()
def exit_app():
qApp.quit()
class KeySignal(QObject):
capsLock = pyqtSignal(int, name='caps_lock')
numLock = pyqtSignal(int, name='num_lock')
scrollLock = pyqtSignal(int, name='scroll_lock')
class CapsLockTray(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.iconOn = getIcon(CAPS_LOCK, "on")
self.iconOff = getIcon(CAPS_LOCK, "off")
self.tray_menu = getTrayMenu(self)
self.setContextMenu(self.tray_menu)
keySignal.capsLock.connect(self.showNotification)
self.messageOn = "Caps Lock ON"
self.messageOff = "Caps Lock OFF"
def showNotification(self, onOff):
if onOff == 1 or onOff == 3:
self.setIcon(self.iconOn)
self.setToolTip(self.messageOn)
self.show()
if onOff == 1:
showMessage(self.messageOn)
if onOff == 0 or onOff == 2:
self.setIcon(self.iconOff)
self.setToolTip(self.messageOff)
self.show()
if onOff == 0:
showMessage(self.messageOff)
class NumLockTray(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.iconOn = getIcon(NUM_LOCK, "on")
self.iconOff = getIcon(NUM_LOCK, "off")
tray_menu = getTrayMenu(self)
self.setContextMenu(tray_menu)
keySignal.numLock.connect(self.showNotification)
self.messageOn = "Num Lock ON"
self.messageOff = "Num Lock OFF"
def showNotification(self, onOff):
if onOff == 1 or onOff == 3:
self.setIcon(self.iconOn)
self.setToolTip(self.messageOn)
self.show()
if onOff == 1:
showMessage(self.messageOn)
if onOff == 0 or onOff == 2:
self.setIcon(self.iconOff)
self.setToolTip(self.messageOff)
self.show()
if onOff == 0:
showMessage(self.messageOff)
class ScrollLockTray(QSystemTrayIcon):
def __init__(self):
QSystemTrayIcon.__init__(self)
self.iconOn = getIcon(SCROLL_LOCK, "on")
self.iconOff = getIcon(SCROLL_LOCK, "off")
tray_menu = getTrayMenu(self)
self.setContextMenu(tray_menu)
keySignal.scrollLock.connect(self.showNotification)
self.messageOn = "Scroll Lock ON"
self.messageOff = "Scroll Lock OFF"
def showNotification(self, onOff):
if onOff == 1 or onOff == 3:
self.setIcon(self.iconOn)
self.setToolTip(self.messageOn)
self.show()
if onOff == 1:
showMessage(self.messageOn)
if onOff == 0 or onOff == 2:
self.setIcon(self.iconOff)
self.setToolTip(self.messageOff)
self.show()
if onOff == 0:
showMessage(self.messageOff)
class MonitorThread (QThread):
def __init__(self):
QThread.__init__(self)
def on_press(self, key):
return True
def on_release(self, key):
# print('{0} released'.format(key))
if key == keyboard.Key.caps_lock:
capsStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 5")
if capsStatus == 'off':
keySignal.capsLock.emit(0)
if capsStatus == 'on':
keySignal.capsLock.emit(1)
if key == keyboard.Key.num_lock:
numStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 9")
if numStatus == 'off':
keySignal.numLock.emit(0)
if numStatus == 'on':
keySignal.numLock.emit(1)
if key == keyboard.Key.scroll_lock:
scrollStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 13")
if scrollStatus == 'off':
keySignal.scrollLock.emit(0)
if scrollStatus == 'on':
keySignal.scrollLock.emit(1)
return True
def run(self):
with keyboard.Listener(on_press=self.on_press, on_release=self.on_release) as listener:
listener.join()
if __name__ == "__main__":
keySignal = KeySignal()
app = QApplication(sys.argv)
qApp.setApplicationDisplayName(__appname__)
capsLockTray = CapsLockTray()
numLockTray = NumLockTray()
scrollLockTray = ScrollLockTray()
capsStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 5")
if capsStatus == 'off':
capsLockTray.showNotification(2)
if capsStatus == 'on':
capsLockTray.showNotification(3)
numStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 9")
if numStatus == 'off':
numLockTray.showNotification(2)
if numStatus == 'on':
numLockTray.showNotification(3)
scrollStatus = subprocess.getoutput("xset q | grep Caps | tr -s ' ' | cut -d ' ' -f 13")
if scrollStatus == 'off':
scrollLockTray.showNotification(2)
if scrollStatus == 'on':
scrollLockTray.showNotification(3)
monThread = MonitorThread()
monThread.start()
sys.exit(app.exec())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment