#!/usr/bin/python3 import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import dbus import dbus.service import subprocess import time from dbus.mainloop.glib import DBusGMainLoop import notify2 class KeyhandlerDBUSService(dbus.service.Object): def __init__(self): bus_name = dbus.service.BusName('org.elektranox.keyhandler', bus=dbus.SessionBus()) dbus.service.Object.__init__(self, bus_name, '/org/elektranox/keyhandler') self.bnotice = notify2.Notification("Backlight", "", "display-brightness-symbolic") self.vnotice = notify2.Notification("Volume", "", "") self.wnotice = notify2.Notification("WLAN", "", "") self.mnotice = notify2.Notification("Mouse", "", "") def _lid_status_open(self): lidstatus = "state: unknown" with open('/proc/acpi/button/lid/LID/state', 'r') as lidstatefile: lidstatus = lidstatefile.read() lidstatus = lidstatus.strip().replace("state: ", "") return lidstatus == "open" def _dock_status_docked(self): popen = subprocess.Popen(['/usr/bin/lsusb', '-d', '17ef:1010']) popen.wait() return not popen.returncode def _bluetooth_set_status(self, state): bus = dbus.SystemBus() dev = bus.get_object("org.bluez", u'/org/bluez/hci0') iface = dbus.Interface(dev, 'org.freedesktop.DBus.Properties') iface.Set("org.bluez.Adapter1", "Powered", state) def _bluetooth_get_status(self, state): bus = dbus.SystemBus() dev = bus.get_object("org.bluez", u'/org/bluez/hci0') iface = dbus.Interface(dev, 'org.freedesktop.DBus.Properties') return iface.Get("org.bluez.Adapter1", "Powered") def _getBacklight(self): with open("/sys/class/backlight/intel_backlight/brightness", "r") as f: return int(f.readline().strip()) def _getMaxBacklight(self): with open("/sys/class/backlight/intel_backlight/max_brightness", "r") as f: return int(f.readline().strip()) def _setBacklight(self, value): with open("/sys/class/backlight/intel_backlight/brightness", "w") as f: f.write(str(value)) def _showBacklightState(self): state = self._getBacklight() * 100 / self._getMaxBacklight() self.bnotice.set_hint_int32("value", int(state)) self.bnotice.set_hint_string("synchronous", "brightness") self.bnotice.show() def _showVolumeState(self): popen = subprocess.Popen(['/usr/bin/amixer', '-c', 'PCH', 'get', 'Master'], stdout = subprocess.PIPE) popen.wait() (stdout,stderr) = popen.communicate(None) lines = stdout.decode("utf-8").split("\n") state = int(lines[-2].split()[3][1:-2]) muted = lines[-2].split()[5][1:-1] == "off" if muted: self.vnotice.icon = "audio-volume-muted" elif state < 20: self.vnotice.icon = "audio-volume-low" elif state < 60: self.vnotice.icon = "audio-volume-medium" else: self.vnotice.icon = "audio-volume-high" self.vnotice.set_hint_int32("value", state) self.vnotice.set_hint_string("synchronous", "volume") self.vnotice.show() def _rfkill_get(self, rfid): popen = subprocess.Popen(['/usr/sbin/rfkill', 'list', rfid], stdout = subprocess.PIPE) popen.wait() (stdout,stderr) = popen.communicate() return stdout.decode("utf-8").split("\n")[1].split(" ")[2] == "no" def _showMicState(self): popen = subprocess.Popen(['/usr/bin/amixer', '-c', 'PCH', 'get', 'Capture'], stdout = subprocess.PIPE) popen.wait() (stdout,stderr) = popen.communicate(None) lines = stdout.decode("utf-8").split("\n") state = int(lines[-2].split()[4][1:-2]) muted = lines[-2].split()[6][1:-1] == "off" if muted: self.vnotice.icon = "microphone-sensitivity-muted" elif state < 20: self.vnotice.icon = "microphone-sensitivity-low" elif state < 60: self.vnotice.icon = "microphone-sensitivity-medium" else: self.vnotice.icon = "microphone-sensitivity-high" self.vnotice.set_hint_int32("value", state) self.vnotice.set_hint_string("synchronous", "volume") self.vnotice.show() @dbus.service.method('org.elektranox.keyhandler') def volumeMute(self): #popen = subprocess.Popen(['/usr/bin/amixer', '-c', 'PCH', 'set', 'Master', 'toggle']) popen = subprocess.Popen(['/usr/bin/pactl', 'set-sink-mute', 'alsa_output.pci-0000_00_1b.0.analog-stereo', 'toggle']) popen.wait() self._showVolumeState() @dbus.service.method('org.elektranox.keyhandler') def volumeDec(self): popen = subprocess.Popen(['/usr/bin/amixer', '-c', 'PCH', 'set', 'Master', '2%-']) popen.wait() self._showVolumeState() @dbus.service.method('org.elektranox.keyhandler') def volumeInc(self): popen = subprocess.Popen(['/usr/bin/amixer', '-c', 'PCH', 'set', 'Master', '2%+']) popen.wait() self._showVolumeState() @dbus.service.method('org.elektranox.keyhandler') def micMute(self): #popen = subprocess.Popen(['/usr/bin/amixer', '-c', 'PCH', 'set', 'Master', 'toggle']) popen = subprocess.Popen(['/usr/bin/amixer', 'set', 'Capture', 'toggle']) popen.wait() self._showMicState() def _backlightChg(self, decrease): brightness = self._getBacklight() maximum = self._getMaxBacklight() current = self._getBacklight() / maximum * 100 step = 1 # probably should implement something using a logarithmic scale if current <= 2: step = int(0.5 * maximum/100) elif current <= 10: step = int(1 * maximum/100) elif current <= 50: step = int(5 * maximum/100) else: step = int(10 * maximum/100) if decrease: brightness -= step else: brightness += step if brightness < 0: brightness = 0 if brightness > maximum: brightness = maximum self._setBacklight(brightness) self._showBacklightState() @dbus.service.method('org.elektranox.keyhandler') def backlightDec(self): self._backlightChg(True) @dbus.service.method('org.elektranox.keyhandler') def backlightInc(self): self._backlightChg(False) @dbus.service.method('org.elektranox.keyhandler') def XF86Display(self): lidopen = self._lid_status_open() docked = self._dock_status_docked() if not docked: popen = subprocess.Popen(['/usr/bin/xrandr','--output', 'eDP1', '--auto']) popen.wait() popen = subprocess.Popen(['/usr/bin/xrandr','--output', 'DP2-1', '--off']) popen.wait() popen = subprocess.Popen(['/usr/bin/notify-send','Not docked']) popen.wait() elif lidopen: popen = subprocess.Popen(['/usr/bin/xrandr','--output', 'eDP1', '--auto']) popen.wait() popen = subprocess.Popen(['/usr/bin/xrandr','--output', 'DP2-1', '--right-of', 'eDP1', '--auto']) popen.wait() popen = subprocess.Popen(['/usr/bin/notify-send','Docked with open lid']) popen.wait() else: popen = subprocess.Popen(['/usr/bin/xrandr','--output', 'DP2-1', '--right-of', 'eDP1', '--auto']) popen.wait() popen = subprocess.Popen(['/usr/bin/xrandr','--output', 'eDP1', '--off']) popen.wait() popen = subprocess.Popen(['/usr/bin/notify-send','Docked with closed lid']) popen.wait() @dbus.service.method('org.elektranox.keyhandler') def WLAN(self): # button itself is handled by systemd state = self._rfkill_get("wlan") if state: self.wnotice.icon = "network-wireless-symbolic" self.wnotice.summary = "enabled" else: self.wnotice.icon = "network-wireless-offline-symbolic" self.wnotice.summary = "disabled" self.wnotice.show() @dbus.service.method('org.elektranox.keyhandler') def XF86Tools(self): popen = subprocess.Popen(['/usr/local/bin/toggle-mouse-wheel-emulation'], stdout = subprocess.PIPE) popen.wait() (stdout,stderr) = popen.communicate(None) enabled = (stdout.decode("utf-8").find("enabled") != -1) self.mnotice.icon = "/usr/share/icons/mate/48x48/devices/input-mouse.png" if enabled: self.mnotice.summary = "Mouse Wheel Emulation enabled" else: self.mnotice.summary = "Mouse Wheel Emulation disabled" self.mnotice.show() @dbus.service.method('org.elektranox.keyhandler') def XF86Search(self): popen = subprocess.Popen(['/usr/bin/notify-send','XF86Search']) popen.wait() # TODO: add some fancy binding pass @dbus.service.method('org.elektranox.keyhandler') def XF86LaunchA(self): popen = subprocess.Popen(['/usr/bin/notify-send','XF86LaunchA']) popen.wait() # TODO: add some fancy binding pass @dbus.service.method('org.elektranox.keyhandler') def XF86Explorer(self): state = self._rfkill_get("bluetooth") if state: subprocess.call(['/usr/sbin/rfkill','block', 'bluetooth']) self.wnotice.icon = "/usr/share/icons/gnome/scalable/status/bluetooth-disabled-symbolic.svg" self.wnotice.summary = "Bluetooth blocked" else: subprocess.call(['/usr/sbin/rfkill','unblock', 'bluetooth']) self.wnotice.icon = "/usr/share/icons/gnome/scalable/status/bluetooth-active-symbolic.svg" self.wnotice.summary = "Bluetooth unblocked" self.wnotice.show() if not state: time.sleep(1) self._bluetooth_set_status(True) DBusGMainLoop(set_as_default=True) service = KeyhandlerDBUSService() notify2.init("TP Keyhandler") Gtk.main()