149 lines
11 KiB
Python
149 lines
11 KiB
Python
|
#!/usr/bin/python3
|
||
|
|
||
|
import argparse
|
||
|
import atexit
|
||
|
import dbus
|
||
|
import dbus.mainloop.glib
|
||
|
import gi.repository.GLib
|
||
|
import pprint
|
||
|
import sys
|
||
|
import usb.core
|
||
|
#import traceback
|
||
|
|
||
|
# Redragon K621 Horus
|
||
|
vendor=0x258a
|
||
|
product=0x0049
|
||
|
|
||
|
screensaver_list = [
|
||
|
'org.gnome.ScreenSaver',
|
||
|
'org.cinnamon.ScreenSaver',
|
||
|
'org.kde.screensaver',
|
||
|
'org.freedesktop.ScreenSaver'
|
||
|
]
|
||
|
|
||
|
def main():
|
||
|
parser = argparse.ArgumentParser(
|
||
|
description='Adjust backlight for Redgradon Horus K621',
|
||
|
add_help=True,
|
||
|
)
|
||
|
parser.add_argument('--on', '-1', dest='switch', action='store_true',
|
||
|
default=None, help='Turn keyboard backlight on')
|
||
|
parser.add_argument('--off', '-0', dest='switch', action='store_false',
|
||
|
default=None, help='Turn keyboard backlight off')
|
||
|
parser.add_argument('--screensaver', '-s', dest='screensaver', action='store_true',
|
||
|
default=None, help='Turn keyboard backlight off')
|
||
|
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
if args.switch is None and args.screensaver is None:
|
||
|
parser.print_help()
|
||
|
sys.exit(1)
|
||
|
|
||
|
if args.screensaver:
|
||
|
dbus_loop = dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||
|
session = dbus.SessionBus(mainloop=dbus_loop)
|
||
|
for screensaver in screensaver_list:
|
||
|
session.add_match_string_non_blocking("interface='{}'".format(screensaver))
|
||
|
#session.add_match_string_non_blocking("interface='org.gnome.Mutter.IdleMonitor'")
|
||
|
session.add_message_filter(message_callback)
|
||
|
loop = gi.repository.GLib.MainLoop()
|
||
|
loop.run()
|
||
|
else:
|
||
|
kbd = setup_usb()
|
||
|
send_packets(kbd, args.switch)
|
||
|
|
||
|
|
||
|
def message_callback(session, message):
|
||
|
for screensaver in screensaver_list:
|
||
|
if message.get_interface() == screensaver:
|
||
|
pprint.pprint(message)
|
||
|
# not supported in org.freedesktop.ScreenSaver:
|
||
|
# Error org.freedesktop.DBus.Error.NotSupported: This method is not part of the idle inhibition specification: https://specifications.freedesktop.org/idle-inhibit-spec/latest/
|
||
|
if message.get_member() == "ActiveChanged":
|
||
|
screensaver_changed = bool(message.get_args_list()[0])
|
||
|
#print("Screen saver {} changed. ActiveChanged: {}".format(screensaver, screensaver_changed))
|
||
|
# Capture the GetActive method call in a try/except, or the screensavers that
|
||
|
# don't support GetActive will block those that do
|
||
|
try:
|
||
|
screensaver_path = '/{0}'.format(screensaver.replace('.', '/'))
|
||
|
screensaver_obj = session.get_object(screensaver, screensaver_path)
|
||
|
screensaver_iface = dbus.Interface(screensaver_obj, screensaver)
|
||
|
status = bool(screensaver_iface.GetActive())
|
||
|
#print("Screen saver {} changed. GetActive: {}".format(screensaver, status))
|
||
|
kbd = setup_usb()
|
||
|
send_packets(kbd, not status)
|
||
|
except:
|
||
|
continue
|
||
|
|
||
|
|
||
|
|
||
|
# Set up USB
|
||
|
def setup_usb():
|
||
|
kbd = usb.core.find(idVendor=vendor, idProduct=product)
|
||
|
|
||
|
if kbd is None:
|
||
|
raise ValueError('Keyboard not found; perhaps switch to USB mode?')
|
||
|
|
||
|
print("Product: ", kbd.product)
|
||
|
print("Manufacturer: ", kbd.manufacturer)
|
||
|
|
||
|
return kbd
|
||
|
|
||
|
|
||
|
# Send packet/s
|
||
|
def send_packets(kbd, switch):
|
||
|
if kbd is None:
|
||
|
setup_usb()
|
||
|
|
||
|
if switch is True:
|
||
|
#pattern = 0x01 # solid white
|
||
|
#pattern = 0x02 #
|
||
|
#pattern = 0x03 #
|
||
|
#pattern = 0x04 #
|
||
|
#pattern = 0x05 #
|
||
|
#pattern = 0x06 #
|
||
|
#pattern = 0x07 #
|
||
|
#pattern = 0x08 #
|
||
|
pattern = 0x09 # shadow_disappear
|
||
|
#pattern = 0x10 #
|
||
|
#pattern = 0x11 #
|
||
|
#pattern = 0x12 #
|
||
|
#pattern = 0x13 #
|
||
|
#pattern = 0x14 #
|
||
|
#pattern = 0x20 # custom pattern
|
||
|
else:
|
||
|
pattern = 0x00 # off
|
||
|
|
||
|
print("Sending pattern {} command".format(switch))
|
||
|
|
||
|
# This message tweaks the pattern between OFF (0x0) and the white shadow_disappear pattern (0x9)
|
||
|
# with brightness 1/4 and speed 3/4 (I think)
|
||
|
#
|
||
|
# To modify the "on" pattern, capture the packets from the K621-RGB app with wireshark and usbpcap,
|
||
|
# and find the last SET_REPORT request of a set of 4 with size 1068 bytes (1031 data bytes);
|
||
|
# the first 20 bytes are identical in all four packets.
|
||
|
#
|
||
|
# You may need the preceeding three packets as well, and possibly the preceeding SET_REPORT request
|
||
|
#(of size 42; I think this is a request for current settings) and GET_REPORT response (of size 290 bytes).
|
||
|
#
|
||
|
msg = [ 0x06, 0x03, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xa5, 0x03, 0x03, 0x00, 0x00, 0x00, pattern, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x31, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x00, 0x31, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x07, 0x39, 0x5a, 0xa5, 0x00, 0x10, 0x07, 0x49, 0x07, 0x49, 0x07, 0x49, 0x07, 0x49, 0x07, 0x49, 0x07, 0x49, 0x07, 0x49, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0xa5, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||
|
|
||
|
try:
|
||
|
ret = kbd.ctrl_transfer(0x21, 0x09, 0x0306, 1, msg)
|
||
|
assert ret == len(msg)
|
||
|
# Prevent [Errno 32] Pipe error
|
||
|
#time.sleep(0.25)
|
||
|
except usb.core.USBError as e:
|
||
|
print(e)
|
||
|
if e.errno == 16:
|
||
|
print("This issue needs more investigation... it may simply be previous invalid commands")
|
||
|
# May need to reconfigure the device, or detach/reattach kernel driver, either for interface 0 or 0 _and_ 1
|
||
|
elif e.errno == 2:
|
||
|
print("Try unplugging and replugging the keyboard...")
|
||
|
sys.exit()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
#atexit.register(cleanup)
|
||
|
main()
|