- /* Control Logitech G29 wheel with intervals and amplitude
- # Install
- npm init
- npm install logitech-g29
- # Run
- npm start
- */
- const g = require('logitech-g29')
- const readline = require('readline');
- const os = require('os')
- readline.emitKeypressEvents(process.stdin);
- process.stdin.setRawMode(true);
- // Initialization
- const options = {
- autocenter: false,
- range: 270
- }
- const defaults = {
- forceFriction: 0 // 0 = no friction, 0.5 = half strength, 1 = full strength
- }
- let lastFriction = defaults.forceFriction
- const min_interval = 50;
- const max_interval = 4000;
- // Variables
- let interval = 500;
- let nextInterval = false;
- let frq = 25;
- let amplitude = 0.1
- let nextAmplitude = false;
- let drift = 0.02
- // Helper function
- function mathRound(number) {
- return Math.round(number * 100) / 100;
- }
- // Friction
- function setForceFriction(val) {
- if (val === 0) {
- lastFriction = 0
- } else if (val > 0) {
- lastFriction += 0.1
- } else {
- lastFriction -= 0.1
- }
- lastFriction = mathRound(lastFriction)
- if (lastFriction < 0) lastFriction = 0
- if (lastFriction > 1) lastFriction = 1
- console.log('forceFriction(' + lastFriction + ')')
- g.forceFriction(lastFriction)
- }
- // Amplitude
- function setAmplitude(val) {
- if (amplitude == val)
- return
- if (val < 0)
- val = 0
- else if ((interval > 400) && val > 0.2)
- val = 0.2
- else if ((interval > 200) && val > 0.3)
- val = 0.3
- else if (val > 0.4)
- val = 0.4
- nextAmplitude = mathRound(val)
- }
- function increaseAmplitude() {
- setAmplitude(amplitude + 0.01)
- }
- function decreaseAmplitude() {
- setAmplitude(amplitude - 0.01)
- }
- // Drift
- function setDrift(val) {
- if (val < -0.5)
- val = -0.5
- else if (val > 0.5)
- val = 0.5
- drift = mathRound(val)
- console.log(color.cyan('drift'), drift)
- }
- function increaseDrift() {
- setDrift(drift + 0.01)
- }
- function decreaseDrift() {
- setDrift(drift - 0.01)
- }
- // Interval
- function updateInterval(val) {
- if ((val > max_interval) || (val < min_interval)) {
- console.log(color.red("WARN: Invalid interval ") + val)
- return
- }
- nextInterval = val
- // Sanity check for amplitued with the new interval
- setAmplitude(amplitude)
- }
- function increaseInterval() {
- let step = 500
- if (interval < 300)
- step = 50
- else if (interval < 1000)
- step = 100
- let val = interval + step
- if (val > max_interval)
- return
- updateInterval(val)
- }
- function decreaseInterval() {
- let step = 50
- if (interval > 1000)
- step = 500
- else if (interval > 300)
- step = 100
- let val = interval - step
- if (val < min_interval)
- return
- updateInterval(val)
- }
- // Position
- let increase = false;
- let extreme = false;
- let last = 0;
- // Wait until end position before changing amplitude and interval
- function delayChange(x) {
- if (x > last && !increase) {
- extreme = true
- increase = true
- } else if (x < last && increase) {
- extreme = true
- increase = false
- }
- if (extreme) {
- if (nextAmplitude) {
- amplitude = nextAmplitude
- nextAmplitude = false
- console.log(color.magenta('amplitude'), amplitude)
- }
- if (nextInterval) {
- interval = nextInterval
- nextInterval = false
- console.log(color.green('interval ') + interval)
- }
- extreme = false
- }
- last = x
- }
- function updatePosition() {
- let x = Math.cos(Math.PI * 2 * new Date().getTime() / interval); // Value between 0 and 1
- x *= amplitude // Multiplied by amplitude to decrease movement
- x += 0.5 // Middle is 0.5 which is no movement
- x += drift // Add extra weight towards one side
- x = mathRound(x)
- //console.log(x)
- delayChange(x)
- g.forceConstant(x)
- }
- // Bind buttons
- g.connect(options, function(err) {
- g.on('wheel-button_plus', function(val) {
- if (val == 1)
- increaseInterval()
- })
- g.on('wheel-button_minus', function(val) {
- if (val == 1)
- decreaseInterval()
- })
- g.on('wheel-spinner', function(val) {
- if (val !== 0) {
- setForceFriction(val)
- }
- })
- g.on('wheel-button_spinner', function(val) {
- if (val === 1) {
- setForceFriction(0)
- }
- })
- process.stdin.on('keypress', (str, key) => {
- if (key.ctrl && key.name === 'c') {
- g.forceConstant(0.5)
- clearInterval(loop)
- process.exit();
- } else {
- // console.log(`You pressed the "${str}" key`);
- // console.log();
- //console.log(key);
- // console.log();
- if (key.name == 'up') {
- decreaseInterval()
- } else if (key.name == 'down') {
- increaseInterval()
- } else if (key.name == 'left') {
- decreaseAmplitude()
- } else if (key.name == 'right') {
- increaseAmplitude()
- } else if (key.name == 'q') {
- increaseDrift()
- } else if (key.name == 'a') {
- decreaseDrift()
- } else if (key.name == '1') {
- updateInterval(4000)
- setAmplitude(0.13)
- } else if (key.name == '2') {
- updateInterval(2000)
- setAmplitude(0.16)
- } else if (key.name == '3') {
- updateInterval(1000)
- setAmplitude(0.18)
- } else if (key.name == '4') {
- updateInterval(500)
- setAmplitude(0.2)
- } else if (key.name == '5') {
- updateInterval(350)
- setAmplitude(0.25)
- } else if (key.name == '6') {
- updateInterval(250)
- setAmplitude(0.3)
- } else if (key.name == '7') {
- updateInterval(200)
- setAmplitude(0.4)
- } else if (key.name == 'escape') {
- setAmplitude(0.01)
- }
- }
- });
- console.log(color.cyan('Wheel ready.'))
- console.log()
- console.log(color.green('Increase speed with up, decrease with down.'))
- console.log(color.magenta('Increase amplitude/movement with right, decrease with left.'))
- console.log(color.cyan('Increase drift/weight right with q, left with a.'))
- console.log(color.yellow('Number keys are quick settings, 1-7, slow to fast'))
- console.log()
- console.log(color.grey('Play with forceFriction() by using the Red Spinner. Rotate right for more, left for less, and press the spinner button to reset.'))
- console.log()
- console.log('Quit with Ctrl + C')
- // Start interval that changes wheel position
- let loop = setInterval(updatePosition, frq)
- })
- // Terminal Colors
- let color = {}
- const colors = {
- black: [30, 39],
- red: [31, 39],
- green: [32, 39],
- yellow: [33, 39],
- blue: [34, 39],
- magenta: [35, 39],
- cyan: [36, 39],
- white: [37, 39],
- gray: [90, 39],
- grey: [90, 39],
- // bright colors
- redBright: [91, 39],
- greenBright: [92, 39],
- yellowBright: [93, 39],
- blueBright: [94, 39],
- magentaBright: [95, 39],
- cyanBright: [96, 39],
- whiteBright: [97, 39]
- }
- const platform = os.platform()
- function showColor(hue, info = '') {
- // ` signifies a template literal
- return `\u001B[${colors[hue][0]}m` + info + `\u001B[${colors[hue][1]}m`
- } // showColor
- function setupColors() {
- for (let item in colors) {
- const hue = item
- color[hue] = function (info) {
- return showColor(hue, info)
- }
- }
- if (platform === 'win32' || platform === 'win64') {
- // use brigher versions of these colors
- color.red = color.redBright
- color.green = color.greenBright
- color.yellow = color.yellowBright
- color.blue = color.blueBright
- color.magenta = color.magentaBright
- color.cyan = color.cyanBright
- color.white = color.whiteBright
- }
- } // setupColors
- setupColors()
Control Logitech G29 wheel with intervals and amplitude
Requires node.js