Skip to content

Commit

Permalink
feat: add support for Loupdeck CT surface
Browse files Browse the repository at this point in the history
  • Loading branch information
dnmeid committed Jul 1, 2023
1 parent 6150e23 commit 9a7cea8
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 31 deletions.
4 changes: 2 additions & 2 deletions docs/3_config/settings/surfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ More details on supported surfaces are available in the chapter on [Surfaces](#7
- **Enable connected X-keys (Requires Companion restart)**
Whether to enable support for connecting to XKeys devices.

- **Enable connected Loupedeck Live and Razer Stream Controller devices (Requires Companion restart)**
Whether to enable support for connecting Loupedeck Live and Razer Stream Controller devices.
- **Enable connected Loupedeck and Razer Stream Controller devices (Requires Companion restart)**
Whether to enable support for connecting Loupedeck and Razer Stream Controller devices.
4 changes: 2 additions & 2 deletions docs/7_surfaces/loupedeck-live.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
It is possible to use the [Loupedeck Live](https://loupedeck.com/uk/products/loupedeck-live/), [Razer Stream Controller](https://www.razer.com/gb-en/streaming-accessories/razer-stream-controller) and [Loupdeck Live S](https://loupedeck.com/uk/products/loupedeck-live-s/) with Companion since v2.4.0.
It is possible to use the [Loupedeck Live, Loupedeck Live S, Loupedeck CT](https://loupedeck.com/products/) and [Razer Stream Controller](https://www.razer.com/gb-en/streaming-accessories/razer-stream-controller) with Companion.

It requires your Loupedeck Live to be running v0.2.0 or later firmware, and the Loupedeck software must not be running.
It requires your Loupedeck to be running v0.2.0 or later firmware, and the Loupedeck software must not be running.
Enable support for it in the Companion settings, and rescan for usb devices.

The layout pretty closely matches what you should expect based on the device, but the tall touch strips are not mapped across yet.
Expand Down
16 changes: 9 additions & 7 deletions lib/Surface/Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import ElgatoStreamDeckDriver from './USB/ElgatoStreamDeck.js'
// import InfinittonDriver from './USB/Infinitton.js'
import XKeysDriver from './USB/XKeys.js'
import LoupedeckLiveDriver from './USB/LoupedeckLive.js'
import SurfaceUSBLoupedeckCt from './USB/LoupedeckCt.js'

import CoreBase from '../Core/Base.js'

Expand Down Expand Up @@ -500,12 +501,12 @@ class SurfaceController extends CoreBase {
}

// Now do the scan
try {
const ignoreStreamDeck = streamDeckSoftwareRunning || streamdeckDisabled
const scanForLoupedeck = !!this.userconfig.getKey('loupedeck_enable')

this.logger.silly('USB: checking devices')
const scanForLoupedeck = !!this.userconfig.getKey('loupedeck_enable')
this.logger.log('scanForLoupedeck', scanForLoupedeck)
const ignoreStreamDeck = streamDeckSoftwareRunning || streamdeckDisabled
this.logger.silly('USB: checking devices')

try {
await Promise.allSettled([
HID.devicesAsync().then(async (deviceInfos) =>
Promise.allSettled(
Expand Down Expand Up @@ -537,22 +538,23 @@ class SurfaceController extends CoreBase {
? listLoupedecks().then((deviceInfos) =>
Promise.allSettled(
deviceInfos.map(async (deviceInfo) => {
console.log('found loupedeck', deviceInfo)
this.logger.log('found loupedeck', deviceInfo)
if (this.#surfaceHandlers[deviceInfo.path] === undefined) {
if (
deviceInfo.model === LoupedeckModelId.LoupedeckLive ||
deviceInfo.model === LoupedeckModelId.LoupedeckLiveS ||
deviceInfo.model === LoupedeckModelId.RazerStreamControllerX
) {
await this.#addDevice(deviceInfo, 'loupedeck-live', LoupedeckLiveDriver, true)
} else if (deviceInfo.model === LoupedeckModelId.LoupedeckCt) {
await this.#addDevice(deviceInfo, 'loupedeck-ct', SurfaceUSBLoupedeckCt, true)
}
}
})
)
)
: null,
])
console.log('scanForLoupedeck', scanForLoupedeck)

this.logger.silly('USB: done')

Expand Down
35 changes: 31 additions & 4 deletions lib/Surface/Handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ class SurfaceHandler extends CoreBase {

this.panel = panel
this.isSurfaceLocked = isLocked
this.pincodeNumberPositions = PINCODE_NUMBER_POSITIONS
this.pincodeCodePosition = PINCODE_CODE_POSITION

// some surfaces need different positions for the pincode numbers
if (this.panel.info.type === 'Loupedeck Live' ||
this.panel.info.type === 'Loupedeck Live S' ||
this.panel.info.type === 'Razer Stream Controller' ||
this.panel.info.type === 'Razer Stream Controller X'
) {
this.pincodeNumberPositions = [13, 18, 19, 20, 10, 11, 12, 2, 3, 4]
this.pincodeCodePosition = 21
}
if(this.panel.info.type === 'Loupedeck CT') {
this.pincodeNumberPositions = [13, 18, 19, 20, 10, 11, 12, 2, 3, 4]
this.pincodeCodePosition = 35
}

this.currentPage = 1 // The current page of the device

Expand Down Expand Up @@ -191,15 +207,23 @@ class SurfaceHandler extends CoreBase {
if (this.isSurfaceLocked) {
const buffers = this.graphics.getImagesForPincode(this.currentPincodeEntry)
this.panel.clearDeck()
this.#drawButton(PINCODE_CODE_POSITION, buffers.code.buffer)
this.#drawButton(this.pincodeCodePosition, buffers.code.buffer)

PINCODE_NUMBER_POSITIONS.forEach((key, i) => {
this.pincodeNumberPositions.forEach((key, i) => {
if (buffers[i]) {
this.#drawButton(key, buffers[i].buffer)
}
})
} else if (this.#xkeysPageCount > 0) {
this.#xkeysDrawPages()
} else if (this.panel.info.type === 'Loupedeck CT') {
for (let i = 0; i < 56; ++i) {
// Note: the maths looks inverted, but it goes through the toDeviceKey still
const key = i
const pageOffset = Math.floor(i/32)
const image = this.graphics.getBank(this.currentPage + pageOffset, (i % 32) + 1)
this.#drawButton(key, image.buffer, image.style)
}
} else {
const xOffset = Math.min(Math.max(this.panelconfig.config.xOffset || 0, 0), this.panelInfo.xOffsetMax)
const yOffset = Math.min(Math.max(this.panelconfig.config.yOffset || 0, 0), this.panelInfo.yOffsetMax)
Expand Down Expand Up @@ -252,6 +276,9 @@ class SurfaceHandler extends CoreBase {
if (pageOffset >= 0 && pageOffset < this.#xkeysPageCount) {
this.panel.drawColor(pageOffset, bank, render.style?.bgcolor || 0)
}
} else if (this.panel.info.type === 'Loupedeck CT' && (page - this.currentPage == 1 || (page == 1 && this.currentPage == 99)) && bank <= 24) {
// Loupdeck CT lower half, draw buttun with number offset by 32
this.#drawButton(bank + 31, render.buffer, render.style)
} else if (page == this.currentPage) {
// normal mode
const xOffset = Math.min(Math.max(this.panelconfig.config.xOffset || 0, 0), this.panelInfo.xOffsetMax)
Expand Down Expand Up @@ -318,7 +345,7 @@ class SurfaceHandler extends CoreBase {
this.logger.debug('Button ' + thisPage + '.' + (key + 1) + ' ' + (pressed ? 'pressed' : 'released'))
} else {
if (pressed) {
const pressCode = PINCODE_NUMBER_POSITIONS.indexOf(key)
const pressCode = this.pincodeNumberPositions.indexOf(key)
if (pressCode !== -1) {
this.currentPincodeEntry += pressCode.toString()
}
Expand All @@ -338,7 +365,7 @@ class SurfaceHandler extends CoreBase {
if (this.isSurfaceLocked) {
// Update lockout button
const datap = this.graphics.getImagesForPincode(this.currentPincodeEntry)
this.#drawButton(PINCODE_CODE_POSITION, datap.code.buffer)
this.#drawButton(this.pincodeCodePosition, datap.code.buffer)
}
}
}
Expand Down
Loading

0 comments on commit 9a7cea8

Please sign in to comment.