Skip to content

Implement hack fix for Launchpad Pro #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions INSTALL/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
MouseInfo==0.1.3
Pillow==8.1.1
Pillow==8.2.0
py-getch==1.0.1
PyAutoGUI==0.9.50
pygame==1.9.6
pygame==2.0.1
PyGetWindow==0.0.8
PyMsgBox==1.0.7
pynput==1.6.8
Expand Down
26 changes: 15 additions & 11 deletions LPHK.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,44 @@
import sys, os, subprocess
import os
import sys
from datetime import datetime

print("\n!!!!!!!! DO NOT CLOSE THIS WINDOW WITHOUT SAVING !!!!!!!!\n")

LOG_TITLE = "LPHK.log"

# Get platform information
PLATFORMS = [ {"search_string": "win", "name_string": "windows"},
{"search_string": "linux", "name_string": "linux"},
{"search_string": "darwin", "name_string": "macintosh"} ]
PLATFORMS = [{"search_string": "win", "name_string": "windows"},
{"search_string": "linux", "name_string": "linux"},
{"search_string": "darwin", "name_string": "macintosh"}]
PLATFORM = None
for plat in PLATFORMS:
if sys.platform.startswith(plat["search_string"]):
PLATFORM = plat["name_string"]
break
if PLATFORM == None:
if PLATFORM is None:
PLATFORM = "other"

# Test if this is a PyInstaller executable or a .py file
if getattr(sys, 'frozen', False):
IS_EXE = True
PROG_FILE = sys.executable
PROG_PATH = os.path.dirname(PROG_FILE)
PROG_PATH = os.path.dirname(PROG_FILE)
PATH = sys._MEIPASS
else:
IS_EXE = False
PROG_FILE = os.path.realpath(__file__)
PROG_PATH = os.path.dirname(PROG_FILE)
PATH = PROG_PATH


# Test if there is a user folder specified
def get_first_textfile_line(file_path):
file_lines = None
with open(file_path, "r") as f:
file_lines = f.readlines()
first_line = file_lines[0]
return first_line.strip()


USERPATH_FILE = os.path.join(PATH, "USERPATH")
if os.path.exists(USERPATH_FILE):
IS_PORTABLE = False
Expand All @@ -53,6 +55,7 @@ def get_first_textfile_line(file_path):
LOG_PATH = os.path.join(USER_PATH, LOG_TITLE)

import logger

logger.start(LOG_PATH)


Expand Down Expand Up @@ -84,7 +87,7 @@ def datetime_str():
sys.exit("[LPHK] Error loading launchpad.py")
print("")

import lp_events, scripts, kb, files, sound, window
import lp_events, scripts, files, sound, window
from utils import launchpad_connector

lp = launchpad.Launchpad()
Expand All @@ -102,17 +105,18 @@ def init():

else:
print("[LPHK] Invalid argument: " + sys.argv[1] + ". Ignoring...")

files.init(USER_PATH)
sound.init(USER_PATH)


def shutdown():
if lp_events.timer != None:
if lp_events.timer is not None:
lp_events.timer.cancel()
scripts.to_run = []
for x in range(9):
for y in range(9):
if scripts.threads[x][y] != None:
if scripts.threads[x][y] is not None:
scripts.threads[x][y].kill.set()
if window.lp_connected:
scripts.unbind_all()
Expand Down
31 changes: 21 additions & 10 deletions lp_colors.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
curr_colors = [[[0,0,0] for y in range(9)] for x in range(9)]
curr_colors = [[[0, 0, 0] for y in range(9)] for x in range(9)]
color_modes = [["solid" for y in range(9)] for x in range(9)]

import lp_events, scripts, window
import colorsys

lp_object = None


def init(lp_object_in):
global lp_object
lp_object = lp_object_in


def code_to_RGB(code):
# Used to convert old layouts to the new format only
RGB = {0: "#000",
Expand Down Expand Up @@ -49,10 +51,11 @@ def code_to_RGB(code):
rgb.append(int(val + val, 16))
return rgb


def RGB_to_RG(rgb):
if rgb[2] != 0:
color = list(colorsys.rgb_to_hsv(rgb[0], rgb[1], rgb[2]))
color[0] = color[0] * (106/330)
color[0] = color[0] * (106 / 330)
color = list(colorsys.hsv_to_rgb(color[0], color[1], color[2]))
color = [round(x) for x in color]
for x in range(2):
Expand All @@ -61,12 +64,15 @@ def RGB_to_RG(rgb):
else:
return rgb


def setXY(x, y, color):
curr_colors[x][y] = color


def getXY(x, y):
return curr_colors[x][y]


def list_RGB_to_string(color):
color_texts = [hex(c)[2:] for c in color]
color_string = "#"
Expand All @@ -76,25 +82,28 @@ def list_RGB_to_string(color):
color_string += c
return color_string


def getXY_RGB(x, y):
color = getXY(x, y)
color_string = list_RGB_to_string(color)
return color_string


def luminance(r, g, b):
return ((0.299 * r) + (0.587 * g) + (0.114 * b)) / 255.0
return ((0.299 * r) + (0.587 * g) + (0.114 * b)) / 255.0


def updateXY(x, y):
if window.lp_connected:
if (x, y) != (8, 0):
is_running = False
if scripts.threads[x][y] != None:
if scripts.threads[x][y].isAlive():
if scripts.threads[x][y] is not None:
if scripts.threads[x][y].is_alive():
is_running = True

is_func_key = ((y == 0) or (x == 8))

#print("Update colors for (" + str(x) + ", " + str(y) + "), is_running = " + str(is_running))
# print("Update colors for (" + str(x) + ", " + str(y) + "), is_running = " + str(is_running))

if is_running:
set_color = scripts.COLOR_PRIMED
Expand All @@ -112,12 +121,12 @@ def updateXY(x, y):
if window.lp_mode == "Mk1":
if type(set_color) is int:
set_color = code_to_RGB(set_color)
lp_object.LedCtrlXY(x, y, set_color[0]//64, set_color[1]//64)
lp_object.LedCtrlXY(x, y, set_color[0] // 64, set_color[1] // 64)
else:
if (color_modes[x][y] == "solid") or is_func_key:
#pulse and flash only work on main grid
# pulse and flash only work on main grid
if type(set_color) is list:
lp_object.LedCtrlXYByRGB(x, y, [c//4 for c in set_color])
lp_object.LedCtrlXYByRGB(x, y, [c // 4 for c in set_color])
else:
lp_object.LedCtrlXYByCode(x, y, set_color)
elif color_modes[x][y] == "pulse":
Expand All @@ -127,12 +136,13 @@ def updateXY(x, y):
lp_object.LedCtrlFlashXYByCode(x, y, set_color)
else:
if type(set_color) is list:
lp_object.LedCtrlXYByRGB(x, y, [c//4 for c in set_color])
lp_object.LedCtrlXYByRGB(x, y, [c // 4 for c in set_color])
else:
lp_object.LedCtrlXYByCode(x, y, set_color)
else:
print("[lp_colors] (" + str(x) + ", " + str(y) + ") Launchpad is disconnected, cannot update.")


def update_all():
if window.lp_connected:
for x in range(9):
Expand All @@ -141,6 +151,7 @@ def update_all():
else:
print("[lp_colors] Launchpad is disconnected, cannot update.")


def raw_clear():
for x in range(9):
for y in range(9):
Expand Down
33 changes: 21 additions & 12 deletions lp_events.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,71 @@
import copy, threading, time
import lp_colors

RUN_DELAY = 0.005 #0.005 == 200 FPS
RUN_DELAY = 0.005 # 0.005 == 200 FPS


def unbound_press(x, y):
print("[lp_events] ("+str(x)+", "+str(y)+") Unbound button...")
print("[lp_events] (" + str(x) + ", " + str(y) + ") Unbound button...")


press_funcs = [[unbound_press for y in range(9)] for x in range(9)]
pressed = [[False for y in range(9)] for x in range(9)]

timer = None


def init(lp_object):
global timer
global press_funcs
timer = threading.Timer(RUN_DELAY, run, (lp_object,))


def run(lp_object):
global timer
while True:
event = lp_object.ButtonStateXY()
if event != []:
if event:
x = event[0]
y = event[1]
if event[2] == 0:
pressed[x][y] = False
else:
pressed[x][y] = True
press_funcs[x][y](x, y)
lp_colors.updateXY(x, y)
try:
if event[2] == 0:
pressed[x][y] = False
else:
pressed[x][y] = True
press_funcs[x][y](x, y)
lp_colors.updateXY(x, y)
except IndexError:
pass
else:
break
init(lp_object)
timer.start()


def start(lp_object):
lp_colors.init(lp_object)
init(lp_object)
run(lp_object)
lp_colors.update_all()


def bind_func_with_colors(x, y, func, off_color):
global press_funcs
press_funcs[x][y] = func
lp_colors.setXY(x, y, off_color)


def unbind(x, y):
global press_funcs
press_funcs[x][y] = unbound_press
lp_colors.setXY(x, y, [0,0,0])
lp_colors.setXY(x, y, [0, 0, 0])
lp_colors.updateXY(x, y)


def unbind_all():
global press_funcs
press_funcs = [[unbound_press for y in range(9)] for x in range(9)]
for x in range(9):
for y in range(9):
lp_colors.setXY(x, y, [0,0,0])
lp_colors.setXY(x, y, [0, 0, 0])
lp_colors.raw_clear()

2 changes: 1 addition & 1 deletion scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,7 @@ def unbind_all():
for x in range(9):
for y in range(9):
if threads[x][y] is not None:
if threads[x][y].isAlive():
if threads[x][y].is_alive():
threads[x][y].kill.set()
files.curr_layout = None
files.layout_changed_since_load = False
Expand Down
6 changes: 3 additions & 3 deletions window.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def connect_lp(self):

lp = lpcon.get_launchpad()

if lp is -1:
if lp == -1:
self.popup(self, "Connect to Unsupported Device", self.error_image,
"""The device you are attempting to use is not currently supported by LPHK,
and there are no plans to add support for it.
Expand All @@ -187,7 +187,7 @@ def connect_lp(self):
lp_object = lp
lp_mode = lpcon.get_mode(lp)

if lp_mode is "Pro":
if lp_mode == "Pro":
self.popup(self, "Connect to Launchpad Pro", self.error_image,
"""This is a BETA feature! The Pro is not fully supported yet,as the bottom and left rows are not mappable currently.
I (nimaid) do not have a Launchpad Pro to test with, so let me know if this does or does not work on the Discord! (https://discord.gg/mDCzB8X)
Expand All @@ -198,7 +198,7 @@ def connect_lp(self):
lp_object.ButtonFlush()

# special case?
if lp_mode is not "Mk1":
if lp_mode != "Mk1":
lp_object.LedCtrlBpm(INDICATOR_BPM)

lp_events.start(lp_object)
Expand Down