[Keyboard] Overhaul ploopyco devices (#22967)

master
Drashna Jaelre 2024-03-14 22:15:44 -07:00 committed by GitHub
parent 359cec14fa
commit 68e8d74188
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 355 additions and 1909 deletions

View File

@ -142,7 +142,7 @@ int8_t opt_encoder_handler(uint16_t curA, uint16_t curB) {
} }
} }
else { // state must be LOHI else { // state must be LOHI
if (sA == HI && sB == HI) { if (sA == HI && sB == HI) {
state = HIHI; state = HIHI;
lohif = true; lohif = true;
@ -157,9 +157,13 @@ int8_t opt_encoder_handler(uint16_t curA, uint16_t curB) {
return ret; return ret;
} }
void calculateThresholdA(int curA) { scrollThresholdA = calculateThreshold(curA, &lowA, &highA, &cLowA, &cHighA, arLowA, arHighA, &lowIndexA, &highIndexA, &lowOverflowA, &highOverflowA); } void calculateThresholdA(int curA) {
scrollThresholdA = calculateThreshold(curA, &lowA, &highA, &cLowA, &cHighA, arLowA, arHighA, &lowIndexA, &highIndexA, &lowOverflowA, &highOverflowA);
}
void calculateThresholdB(int curB) { scrollThresholdB = calculateThreshold(curB, &lowB, &highB, &cLowB, &cHighB, arLowB, arHighB, &lowIndexB, &highIndexB, &lowOverflowB, &highOverflowB); } void calculateThresholdB(int curB) {
scrollThresholdB = calculateThreshold(curB, &lowB, &highB, &cLowB, &cHighB, arLowB, arHighB, &lowIndexB, &highIndexB, &lowOverflowB, &highOverflowB);
}
int calculateThreshold(int cur, int* low, int* high, bool* cLow, bool* cHigh, int arLow[], int arHigh[], int* lowIndex, int* highIndex, bool* lowOverflow, bool* highOverflow) { int calculateThreshold(int cur, int* low, int* high, bool* cLow, bool* cHigh, int arLow[], int arHigh[], int* lowIndex, int* highIndex, bool* lowOverflow, bool* highOverflow) {
if (cur < *low) *low = cur; if (cur < *low) *low = cur;
@ -236,7 +240,9 @@ int calculateThreshold(int cur, int* low, int* high, bool* cLow, bool* cHigh, in
return thresholdEquation(calcLow, calcHigh); return thresholdEquation(calcLow, calcHigh);
} }
int thresholdEquation(int lo, int hi) { return ((hi - lo) / 3) + lo; } int thresholdEquation(int lo, int hi) {
return ((hi - lo) / 3) + lo;
}
void incrementIndex(int* index, bool* ovflw) { void incrementIndex(int* index, bool* ovflw) {
if (*index < SCROLLER_AR_SIZE - 1) if (*index < SCROLLER_AR_SIZE - 1)

View File

@ -63,7 +63,7 @@
typedef enum { typedef enum {
CALIBRATION, /* Recalibrate encoder state by waiting for a 01 -> 00 or 10 -> 00 transistion */ CALIBRATION, /* Recalibrate encoder state by waiting for a 01 -> 00 or 10 -> 00 transistion */
DECODE /* Translate changes in the encoder state into movement */ DECODE /* Translate changes in the encoder state into movement */
} encoder_state_t; } encoder_state_t;
static encoder_state_t mode; static encoder_state_t mode;
@ -87,15 +87,14 @@ static const uint8_t movement[] = {
// 10 -> 00, 01, 10, 11 // 10 -> 00, 01, 10, 11
MOVE_DOWN, MOVE_ERR, MOVE_NONE, MOVE_UP, MOVE_DOWN, MOVE_ERR, MOVE_NONE, MOVE_UP,
// 11 -> 00, 01, 10, 11 // 11 -> 00, 01, 10, 11
MOVE_ERR, MOVE_UP, MOVE_DOWN, MOVE_NONE MOVE_ERR, MOVE_UP, MOVE_DOWN, MOVE_NONE};
};
void opt_encoder_init(void) { void opt_encoder_init(void) {
mode = CALIBRATION; mode = CALIBRATION;
lastState = 0; lastState = 0;
lowA = ENCODER_MAX; lowA = ENCODER_MAX;
lowB = ENCODER_MAX; lowB = ENCODER_MAX;
highA = ENCODER_MIN; highA = ENCODER_MIN;
highB = ENCODER_MIN; highB = ENCODER_MIN;
} }
@ -104,26 +103,22 @@ int8_t opt_encoder_handler(uint16_t encA, uint16_t encB) {
int8_t result = 0; int8_t result = 0;
highA = MAX(encA, highA); highA = MAX(encA, highA);
lowA = MIN(encA, lowA); lowA = MIN(encA, lowA);
highB = MAX(encB, highB); highB = MAX(encB, highB);
lowB = MIN(encB, lowB); lowB = MIN(encB, lowB);
/* Only compute the thresholds after a large enough range is established */ /* Only compute the thresholds after a large enough range is established */
if (highA - lowA > SCROLL_THRESH_RANGE_LIM && highB - lowB > SCROLL_THRESH_RANGE_LIM) { if (highA - lowA > SCROLL_THRESH_RANGE_LIM && highB - lowB > SCROLL_THRESH_RANGE_LIM) {
const int16_t lowThresholdA = (highA + lowA) / 4; const int16_t lowThresholdA = (highA + lowA) / 4;
const int16_t highThresholdA = (highA + lowA) - lowThresholdA; const int16_t highThresholdA = (highA + lowA) - lowThresholdA;
const int16_t lowThresholdB = (highB + lowB) / 4; const int16_t lowThresholdB = (highB + lowB) / 4;
const int16_t highThresholdB = (highB + lowB) - lowThresholdB; const int16_t highThresholdB = (highB + lowB) - lowThresholdB;
uint8_t state = MAKE_STATE( uint8_t state = MAKE_STATE(STATE_A(lastState) ? encA > lowThresholdA : encA > highThresholdA, STATE_B(lastState) ? encB > lowThresholdB : encB > highThresholdB);
STATE_A(lastState) ? encA > lowThresholdA : encA > highThresholdA,
STATE_B(lastState) ? encB > lowThresholdB : encB > highThresholdB
);
switch (mode) { switch (mode) {
case CALIBRATION: case CALIBRATION:
if ((lastState == HILO && state == LOLO) if ((lastState == HILO && state == LOLO) || (lastState == LOHI && state == LOLO))
|| (lastState == LOHI && state == LOLO))
mode = DECODE; mode = DECODE;
else else
mode = CALIBRATION; mode = CALIBRATION;
@ -134,7 +129,7 @@ int8_t opt_encoder_handler(uint16_t encA, uint16_t encB) {
/* If we detect a state change that should not be possible, /* If we detect a state change that should not be possible,
* then the wheel might have moved too fast and we need to * then the wheel might have moved too fast and we need to
* recalibrate the encoder position. */ * recalibrate the encoder position. */
mode = result == MOVE_ERR ? CALIBRATION : mode; mode = result == MOVE_ERR ? CALIBRATION : mode;
result = result == MOVE_ERR ? MOVE_NONE : result; result = result == MOVE_ERR ? MOVE_NONE : result;
break; break;

View File

@ -0,0 +1,116 @@
/* Copyright 2023 Leorize <leorize+oss@disroot.org>
* Copyright 2011 Ben Buxton <bb@cactii.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "opt_encoder.h"
#include <stdbool.h>
#include <stdint.h>
/* An extremely simple implementation of the encoder:
*
* For read out, the mechanism mimics that of a Schmitt trigger, with
* statically defined high/low thresholds used instead of computing
* one at runtime.
*
* The advantage of this approach is computing less in the decoder
* implementation and allow the state to be measured before the wheel
* moved.
*
* Compared to opt_encoder_simple.c, the use of an intermediary state
* reduces sensitivity and de-sensitize against tiny movements caused
* when lifting finger off the wheel.
*
* For turning decoded values into rotation, an algorithm inspired by
* http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html
* is employed.
*/
#if !defined(ENCODER_LOW_THRES_A) || !defined(ENCODER_HIGH_THRES_A)
# error "The thresholds for phototransistors A is not defined in config.h"
#endif
#if !defined(ENCODER_LOW_THRES_B) || !defined(ENCODER_HIGH_THRES_B)
# error "The thresholds for phototransistors B is not defined in config.h"
#endif
/*
* Sample values, captured for a Ploopy Mini Trackball
*
* The following min-max values was captured by aggregating data recorded
* when debug_encoder is enabled:
*
* A: min: 0, max: 214
* B: min: 0, max: 204
*
* The threshold specified is then defined at the 1/4 and the 3/4 points.
*
* As these values might vary between units, you're encouraged to
* measure your own.
*/
#if 0
# define ENCODER_LOW_THRES_A 53
# define ENCODER_HIGH_THRES_A 161
# define ENCODER_LOW_THRES_B 52
# define ENCODER_HIGH_THRES_B 153
#endif
/* Utilities for composing the encoder state */
#define MAKE_STATE(HI_A, HI_B) (((uint8_t)((HI_A) & 0x1) << 1) | ((uint8_t)((HI_B) & 0x1)))
#define STATE_A(st) ((st & 0x2) >> 1)
#define STATE_B(st) (st & 0x1)
typedef enum {
START,
DOWN_BEGIN,
UP_BEGIN,
START_MID,
DOWN_BEGIN_MID,
UP_BEGIN_MID,
STATE_MASK = 0xf, /* 0b1111 */
EMIT_UP = 0x10,
EMIT_UP_MID = EMIT_UP & START_MID,
EMIT_DOWN = 0x80,
EMIT_DOWN_MID = EMIT_DOWN & START_MID,
EMIT_MASK = 0xf0
} encoder_state_t;
static encoder_state_t state;
static uint8_t encState;
static const uint8_t transitions[] = {
// clang-format off
// START -> 00, 01, 10, 11
START, DOWN_BEGIN, UP_BEGIN, START_MID,
// DOWN_BEGIN -> 00, 01, 10, 11
START, DOWN_BEGIN, START, EMIT_DOWN_MID,
// UP_BEGIN -> 00, 01, 10, 11
START, START, UP_BEGIN, EMIT_UP_MID,
// START_MID -> 00, 01, 10, 11
START, UP_BEGIN_MID, DOWN_BEGIN_MID, START_MID,
// DOWN_BEGIN_MID -> 00, 01, 10, 11
EMIT_DOWN, START_MID, DOWN_BEGIN_MID, START_MID,
// UP_BEGIN_MID -> 00, 01, 10, 11
EMIT_UP, UP_BEGIN_MID, START_MID, START_MID,
// clang-format on
};
void opt_encoder_init(void) {
state = START;
encState = 0;
}
int8_t opt_encoder_handler(uint16_t encA, uint16_t encB) {
encState = MAKE_STATE((STATE_A(encState) & (encA > ENCODER_LOW_THRES_A)) | (encA > ENCODER_HIGH_THRES_A), (STATE_B(encState) & (encB > ENCODER_LOW_THRES_B)) | (encB > ENCODER_HIGH_THRES_B));
state = transitions[((state & STATE_MASK) << 2) + encState];
return state & EMIT_MASK;
}

View File

@ -18,6 +18,9 @@
#pragma once #pragma once
#define UNUSABLE_PINS \
{ GP1, GP3, GP4, GP6, GP8, GP10, GP14, GP16, GP18, GP20, GP22, GP24, GP25, GP26, GP27, GP28, GP29 }
// #define ROTATIONAL_TRANSFORM_ANGLE 0 // #define ROTATIONAL_TRANSFORM_ANGLE 0
#define POINTING_DEVICE_INVERT_Y #define POINTING_DEVICE_INVERT_Y

View File

@ -15,7 +15,7 @@
"extrakey": true, "extrakey": true,
"mousekey": true, "mousekey": true,
"nkro": true, "nkro": true,
"pointing_device": true, "pointing_device": true
}, },
"layouts": { "layouts": {
"LAYOUT": { "LAYOUT": {
@ -31,5 +31,5 @@
}, },
"dynamic_keymap": { "dynamic_keymap": {
"layer_count": 8 "layer_count": 8
}, }
} }

View File

@ -1,176 +0,0 @@
/* Copyright 2023 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "madromys.h"
#ifndef PLOOPY_DPI_OPTIONS
# define PLOOPY_DPI_OPTIONS \
{ 600, 900, 1200, 1600 }
# ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 1
# endif
#endif
#ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 0
#endif
#ifndef PLOOPY_DRAGSCROLL_DPI
# define PLOOPY_DRAGSCROLL_DPI 100 // Fixed-DPI Drag Scroll
#endif
#ifndef PLOOPY_DRAGSCROLL_FIXED
# define PLOOPY_DRAGSCROLL_FIXED 1
#endif
#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER
# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll
#endif
#ifndef PLOOPY_DRAGSCROLL_SEMAPHORE
# define PLOOPY_DRAGSCROLL_SEMAPHORE 4
#endif
#ifndef PLOOPY_DRAGSCROLL_MOMENTARY
# define PLOOPY_DRAGSCROLL_MOMENTARY 1
#endif
#ifndef PLOOPY_DRAGSCROLL_INVERT
# define PLOOPY_DRAGSCROLL_INVERT 1
#endif
keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
// TODO: Implement libinput profiles
// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
// Compile time accel selection
// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
// Trackball State
bool is_drag_scroll = false;
// drag scroll divisor state
int8_t drag_scroll_x_semaphore = 0;
int8_t drag_scroll_y_semaphore = 0;
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
if (is_drag_scroll) {
int16_t mouse_report_x_temp = mouse_report.x;
int16_t mouse_report_y_temp = mouse_report.y;
int16_t mouse_report_x_calc = 0;
int16_t mouse_report_y_calc = 0;
int16_t valx = (mouse_report_x_temp > 0) ? -1 : 1;
int16_t valy = (mouse_report_y_temp > 0) ? -1 : 1;
while (mouse_report_x_temp != 0) {
mouse_report_x_temp += valx;
drag_scroll_x_semaphore -= valx;
if (abs(drag_scroll_x_semaphore) >= PLOOPY_DRAGSCROLL_SEMAPHORE) {
mouse_report_x_calc -= valx;
drag_scroll_x_semaphore = 0;
}
}
while (mouse_report_y_temp != 0) {
mouse_report_y_temp += valy;
drag_scroll_y_semaphore -= valy;
if (abs(drag_scroll_y_semaphore) >= PLOOPY_DRAGSCROLL_SEMAPHORE) {
mouse_report_y_calc -= valy;
drag_scroll_y_semaphore = 0;
}
}
mouse_report.h = mouse_report_x_calc;
#ifdef PLOOPY_DRAGSCROLL_INVERT
// Invert vertical scroll direction
mouse_report.v = -mouse_report_y_calc;
#else
mouse_report.v = mouse_report_y_calc;
#endif
mouse_report.x = 0;
mouse_report.y = 0;
}
return pointing_device_task_user(mouse_report);
}
bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
if (!process_record_user(keycode, record)) {
return false;
}
if (keycode == DPI_CONFIG && record->event.pressed) {
keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
eeconfig_update_kb(keyboard_config.raw);
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
if (keycode == DRAG_SCROLL) {
#ifndef PLOOPY_DRAGSCROLL_MOMENTARY
if (record->event.pressed)
#endif
{
is_drag_scroll ^= 1;
}
#ifdef PLOOPY_DRAGSCROLL_FIXED
pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
#else
pointing_device_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]);
#endif
}
return true;
}
// Hardware Setup
void keyboard_pre_init_kb(void) {
// debug_enable = true;
// debug_matrix = true;
// debug_mouse = true;
// debug_encoder = true;
/* Ground all output pins connected to ground. This provides additional
* pathways to ground. If you're messing with this, know this: driving ANY
* of these pins high will cause a short. On the MCU. Ka-blooey.
*/
const pin_t unused_pins[] = { GP1, GP3, GP4, GP6, GP8, GP10, GP14, GP16,
GP18, GP20, GP22, GP24, GP25, GP26, GP27, GP28, GP29 };
for (uint8_t i = 0; i < (sizeof(unused_pins) / sizeof(pin_t)); i++) {
setPinOutput(unused_pins[i]);
writePinLow(unused_pins[i]);
}
keyboard_pre_init_user();
}
void pointing_device_init_kb(void) { pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); }
void eeconfig_init_kb(void) {
keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}
void matrix_init_kb(void) {
// is safe to just read DPI setting since matrix init
// comes before pointing device init.
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
matrix_init_user();
}

View File

@ -1,37 +0,0 @@
/* Copyright 2023 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
typedef union {
uint32_t raw;
struct {
uint8_t dpi_config;
};
} keyboard_config_t;
_Static_assert(sizeof(keyboard_config_t) == sizeof(uint32_t), "keyboard_config_t size mismatch compared to EEPROM area");
extern keyboard_config_t keyboard_config;
extern uint16_t dpi_array[];
enum ploopy_keycodes {
DPI_CONFIG = QK_KB_0,
DRAG_SCROLL,
};

View File

@ -27,17 +27,6 @@ If you want to upload a new firmware file (a ".uf2" file, like "madromys_awesome
**TIP**: If your firmware is in some kind of strange state and uploading new firmware isn't fixing it, try uploading [a flash nuke](https://learn.adafruit.com/getting-started-with-raspberry-pi-pico-circuitpython/circuitpython#flash-resetting-uf2-3083182) to the Madromys board before flashing the new firmware. It wipes the memory of the Madromys board completely clean, which can help clear a few types of errors. **TIP**: If your firmware is in some kind of strange state and uploading new firmware isn't fixing it, try uploading [a flash nuke](https://learn.adafruit.com/getting-started-with-raspberry-pi-pico-circuitpython/circuitpython#flash-resetting-uf2-3083182) to the Madromys board before flashing the new firmware. It wipes the memory of the Madromys board completely clean, which can help clear a few types of errors.
# Drag Scroll # Customizing your Ploopy Madromys
Drag Scroll is a custom keycode for Ploopy devices that allows you to hold or tap a button and have the mouse movement translate into scrolling instead. You can find customziation options [here](../readme.md).
Nothing needs to be enabled to use this functionality; it's enabled on Madromys by default.
### Drag Scroll Configuration
* `#define PLOOPY_DRAGSCROLL_MOMENTARY` - Makes the key into a momentary key, rather than a toggle.
* `#define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75` - Sets the DPI multiplier to use when drag scroll is enabled.
* `#define PLOOPY_DRAGSCROLL_FIXED` - Normally, when activating Drag Scroll, it uses a fraction of the current DPI. You can define this to use a specific, set DPI rather than a fraction of the current DPI.
* `#define PLOOPY_DRAGSCROLL_DPI 100` - When the fixed DPI option is enabled, this sets the DPI to be used for Drag Scroll.
* `#define PLOOPY_DRAGSCROLL_INVERT` - This reverses the direction that the scroll is performed.
* `#define PLOOPY_DRAGSCROLL_SEMAPHORE` - This is a divisor on the drag scroll sensitivity. The default is 0, which means that the drag scroll is at maximum sensitivity. A value of 4 would mean that the drag scroll is 4 times less sensitive.

View File

@ -33,5 +33,10 @@
/* PMW33XX Settings */ /* PMW33XX Settings */
#define PMW33XX_CS_PIN B0 #define PMW33XX_CS_PIN B0
#define ENCODER_BUTTON_COL 1
#define ENCODER_BUTTON_ROW 0
/* Custom encoder needs to specify just how many encoders we have */ /* Custom encoder needs to specify just how many encoders we have */
#define NUM_ENCODERS 1 #define NUM_ENCODERS 1
#define ENCODERS_PAD_A { F0 }
#define ENCODERS_PAD_B { F4 }

View File

@ -9,6 +9,15 @@
"device_version": "0.0.1", "device_version": "0.0.1",
"max_power": 100 "max_power": 100
}, },
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": false,
"pointing_device": true,
"rgblight": false,
"encoder": true
},
"bootmagic": { "bootmagic": {
"matrix": [0, 3] "matrix": [0, 3]
}, },
@ -31,9 +40,6 @@
["D4", "D2", "E6", "B6", "D7", "C6", "C7", "B7"] ["D4", "D2", "E6", "B6", "D7", "C6", "C7", "B7"]
] ]
}, },
"features": {
"encoder": true
},
"encoder": { "encoder": {
"driver": "custom" "driver": "custom"
}, },

View File

@ -1,27 +0,0 @@
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2020 Ploopy Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT(/* Base */
C(KC_C), KC_BTN1, KC_BTN3, LT(1, KC_BTN2), C(KC_V), KC_BTN4, KC_BTN5, DPI_CONFIG),
[1] = LAYOUT(/* Base */
_______, DRAG_SCROLL, _______, _______, _______, _______, _______, QK_BOOT),
};

View File

@ -1,3 +0,0 @@
# The Drag Scroll keymap for PloopyCo Mouse
This is a sample keymap showing off what you can do with the custom callback drivers.

View File

@ -1,49 +0,0 @@
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2020 Ploopy Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "analog.h"
#include "opt_encoder.h"
// Sensor defs
#define OPT_ENC1 F0
#define OPT_ENC2 F4
#define OPT_ENC1_MUX 0
#define OPT_ENC2_MUX 4
void process_wheel(void);
typedef union {
uint32_t raw;
struct {
uint8_t dpi_config;
};
} keyboard_config_t;
extern keyboard_config_t keyboard_config;
extern uint16_t dpi_array[];
enum ploopy_keycodes {
DPI_CONFIG = QK_KB_0,
DRAG_SCROLL,
};
bool encoder_update_user(uint8_t index, bool clockwise);
bool encoder_update_kb(uint8_t index, bool clockwise);

View File

@ -19,48 +19,4 @@ See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_to
# Customizing your PloopyCo Mouse # Customizing your PloopyCo Mouse
While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change. Such as adding DPI control, or to use the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse sensor. You can find customziation options [here](../readme.md).
The default behavior for this is:
```c
void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
mouse_report->h = h;
mouse_report->v = v;
}
void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
mouse_report->x = x;
mouse_report->y = y;
}
```
This should allow you to more heavily customize the behavior.
Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
Additionally, you can change the DPI/CPI or speed of the trackball by calling `pointing_device_set_cpi` at any time. Additionally, there is a `DPI_CONFIG` macro that will cycle through an array of options for the DPI. This is set to 1200, 1600, and 2400, but can be changed. 1600 is also set to the default.
To configure/set your own array, there are two defines to use, `PLOOPY_DPI_OPTIONS` to set the array, and `PLOOPY_DPI_DEFAULT`.
```c
#define PLOOPY_DPI_OPTIONS { 1200, 1600, 2400 }
#define PLOOPY_DPI_DEFAULT 1
```
The `PLOOPY_DPI_OPTIONS` array sets the values that you want to be able to cycle through, and the order they are in. The "default" define lets the firmware know which of these options is the default and should be loaded by default.
The `DPI_CONFIG` macro will cycle through the values in the array, each time you hit it. And it stores this value in persistent memory, so it will load it the next time the device powers up.
## Drag Scroll
Drag Sroll is a custom keycode for the Ploopy devices that allow you to hold or tap a button and have the mouse movement translate into scrolling instead.
Nothing needs to be enabled to use this functionality. Just add the `DRAG_SCROLL` to your keymap.
### Drag Scroll Configuration
* `#define PLOOPY_DRAGSCROLL_MOMENTARY` - Makes the key into a momentary key, rather than a toggle.
* `#define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75` - Sets the DPI multiplier to use when drag scroll is enabled.
* `#define PLOOPY_DRAGSCROLL_FIXED` - Normally, when activating Drag Scroll, it uses a fraction of the current DPI. You can define this to use a specific, set DPI rather than a fraction of the current DPI.
* `#define PLOOPY_DRAGSCROLL_DPI 100` - When the fixed DPI option is enabled, this sets the DPI to be used for Drag Scroll.
* `#define PLOOPY_DRAGSCROLL_INVERT` - This reverses the direction that the scroll is performed.

View File

@ -1,21 +1,4 @@
# Processor frequency # Processor frequency
F_CPU = 8000000 F_CPU = 8000000
# Build Options
# change yes to no to disable
#
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
AUDIO_ENABLE = no # Audio output
POINTING_DEVICE_ENABLE = yes
POINTING_DEVICE_DRIVER = pmw3360 POINTING_DEVICE_DRIVER = pmw3360
MOUSEKEY_ENABLE = yes # Mouse keys
ANALOG_DRIVER_REQUIRED = yes
SRC += opt_encoder.c

View File

@ -16,23 +16,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "mouse.h" #include "ploopyco.h"
#include "analog.h"
#include "opt_encoder.h"
#ifndef OPT_DEBOUNCE // for legacy support
# define OPT_DEBOUNCE 5 // (ms) Time between scroll events #if defined(OPT_DEBOUNCE) && !defined(PLOOPY_SCROLL_DEBOUNCE)
# define PLOOPY_SCROLL_DEBOUNCE OPT_DEBOUNCE
#endif #endif
#ifndef SCROLL_BUTT_DEBOUNCE #if defined(SCROLL_BUTT_DEBOUNCE) && !defined(PLOOPY_SCROLL_BUTTON_DEBOUNCE)
# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events # define PLOOPY_SCROLL_BUTTON_DEBOUNCE SCROLL_BUTT_DEBOUNCE
#endif #endif
#ifndef OPT_THRES
# define OPT_THRES 150 // (0-1024) Threshold for actication #ifndef PLOOPY_SCROLL_DEBOUNCE
# define PLOOPY_SCROLL_DEBOUNCE 5
#endif #endif
#ifndef OPT_SCALE #ifndef PLOOPY_SCROLL_BUTTON_DEBOUNCE
# define OPT_SCALE 1 // Multiplier for wheel # define PLOOPY_SCROLL_BUTTON_DEBOUNCE 100
#endif #endif
#ifndef PLOOPY_DPI_OPTIONS #ifndef PLOOPY_DPI_OPTIONS
# define PLOOPY_DPI_OPTIONS \ # define PLOOPY_DPI_OPTIONS \
{ 1200, 1600, 2400 } { 600, 900, 1200, 1600, 2400 }
# ifndef PLOOPY_DPI_DEFAULT # ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 1 # define PLOOPY_DPI_DEFAULT 1
# endif # endif
@ -40,94 +45,110 @@
#ifndef PLOOPY_DPI_DEFAULT #ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 0 # define PLOOPY_DPI_DEFAULT 0
#endif #endif
#ifndef PLOOPY_DRAGSCROLL_DPI #ifndef PLOOPY_DRAGSCROLL_DIVISOR_H
# define PLOOPY_DRAGSCROLL_DPI 100 // Fixed-DPI Drag Scroll # define PLOOPY_DRAGSCROLL_DIVISOR_H 8.0
#endif #endif
#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER #ifndef PLOOPY_DRAGSCROLL_DIVISOR_V
# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll # define PLOOPY_DRAGSCROLL_DIVISOR_V 8.0
#endif
#ifndef ENCODER_BUTTON_ROW
# define ENCODER_BUTTON_ROW 0
#endif
#ifndef ENCODER_BUTTON_COL
# define ENCODER_BUTTON_COL 0
#endif #endif
keyboard_config_t keyboard_config; keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS; uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array) #define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array)
// TODO: Implement libinput profiles
// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
// Compile time accel selection
// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
// Trackball State // Trackball State
bool is_scroll_clicked = false; bool is_scroll_clicked = false;
bool BurstState = false; // init burst state for Trackball module bool is_drag_scroll = false;
uint16_t MotionStart = 0; // Timer for accel, 0 is resting state float scroll_accumulated_h = 0;
uint16_t lastScroll = 0; // Previous confirmed wheel event float scroll_accumulated_v = 0;
uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
uint8_t OptLowPin = OPT_ENC1; #ifdef ENCODER_ENABLE
uint16_t lastScroll = 0; // Previous confirmed wheel event
uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
pin_t encoder_pins_a[1] = ENCODERS_PAD_A;
pin_t encoder_pins_b[1] = ENCODERS_PAD_B;
bool debug_encoder = false; bool debug_encoder = false;
bool is_drag_scroll = false;
bool encoder_update_kb(uint8_t index, bool clockwise) { bool encoder_update_kb(uint8_t index, bool clockwise) {
if (!encoder_update_user(index, clockwise)) { if (!encoder_update_user(index, clockwise)) {
return false; return false;
} }
#ifdef MOUSEKEY_ENABLE # ifdef MOUSEKEY_ENABLE
tap_code(clockwise ? KC_WH_U : KC_WH_D); tap_code(clockwise ? KC_WH_U : KC_WH_D);
#else # else
report_mouse_t mouse_report = pointing_device_get_report(); report_mouse_t mouse_report = pointing_device_get_report();
mouse_report.v = clockwise ? 1 : -1; mouse_report.v = clockwise ? 1 : -1;
pointing_device_set_report(mouse_report); pointing_device_set_report(mouse_report);
pointing_device_send(); pointing_device_send();
#endif # endif
return true; return true;
} }
void encoder_driver_init(void) { void encoder_driver_init(void) {
setPinInput(OPT_ENC1); for (uint8_t i = 0; i < ARRAY_SIZE(encoder_pins_a); i++) {
setPinInput(OPT_ENC2); gpio_set_pin_input(encoder_pins_a[i]);
gpio_set_pin_input(encoder_pins_b[i]);
}
opt_encoder_init(); opt_encoder_init();
} }
void encoder_driver_task(void) { void encoder_driver_task(void) {
// Lovingly ripped from the Ploopy Source uint16_t p1 = analogReadPin(encoder_pins_a[0]);
uint16_t p2 = analogReadPin(encoder_pins_b[0]);
if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
int8_t dir = opt_encoder_handler(p1, p2);
// If the mouse wheel was just released, do not scroll. // If the mouse wheel was just released, do not scroll.
if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) { if (timer_elapsed(lastMidClick) < PLOOPY_SCROLL_BUTTON_DEBOUNCE) {
return; return;
} }
// Limit the number of scrolls per unit time. // Limit the number of scrolls per unit time.
if (timer_elapsed(lastScroll) < OPT_DEBOUNCE) { if (timer_elapsed(lastScroll) < PLOOPY_SCROLL_DEBOUNCE) {
return; return;
} }
// Don't scroll if the middle button is depressed. // Don't scroll if the middle button is depressed.
if (is_scroll_clicked) { if (is_scroll_clicked) {
#ifndef IGNORE_SCROLL_CLICK # ifndef PLOOPY_IGNORE_SCROLL_CLICK
return; return;
#endif # endif
} }
lastScroll = timer_read();
uint16_t p1 = adc_read(OPT_ENC1_MUX);
uint16_t p2 = adc_read(OPT_ENC2_MUX);
if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
int dir = opt_encoder_handler(p1, p2);
if (dir == 0) return; if (dir == 0) return;
encoder_queue_event(0, dir == 1); encoder_queue_event(0, dir > 0);
lastScroll = timer_read();
} }
#endif
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) { report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
if (is_drag_scroll) { if (is_drag_scroll) {
mouse_report.h = mouse_report.x; scroll_accumulated_h += (float)mouse_report.x / PLOOPY_DRAGSCROLL_DIVISOR_H;
scroll_accumulated_v += (float)mouse_report.y / PLOOPY_DRAGSCROLL_DIVISOR_V;
// Assign integer parts of accumulated scroll values to the mouse report
mouse_report.h = (int8_t)scroll_accumulated_h;
#ifdef PLOOPY_DRAGSCROLL_INVERT #ifdef PLOOPY_DRAGSCROLL_INVERT
// Invert vertical scroll direction mouse_report.v = -(int8_t)scroll_accumulated_v;
mouse_report.v = -mouse_report.y;
#else #else
mouse_report.v = mouse_report.y; mouse_report.v = (int8_t)scroll_accumulated_v;
#endif #endif
// Update accumulated scroll values by subtracting the integer parts
scroll_accumulated_h -= (int8_t)scroll_accumulated_h;
scroll_accumulated_v -= (int8_t)scroll_accumulated_v;
// Clear the X and Y values of the mouse report
mouse_report.x = 0;
mouse_report.y = 0;
mouse_report.x = 0; mouse_report.x = 0;
mouse_report.y = 0; mouse_report.y = 0;
} }
@ -141,10 +162,12 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
} }
// Update Timer to prevent accidental scrolls // Update Timer to prevent accidental scrolls
if ((record->event.key.col == 1) && (record->event.key.row == 0)) { #ifdef ENCODER_ENABLE
if ((record->event.key.col == ENCODER_BUTTON_COL) && (record->event.key.row == ENCODER_BUTTON_ROW)) {
lastMidClick = timer_read(); lastMidClick = timer_read();
is_scroll_clicked = record->event.pressed; is_scroll_clicked = record->event.pressed;
} }
#endif
if (!process_record_user(keycode, record)) { if (!process_record_user(keycode, record)) {
return false; return false;
@ -157,16 +180,12 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
} }
if (keycode == DRAG_SCROLL) { if (keycode == DRAG_SCROLL) {
#ifndef PLOOPY_DRAGSCROLL_MOMENTARY #ifdef PLOOPY_DRAGSCROLL_MOMENTARY
if (record->event.pressed) is_drag_scroll = record->event.pressed;
#endif #else
{ if (record->event.pressed) {
is_drag_scroll ^= 1; is_drag_scroll ^= 1;
} }
#ifdef PLOOPY_DRAGSCROLL_FIXED
pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
#else
pointing_device_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]);
#endif #endif
} }
@ -188,21 +207,25 @@ void keyboard_pre_init_kb(void) {
const pin_t unused_pins[] = UNUSABLE_PINS; const pin_t unused_pins[] = UNUSABLE_PINS;
for (uint8_t i = 0; i < ARRAY_SIZE(unused_pins); i++) { for (uint8_t i = 0; i < ARRAY_SIZE(unused_pins); i++) {
setPinOutput(unused_pins[i]); gpio_set_pin_output_push_pull(unused_pins[i]);
writePinLow(unused_pins[i]); gpio_write_pin_low(unused_pins[i]);
} }
#endif #endif
// This is the debug LED. // This is the debug LED.
#if defined(DEBUG_LED_PIN) #if defined(DEBUG_LED_PIN)
setPinOutput(DEBUG_LED_PIN); gpio_set_pin_output_push_pull(DEBUG_LED_PIN);
writePin(DEBUG_LED_PIN, debug_enable); gpio_write_pin(DEBUG_LED_PIN, debug_enable);
#endif #endif
keyboard_pre_init_user(); keyboard_pre_init_user();
} }
void pointing_device_init_kb(void) { void pointing_device_init_kb(void) {
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
} }
@ -211,13 +234,3 @@ void eeconfig_init_kb(void) {
eeconfig_update_kb(keyboard_config.raw); eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user(); eeconfig_init_user();
} }
void matrix_init_kb(void) {
// is safe to just read DPI setting since matrix init
// comes before pointing device init.
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
matrix_init_user();
}

View File

@ -19,14 +19,6 @@
#pragma once #pragma once
#include "quantum.h" #include "quantum.h"
#include "analog.h"
#include "opt_encoder.h"
// Sensor defs
#define OPT_ENC1 F0
#define OPT_ENC2 F4
#define OPT_ENC1_MUX 0
#define OPT_ENC2_MUX 4
typedef union { typedef union {
uint32_t raw; uint32_t raw;

View File

@ -0,0 +1,12 @@
OPT_ENCODER_TYPE ?= default
VALID_OPT_ENCODER_TYPES := default simple tiny custom
ifeq ($(filter $(OPT_ENCODER_TYPE),$(VALID_OPT_ENCODER_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid OPT_ENCODER_TYPE,OPT_ENCODER_TYPE="$(OPT_ENCODER_TYPE)" is not a valid pointing device type)
else
ifneq ($(strip $(OPT_ENCODER_TYPE)), custom)
VPATH += keyboards/ploopyco/common
SRC += opt_encoder_$(strip $(OPT_ENCODER_TYPE)).c
ANALOG_DRIVER_REQUIRED = yes
endif
endif

View File

@ -0,0 +1,45 @@
# Ploopyco
* [Mouse](mouse/)
* [Trackball](trackball/)
* [Trackball Mini](trackball_mini/)
* [Trackball Nano](trackball_nano/)
* [Trackball Thumb](trackball_thumb/)
* [Adept/Madromys](manromys/)
# Customizing your PloopyCo Device
There are a number of behavioral settings that you can use to help customize your experience
| | | |
|---------------------------------|-------------------|-----------------------------------------------------------|
| `PLOOPY_IGNORE_SCROLL_CLICK` | *__not_defined__* | Ignores scroll wheel if it is pressed down. |
| `PLOOPY_SCROLL_DEBOUNCE` | `5` | Number of milliseconds between scroll events. |
| `PLOOPY_SCROLL_BUTTON_DEBOUNCE` | `100` | Time to ignore scroll events after pressing scroll wheel. |
## DPI
You can change the DPI/CPI or speed of the trackball by calling `pointing_device_set_cpi` at any time. Additionally, there is a `DPI_CONFIG` macro that will cycle through an array of options for the DPI. This is set to 1200, 1600, and 2400, but can be changed. 1600 is also set to the default.
To configure/set your own array, there are two defines to use, `PLOOPY_DPI_OPTIONS` to set the array, and `PLOOPY_DPI_DEFAULT`.
```c
#define PLOOPY_DPI_OPTIONS { 1200, 1600, 2400 }
#define PLOOPY_DPI_DEFAULT 1
```
The `PLOOPY_DPI_OPTIONS` array sets the values that you want to be able to cycle through, and the order they are in. The "default" define lets the firmware know which of these options is the default and should be loaded by default.
The `DPI_CONFIG` macro will cycle through the values in the array, each time you hit it. And it stores this value in persistent memory, so it will load it the next time the device powers up.
## Drag Scroll
Drag Sroll is a custom keycode for the Ploopy devices that allow you to hold or tap a button and have the mouse movement translate into scrolling instead.
Nothing needs to be enabled to use this functionality. Just add the `DRAG_SCROLL` to your keymap.
### Drag Scroll Configuration
* `#define PLOOPY_DRAGSCROLL_MOMENTARY` - Makes the key into a momentary key, rather than a toggle.
* `#define PLOOPY_DRAGSCROLL_DIVISOR_H 8.0` - Sets the horizontal movement divisor to use when drag scroll is enabled.
* `#define PLOOPY_DRAGSCROLL_DIVISOR_V 8.0` - Sets the vertical movement divisor to use when drag scroll is enabled.
* `#define PLOOPY_DRAGSCROLL_INVERT` - This reverses the direction that the scroll is performed.

View File

@ -32,5 +32,11 @@
#define PMW33XX_CS_PIN B0 #define PMW33XX_CS_PIN B0
#define POINTING_DEVICE_INVERT_Y #define POINTING_DEVICE_INVERT_Y
#define ENCODER_BUTTON_COL 1
#define ENCODER_BUTTON_ROW 0
/* Custom encoder needs to specify just how many encoders we have */ /* Custom encoder needs to specify just how many encoders we have */
#define NUM_ENCODERS 1 #define NUM_ENCODERS 1
#define ENCODERS_PAD_A { F0 }
#define ENCODERS_PAD_B { F4 }

View File

@ -12,7 +12,13 @@
"bootmagic": { "bootmagic": {
"matrix": [0, 3] "matrix": [0, 3]
}, },
"features": { "features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": false,
"pointing_device": true,
"encoder": true "encoder": true
}, },
"encoder": { "encoder": {

View File

@ -1,30 +0,0 @@
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2020 Ploopy Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT( /* Base */
KC_BTN1, KC_BTN3, KC_BTN2,
KC_BTN4, LT(1, KC_BTN5)
),
[1] = LAYOUT(
DRAG_SCROLL, _______, _______,
_______, _______
)
};

View File

@ -1,3 +0,0 @@
# The Drag Scroll keymap for Ploopyco Trackball
This is a sample keymap showing off what you can do with the custom callback drivers.

View File

@ -27,45 +27,4 @@ The PCB should indicate which revision this is.
# Customizing your PloopyCo Trackball # Customizing your PloopyCo Trackball
While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change. Such as adding DPI control, or to use the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse sensor. You can find customziation options [here](../readme.md).
```c
report_mouse_t pointing_device_task_user(report_mouse_t mouse_report){
// executed each time the sensor is updated
// mouse_report.<attribute> - can be used to access indivdual mouse attributes
return mouse_report;
}
```
More information on `report_mouse_t` may be found [here](https://docs.qmk.fm/#/feature_pointing_device?id=manipulating-mouse-reports).
This should allow you to more heavily customize the behavior.
Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
Additionally, you can change the DPI/CPI or speed of the trackball by calling `pointing_device_set_cpi` at any time. Additionally, there is a `DPI_CONFIG` macro that will cycle through an array of options for the DPI. This is set to 1200, 1600, and 2400, but can be changed. 1600 is also set to the default.
To configure/set your own array, there are two defines to use, `PLOOPY_DPI_OPTIONS` to set the array, and `PLOOPY_DPI_DEFAULT`.
```c
#define PLOOPY_DPI_OPTIONS { 1200, 1600, 2400 }
#define PLOOPY_DPI_DEFAULT 1
```
The `PLOOPY_DPI_OPTIONS` array sets the values that you want to be able to cycle through, and the order they are in. The "default" define lets the firmware know which of these options is the default and should be loaded by default.
The `DPI_CONFIG` macro will cycle through the values in the array, each time you hit it. And it stores this value in persistent memory, so it will load it the next time the device powers up.
## Drag Scroll
Drag Sroll is a custom keycode for the Ploopy devices that allow you to hold or tap a button and have the mouse movement translate into scrolling instead.
Nothing needs to be enabled to use this functionality. Just add the `DRAG_SCROLL` to your keymap.
### Drag Scroll Configuration
* `#define PLOOPY_DRAGSCROLL_MOMENTARY` - Makes the key into a momentary key, rather than a toggle.
* `#define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75` - Sets the DPI multiplier to use when drag scroll is enabled.
* `#define PLOOPY_DRAGSCROLL_FIXED` - Normally, when activating Drag Scroll, it uses a fraction of the current DPI. You can define this to use a specific, set DPI rather than a fraction of the current DPI.
* `#define PLOOPY_DRAGSCROLL_DPI 100` - When the fixed DPI option is enabled, this sets the DPI to be used for Drag Scroll.
* `#define PLOOPY_DRAGSCROLL_INVERT` - This reverses the direction that the scroll is performed.

View File

@ -1,23 +1,6 @@
# Processor frequency # Processor frequency
F_CPU = 8000000 F_CPU = 8000000
# Build Options
# change yes to no to disable
#
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
AUDIO_ENABLE = no # Audio output
POINTING_DEVICE_ENABLE = yes
POINTING_DEVICE_DRIVER = pmw3360 POINTING_DEVICE_DRIVER = pmw3360
MOUSEKEY_ENABLE = yes # Mouse keys
ANALOG_DRIVER_REQUIRED = yes
SRC += opt_encoder.c
DEFAULT_FOLDER = ploopyco/trackball/rev1_005 DEFAULT_FOLDER = ploopyco/trackball/rev1_005

View File

@ -1,243 +0,0 @@
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2020 Ploopy Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trackball.h"
#ifndef OPT_DEBOUNCE
# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
#endif
#ifndef SCROLL_BUTT_DEBOUNCE
# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
#endif
#ifndef OPT_THRES
# define OPT_THRES 150 // (0-1024) Threshold for actication
#endif
#ifndef OPT_SCALE
# define OPT_SCALE 1 // Multiplier for wheel
#endif
#ifndef PLOOPY_DPI_OPTIONS
# define PLOOPY_DPI_OPTIONS \
{ 1200, 1600, 2400 }
# ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 1
# endif
#endif
#ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 0
#endif
#ifndef PLOOPY_DRAGSCROLL_DPI
# define PLOOPY_DRAGSCROLL_DPI 100 // Fixed-DPI Drag Scroll
#endif
#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER
# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll
#endif
keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array)
// TODO: Implement libinput profiles
// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
// Compile time accel selection
// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
// Trackball State
bool is_scroll_clicked = false;
bool BurstState = false; // init burst state for Trackball module
uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
uint16_t lastScroll = 0; // Previous confirmed wheel event
uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
uint8_t OptLowPin = OPT_ENC1;
bool debug_encoder = false;
bool is_drag_scroll = false;
bool encoder_update_kb(uint8_t index, bool clockwise) {
if (!encoder_update_user(index, clockwise)) {
return false;
}
#ifdef MOUSEKEY_ENABLE
tap_code(clockwise ? KC_WH_U : KC_WH_D);
#else
report_mouse_t mouse_report = pointing_device_get_report();
mouse_report.v = clockwise ? 1 : -1;
pointing_device_set_report(mouse_report);
pointing_device_send();
#endif
return true;
}
void encoder_driver_init(void) {
setPinInput(OPT_ENC1);
setPinInput(OPT_ENC2);
opt_encoder_init();
}
void encoder_driver_task(void) {
// TODO: Replace this with interrupt driven code, polling is S L O W
// Lovingly ripped from the Ploopy Source
// If the mouse wheel was just released, do not scroll.
if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) {
return;
}
// Limit the number of scrolls per unit time.
if (timer_elapsed(lastScroll) < OPT_DEBOUNCE) {
return;
}
// Don't scroll if the middle button is depressed.
if (is_scroll_clicked) {
#ifndef IGNORE_SCROLL_CLICK
return;
#endif
}
lastScroll = timer_read();
uint16_t p1 = adc_read(OPT_ENC1_MUX);
uint16_t p2 = adc_read(OPT_ENC2_MUX);
if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
int dir = opt_encoder_handler(p1, p2);
if (dir == 0) return;
encoder_queue_event(0, dir == 1);
}
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
if (is_drag_scroll) {
#ifdef PLOOPY_DRAGSCROLL_H_INVERT
// Invert horizontal scroll direction
mouse_report.h = -mouse_report.x;
#else
mouse_report.h = mouse_report.x;
#endif
#ifdef PLOOPY_DRAGSCROLL_INVERT
// Invert vertical scroll direction
mouse_report.v = -mouse_report.y;
#else
mouse_report.v = mouse_report.y;
#endif
mouse_report.x = 0;
mouse_report.y = 0;
}
return pointing_device_task_user(mouse_report);
}
bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
if (true) {
xprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
}
// Update Timer to prevent accidental scrolls
if ((record->event.key.col == 1) && (record->event.key.row == 0)) {
lastMidClick = timer_read();
is_scroll_clicked = record->event.pressed;
}
if (!process_record_user(keycode, record)) {
return false;
}
if (keycode == DPI_CONFIG && record->event.pressed) {
keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
eeconfig_update_kb(keyboard_config.raw);
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
if (keycode == DRAG_SCROLL) {
#ifndef PLOOPY_DRAGSCROLL_MOMENTARY
if (record->event.pressed)
#endif
{
is_drag_scroll ^= 1;
}
#ifdef PLOOPY_DRAGSCROLL_FIXED
pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
#else
pointing_device_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]);
#endif
}
/* If Mousekeys is disabled, then use handle the mouse button
* keycodes. This makes things simpler, and allows usage of
* the keycodes in a consistent manner. But only do this if
* Mousekeys is not enable, so it's not handled twice.
*/
return true;
}
// Hardware Setup
void keyboard_pre_init_kb(void) {
// debug_enable = true;
// debug_matrix = true;
// debug_mouse = true;
// debug_encoder = true;
/* Ground all output pins connected to ground. This provides additional
* pathways to ground. If you're messing with this, know this: driving ANY
* of these pins high will cause a short. On the MCU. Ka-blooey.
*/
#ifdef UNUSABLE_PINS
const pin_t unused_pins[] = UNUSABLE_PINS;
for (uint8_t i = 0; i < ARRAY_SIZE(unused_pins); i++) {
setPinOutput(unused_pins[i]);
writePinLow(unused_pins[i]);
}
#endif
// This is the debug LED.
#if defined(DEBUG_LED_PIN)
setPinOutput(DEBUG_LED_PIN);
writePin(DEBUG_LED_PIN, debug_enable);
#endif
keyboard_pre_init_user();
}
void pointing_device_init_kb(void) {
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
void eeconfig_init_kb(void) {
keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}
void matrix_init_kb(void) {
// is safe to just read DPI setting since matrix init
// comes before pointing device init.
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
matrix_init_user();
}
void keyboard_post_init_kb(void) {
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
keyboard_post_init_user();
}

View File

@ -33,5 +33,10 @@
#define POINTING_DEVICE_ROTATION_270 #define POINTING_DEVICE_ROTATION_270
#define ENCODER_BUTTON_COL 1
#define ENCODER_BUTTON_ROW 0
/* Custom encoder needs to specify just how many encoders we have */ /* Custom encoder needs to specify just how many encoders we have */
#define NUM_ENCODERS 1 #define NUM_ENCODERS 1
#define ENCODERS_PAD_A { F0 }
#define ENCODERS_PAD_B { F4 }

View File

@ -12,11 +12,16 @@
"bootmagic": { "bootmagic": {
"matrix": [0, 3] "matrix": [0, 3]
}, },
"processor": "atmega32u4",
"bootloader": "atmel-dfu",
"features": { "features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": false,
"pointing_device": true,
"encoder": true "encoder": true
}, },
"processor": "atmega32u4",
"bootloader": "atmel-dfu",
"encoder": { "encoder": {
"driver": "custom" "driver": "custom"
}, },

View File

@ -1,66 +0,0 @@
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2020 Ploopy Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
// used for tracking the state
bool is_drag_scroll = false;
enum custom_keycodes {
DRAG_SCROLL = SAFE_RANGE,
};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case DRAG_SCROLL:
if (record->event.pressed) {
// this toggles the state each time you tap it
is_drag_scroll ^= 1;
}
break;
}
return true;
}
// The real magic is here.
// This function is called to translate the processed sensor movement
// from the mouse sensor and translates it into x and y movement for
// the mouse report. Normally. So if "drag scroll" is toggled on,
// moving the ball scrolls instead. You could remove the x or y here
// to only scroll in one direction, if you wanted, as well. In fact,
// there is no reason that you need to send this to the mouse report.
// You could have it register a key, instead.
void process_mouse_user(report_mouse_t* mouse_report, int8_t x, int8_t y) {
if (is_drag_scroll) {
mouse_report->h = x;
mouse_report->v = y;
} else {
mouse_report->x = x;
mouse_report->y = y;
}
}
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT( /* Base */
KC_BTN1, KC_BTN3, KC_BTN2,
KC_BTN4, LT(1, KC_BTN5)
),
[1] = LAYOUT(
DRAG_SCROLL, _______, _______,
_______, _______
)
};

View File

@ -1,5 +0,0 @@
# The Drag Scroll keymap for the Ploopy Trackball Mini
This is a sample keymap showing off what you can do with the custom callback drivers.
This particular example enables "drag scrolling". The movement of the ball is used to scroll up and down.

View File

@ -29,52 +29,6 @@ Occasionally, new revisions of the PCB will be released. Every board comes with
Match the firmware that you flash onto the board with the designator on the board. Match the firmware that you flash onto the board with the designator on the board.
# Customizing your Ploopy Mini Trackball
While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change, such as adding DPI control, or using the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse sensor.
The default behavior for this is:
```c
void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) {
mouse_report->h = h;
mouse_report->v = v;
}
void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) {
mouse_report->x = x;
mouse_report->y = y;
}
```
This should allow you to more heavily customize the behavior.
Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
Additionally, you can change the DPI/CPI or speed of the trackball by calling `adns_set_cpi` at any time. Additionally, there is a `DPI_CONFIG` macro that will cycle through an array of options for the DPI. This is set to 375, 750, and 1375, but can be changed. 1375 is the default.
To configure/set your own array, there are two defines to use, `PLOOPY_DPI_OPTIONS` to set the array, and `PLOOPY_DPI_DEFAULT`.
```c
#define PLOOPY_DPI_OPTIONS { 375, 750, 1375}
#define PLOOPY_DPI_DEFAULT 2
```
The `PLOOPY_DPI_OPTIONS` array sets the values that you want to be able to cycle through, and the order they are in. The "default" define lets the firmware know which of these options is the default and should be loaded by default.
The `DPI_CONFIG` macro will cycle through the values in the array, each time you hit it. It stores this value in persistent memory, so it will load it the next time the device powers up.
## Drag Scroll
Drag Sroll is a custom keycode for the Ploopy devices that allow you to hold or tap a button and have the mouse movement translate into scrolling instead.
Nothing needs to be enabled to use this functionality. Just add the `DRAG_SCROLL` to your keymap.
### Drag Scroll Configuration
* `#define PLOOPY_DRAGSCROLL_MOMENTARY` - Makes the key into a momentary key, rather than a toggle.
* `#define PLOOPY_DRAGSCROLL_DPI 375` - When the fixed DPI option is enabled, this sets the DPI to be used for Drag Scroll.
* `#define PLOOPY_DRAGSCROLL_INVERT` - This reverses the direction that the scroll is performed.
## Fuse settings ## Fuse settings
When flashing the bootloader, use the following fuse settings: When flashing the bootloader, use the following fuse settings:
@ -84,3 +38,7 @@ When flashing the bootloader, use the following fuse settings:
| Low | `0x5E` | | Low | `0x5E` |
| High | `0x99` | | High | `0x99` |
| Extended | `0xC3` | | Extended | `0xC3` |
# Customizing your Ploopy Mini Trackball
You can find customziation options [here](../readme.md).

View File

@ -1,20 +1,3 @@
# Build Options
# change yes to no to disable
#
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = yes # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
AUDIO_ENABLE = no # Audio output
POINTING_DEVICE_ENABLE = yes
POINTING_DEVICE_DRIVER = adns5050 POINTING_DEVICE_DRIVER = adns5050
MOUSEKEY_ENABLE = yes # Mouse keys
ANALOG_DRIVER_REQUIRED = yes
SRC += opt_encoder.c
DEFAULT_FOLDER = ploopyco/trackball_mini/rev1_001 DEFAULT_FOLDER = ploopyco/trackball_mini/rev1_001

View File

@ -1,214 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2019 Hiroyuki Okada
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trackball_mini.h"
#include "wait.h"
#include "debug.h"
#ifndef OPT_DEBOUNCE
# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
#endif
#ifndef SCROLL_BUTT_DEBOUNCE
# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
#endif
#ifndef OPT_THRES
# define OPT_THRES 150 // (0-1024) Threshold for actication
#endif
#ifndef OPT_SCALE
# define OPT_SCALE 1 // Multiplier for wheel
#endif
#ifndef PLOOPY_DPI_OPTIONS
# define PLOOPY_DPI_OPTIONS \
{ 375, 750, 1375 }
# ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 1
# endif
#endif
#ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 0
#endif
#ifndef PLOOPY_DRAGSCROLL_DPI
# define PLOOPY_DRAGSCROLL_DPI 375 // Fixed-DPI Drag Scroll
#endif
#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER
# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll
#endif
keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array)
// TODO: Implement libinput profiles
// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
// Compile time accel selection
// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
// Trackball State
bool is_scroll_clicked = false;
bool BurstState = false; // init burst state for Trackball module
uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
uint16_t lastScroll = 0; // Previous confirmed wheel event
uint16_t lastMidClick = 0; // Stops scrollwheel from being read if it was pressed
uint8_t OptLowPin = OPT_ENC1;
bool debug_encoder = false;
bool is_drag_scroll = false;
bool encoder_update_kb(uint8_t index, bool clockwise) {
if (!encoder_update_user(index, clockwise)) {
return false;
}
#ifdef MOUSEKEY_ENABLE
tap_code(clockwise ? KC_WH_U : KC_WH_D);
#else
report_mouse_t mouse_report = pointing_device_get_report();
mouse_report.v = clockwise ? 1 : -1;
pointing_device_set_report(mouse_report);
pointing_device_send();
#endif
return true;
}
void encoder_driver_init(void) {
setPinInput(OPT_ENC1);
setPinInput(OPT_ENC2);
opt_encoder_init();
}
void encoder_driver_task(void) {
uint16_t p1 = adc_read(OPT_ENC1_MUX);
uint16_t p2 = adc_read(OPT_ENC2_MUX);
if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
int8_t dir = opt_encoder_handler(p1, p2);
// If the mouse wheel was just released, do not scroll.
if (timer_elapsed(lastMidClick) < SCROLL_BUTT_DEBOUNCE) return;
// Limit the number of scrolls per unit time.
if (timer_elapsed(lastScroll) < OPT_DEBOUNCE) return;
// Don't scroll if the middle button is depressed.
if (is_scroll_clicked) {
#ifndef IGNORE_SCROLL_CLICK
return;
#endif
}
if (dir == 0) return;
encoder_queue_event(0, dir == 1);
lastScroll = timer_read();
}
void pointing_device_init_kb(void) {
// set the DPI.
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
if (is_drag_scroll) {
mouse_report.h = mouse_report.x;
#ifdef PLOOPY_DRAGSCROLL_INVERT
// Invert vertical scroll direction
mouse_report.v = -mouse_report.y;
#else
mouse_report.v = mouse_report.y;
#endif
mouse_report.x = 0;
mouse_report.y = 0;
}
return pointing_device_task_user(mouse_report);
}
bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
xprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
// Update Timer to prevent accidental scrolls
if ((record->event.key.col == 1) && (record->event.key.row == 0)) {
lastMidClick = timer_read();
is_scroll_clicked = record->event.pressed;
}
if (!process_record_user(keycode, record)) return false;
if (keycode == DPI_CONFIG && record->event.pressed) {
keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
eeconfig_update_kb(keyboard_config.raw);
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
if (keycode == DRAG_SCROLL) {
#ifndef PLOOPY_DRAGSCROLL_MOMENTARY
if (record->event.pressed)
#endif
{
is_drag_scroll ^= 1;
}
pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
}
return true;
}
// Hardware Setup
void keyboard_pre_init_kb(void) {
// debug_enable = true;
// debug_matrix = true;
// debug_mouse = true;
// debug_encoder = true;
/* Ground all output pins connected to ground. This provides additional
* pathways to ground. If you're messing with this, know this: driving ANY
* of these pins high will cause a short. On the MCU. Ka-blooey.
*/
#ifdef UNUSABLE_PINS
const pin_t unused_pins[] = UNUSABLE_PINS;
for (uint8_t i = 0; i < ARRAY_SIZE(unused_pins); i++) {
setPinOutput(unused_pins[i]);
writePinLow(unused_pins[i]);
}
#endif
keyboard_pre_init_user();
}
void eeconfig_init_kb(void) {
keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}
void matrix_init_kb(void) {
// is safe to just read DPI setting since matrix init
// comes before pointing device init.
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
matrix_init_user();
}

View File

@ -1,49 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2019 Hiroyuki Okada
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "analog.h"
#include "opt_encoder.h"
// Sensor defs
#define OPT_ENC1 F0
#define OPT_ENC2 F4
#define OPT_ENC1_MUX 0
#define OPT_ENC2_MUX 4
void process_wheel(void);
typedef union {
uint32_t raw;
struct {
uint8_t dpi_config;
};
} keyboard_config_t;
extern keyboard_config_t keyboard_config;
enum ploopy_keycodes {
DPI_CONFIG = QK_KB_0,
DRAG_SCROLL,
};
bool encoder_update_user(uint8_t index, bool clockwise);
bool encoder_update_kb(uint8_t index, bool clockwise);

View File

@ -9,6 +9,9 @@
"device_version": "0.0.1", "device_version": "0.0.1",
"max_power": 100 "max_power": 100
}, },
"features": {
"pointing_device": true
},
"processor": "atmega32u4", "processor": "atmega32u4",
"bootloader": "atmel-dfu", "bootloader": "atmel-dfu",
"debounce": 0, "debounce": 0,

View File

@ -1,167 +0,0 @@
/* Copyright 2022 Aidan Gauland
* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2019 Hiroyuki Okada
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
#include "print.h"
#define NUM_LOCK_BITMASK 0b01
#define CAPS_LOCK_BITMASK 0b10
// World record for fastest index finger tapping is 1092 taps per minute, which
// is 55ms for a single tap.
// https://recordsetter.com/world-record/index-finger-taps-minute/46066
#define LED_CMD_TIMEOUT 25
#define DELTA_X_THRESHOLD 60
#define DELTA_Y_THRESHOLD 15
typedef enum {
// You could theoretically define 0b00 and send it by having a macro send
// the second tap after LED_CMD_TIMEOUT has elapsed.
// CMD_EXTRA = 0b00,
TG_SCROLL = 0b01,
CYC_DPI = 0b10,
CMD_RESET = 0b11 // CMD_ prefix to avoid clash with QMK macro
} led_cmd_t;
// State
static bool scroll_enabled = false;
static bool num_lock_state = false;
static bool caps_lock_state = false;
static bool in_cmd_window = false;
static int8_t delta_x = 0;
static int8_t delta_y = 0;
typedef struct {
led_cmd_t led_cmd;
uint8_t num_lock_count;
uint8_t caps_lock_count;
} cmd_window_state_t;
// Dummy
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {{{KC_NO}}};
report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
if (scroll_enabled) {
delta_x += mouse_report.x;
delta_y += mouse_report.y;
if (delta_x > DELTA_X_THRESHOLD) {
mouse_report.h = 1;
delta_x = 0;
} else if (delta_x < -DELTA_X_THRESHOLD) {
mouse_report.h = -1;
delta_x = 0;
}
if (delta_y > DELTA_Y_THRESHOLD) {
mouse_report.v = -1;
delta_y = 0;
} else if (delta_y < -DELTA_Y_THRESHOLD) {
mouse_report.v = 1;
delta_y = 0;
}
mouse_report.x = 0;
mouse_report.y = 0;
}
return mouse_report;
}
void keyboard_post_init_user(void) {
num_lock_state = host_keyboard_led_state().num_lock;
caps_lock_state = host_keyboard_led_state().caps_lock;
}
uint32_t command_timeout(uint32_t trigger_time, void *cb_arg) {
cmd_window_state_t *cmd_window_state = (cmd_window_state_t *)cb_arg;
# ifdef CONSOLE_ENABLE
uprintf("Received command 0b%02b (", cmd_window_state->led_cmd);
# endif
switch (cmd_window_state->led_cmd) {
case TG_SCROLL:
# ifdef CONSOLE_ENABLE
uprint("TG_SCROLL)\n");
# endif
scroll_enabled = !scroll_enabled;
break;
case CYC_DPI:
# ifdef CONSOLE_ENABLE
uprint("CYC_DPI)\n");
# endif
cycle_dpi();
break;
case CMD_RESET:
# ifdef CONSOLE_ENABLE
uprint("QK_BOOT)\n");
# endif
reset_keyboard();
break;
default:
# ifdef CONSOLE_ENABLE
uprint("unknown)\n");
# endif
// Ignore unrecognised commands.
break;
}
cmd_window_state->led_cmd = 0;
cmd_window_state->num_lock_count = 0;
cmd_window_state->caps_lock_count = 0;
in_cmd_window = false;
return 0; // Don't repeat
}
bool led_update_user(led_t led_state) {
static cmd_window_state_t cmd_window_state = {
.led_cmd = 0b00,
.num_lock_count = 0,
.caps_lock_count = 0
};
// Start timer to end command window if we are not already in the middle of
// one.
if (!in_cmd_window) {
in_cmd_window = true;
defer_exec(LED_CMD_TIMEOUT, command_timeout, &cmd_window_state);
}
// Set num lock and caps lock bits when each is toggled on and off within
// the window.
if (led_state.num_lock != num_lock_state) {
cmd_window_state.num_lock_count++;
if (cmd_window_state.num_lock_count == 2) {
cmd_window_state.led_cmd |= NUM_LOCK_BITMASK;
cmd_window_state.num_lock_count = 0;
}
}
if (led_state.caps_lock != caps_lock_state) {
cmd_window_state.caps_lock_count++;
if (cmd_window_state.caps_lock_count == 2) {
cmd_window_state.led_cmd |= CAPS_LOCK_BITMASK;
cmd_window_state.caps_lock_count = 0;
}
}
// Keep our copy of the LED states in sync with the host.
num_lock_state = led_state.num_lock;
caps_lock_state = led_state.caps_lock;
return true;
}

View File

@ -1,2 +0,0 @@
# The keymap that takes commands as LED-Key BitMasks (lkbm)
Based on [maddie](../maddie), this keymap lets you send a 2-bit command by having a macro on your keyboard tap `KC_NUM_LOCK` and `KC_CAPS_LOCK` on and off within a very short window (25ms by default) to represent bits 1 and 2 respectively. The keymap uses this to allow toggling between sending mouse-movement events and scrolling events; cycling DPI presets, and resetting to the bootloader, so you can reflash without having to unscrew your Ploopy Nano.

View File

@ -1 +0,0 @@
DEFERRED_EXEC_ENABLE = yes

View File

@ -28,21 +28,6 @@ Occasionally, new revisions of the PCB will be released. Every board comes with
Match the firmware that you flash onto the board with the designator on the board. Match the firmware that you flash onto the board with the designator on the board.
# Customizing your Ploopy Nano Trackball
You can change the DPI/CPI or speed of the trackball by calling `adns_set_cpi` at any time. Additionally, there is a `DPI_CONFIG` macro that will cycle through an array of options for the DPI. This is set to 375, 750, and 1375, but can be changed. 750 is the default.
To configure/set your own array, there are two defines to use, `PLOOPY_DPI_OPTIONS` to set the array, and `PLOOPY_DPI_DEFAULT`.
```c
#define PLOOPY_DPI_OPTIONS { 375, 750, 1375}
#define PLOOPY_DPI_DEFAULT 1
```
The `PLOOPY_DPI_OPTIONS` array sets the values that you want to be able to cycle through, and the order they are in. The "default" define lets the firmware know which of these options is the default and should be loaded by default.
The `DPI_CONFIG` macro will cycle through the values in the array, each time you hit it. It stores this value in persistent memory, so it will load it the next time the device powers up.
## Fuse settings ## Fuse settings
When flashing the bootloader, use the following fuse settings: When flashing the bootloader, use the following fuse settings:
@ -52,3 +37,7 @@ When flashing the bootloader, use the following fuse settings:
| Low | `0x5E` | | Low | `0x5E` |
| High | `0x99` | | High | `0x99` |
| Extended | `0xC3` | | Extended | `0xC3` |
# Customizing your PloopyCo Trackball Nano
You can find customziation options [here](../readme.md).

View File

@ -1,16 +1,3 @@
# Build Options
# change yes to no to disable
#
BOOTMAGIC_ENABLE = no # Enable Bootmagic Lite
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = yes # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
AUDIO_ENABLE = no # Audio output
POINTING_DEVICE_ENABLE = yes
POINTING_DEVICE_DRIVER = adns5050 POINTING_DEVICE_DRIVER = adns5050
MOUSEKEY_ENABLE = no # Mouse keys
DEFAULT_FOLDER = ploopyco/trackball_nano/rev1_001 DEFAULT_FOLDER = ploopyco/trackball_nano/rev1_001

View File

@ -1,115 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2019 Hiroyuki Okada
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trackball_nano.h"
#include "wait.h"
#ifndef OPT_DEBOUNCE
# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
#endif
#ifndef SCROLL_BUTT_DEBOUNCE
# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
#endif
#ifndef OPT_THRES
# define OPT_THRES 150 // (0-1024) Threshold for actication
#endif
#ifndef OPT_SCALE
# define OPT_SCALE 1 // Multiplier for wheel
#endif
#ifndef PLOOPY_DPI_OPTIONS
# define PLOOPY_DPI_OPTIONS \
{ 375, 750, 1375 }
# ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 2
# endif
#endif
#ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 2
#endif
keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array)
void cycle_dpi(void) {
keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
#ifdef CONSOLE_ENABLE
uprintf("DPI is now %d\n", dpi_array[keyboard_config.dpi_config]);
#endif
}
// TODO: Implement libinput profiles
// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
// Compile time accel selection
// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
// Trackball State
bool is_scroll_clicked = false;
bool BurstState = false; // init burst state for Trackball module
uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
void pointing_device_init_kb(void) {
// set the DPI.
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
// Hardware Setup
void keyboard_pre_init_kb(void) {
// debug_enable = true;
// debug_matrix = true;
// debug_mouse = true;
// debug_encoder = true;
/* Ground all output pins connected to ground. This provides additional
* pathways to ground. If you're messing with this, know this: driving ANY
* of these pins high will cause a short. On the MCU. Ka-blooey.
*/
#ifdef UNUSABLE_PINS
const pin_t unused_pins[] = UNUSABLE_PINS;
for (uint8_t i = 0; i < ARRAY_SIZE(unused_pins); i++) {
setPinOutput(unused_pins[i]);
writePinLow(unused_pins[i]);
}
#endif
keyboard_pre_init_user();
}
void eeconfig_init_kb(void) {
keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}
void matrix_init_kb(void) {
// is safe to just read DPI setting since matrix init
// comes before pointing device init.
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
matrix_init_user();
}

View File

@ -1,37 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
* Copyright 2019 Hiroyuki Okada
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
typedef union {
uint32_t raw;
struct {
uint8_t dpi_config;
};
} keyboard_config_t;
extern keyboard_config_t keyboard_config;
enum ploopy_keycodes {
DPI_CONFIG = QK_KB_0,
};
void cycle_dpi(void);

View File

@ -19,9 +19,9 @@
#pragma once #pragma once
/* disable action features */ /* disable action features */
//#define NO_ACTION_LAYER // #define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING // #define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT // #define NO_ACTION_ONESHOT
// #define ROTATIONAL_TRANSFORM_ANGLE 0 // #define ROTATIONAL_TRANSFORM_ANGLE 0
#define POINTING_DEVICE_INVERT_Y #define POINTING_DEVICE_INVERT_Y
@ -32,5 +32,15 @@
/* PMW3360 Settings */ /* PMW3360 Settings */
#define POINTING_DEVICE_CS_PIN B0 #define POINTING_DEVICE_CS_PIN B0
#define ENCODER_BUTTON_COL 1
#define ENCODER_BUTTON_ROW 0
#define ENCODER_LOW_THRES_A 20
#define ENCODER_HIGH_THRES_A 75
#define ENCODER_LOW_THRES_B 20
#define ENCODER_HIGH_THRES_B 90
/* Custom encoder needs to specify just how many encoders we have */ /* Custom encoder needs to specify just how many encoders we have */
#define NUM_ENCODERS 1 #define NUM_ENCODERS 1
#define ENCODERS_PAD_A { F4 }
#define ENCODERS_PAD_B { F0 }

View File

@ -1,30 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT( /* Base */
KC_BTN4, KC_BTN1, KC_BTN3, KC_BTN2, KC_BTN5,
MO(1)
),
[1] = LAYOUT(
_______, _______, _______, _______, _______,
DRAG_SCROLL
)
};

View File

@ -1,3 +0,0 @@
# The Drag Scroll keymap for Ploopyco Thumb Trackball
This is a sample keymap showing off what you can do with the custom callback drivers.

View File

@ -1 +1,2 @@
VIA_ENABLE = yes VIA_ENABLE = yes
LTO_ENABLE = yes

View File

@ -16,43 +16,4 @@ See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_to
# Customizing your PloopyCo Thumb # Customizing your PloopyCo Thumb
While the defaults are designed so that it can be plugged in and used right away, there are a number of things that you may want to change. Such as adding DPI control, or to use the ball to scroll while holding a button. To allow for this sort of control, there is a callback for both the scroll wheel and the mouse sensor. You can find customziation options [here](../readme.md).
The default behavior for this is:
```c
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
return mouse_report;
}
```
This should allow you to more heavily customize the behavior.
Alternatively, the `process_wheel` and `process_mouse` functions can both be replaced too, to allow for even more functionality.
Additionally, you can change the DPI/CPI or speed of the trackball by calling `pmw_set_cpi` at any time. Additionally, there is a `DPI_CONFIG` keycode that will cycle through an array of options for the DPI. This is set to 1200, 1600, and 2400, but can be changed. 1600 is also set to the default.
To configure/set your own array, there are two defines to use, `PLOOPY_DPI_OPTIONS` to set the array, and `PLOOPY_DPI_DEFAULT`, which is the `0`-based index into the `PLOOPY_DPI_OPTIONS` array.
```c
#define PLOOPY_DPI_OPTIONS { 1200, 1600, 2400 }
#define PLOOPY_DPI_DEFAULT 1
```
The `PLOOPY_DPI_OPTIONS` array sets the values that you want to be able to cycle through, and the order they are in. The "default" define lets the firmware know which of these options is the default and should be loaded by default.
When inserted into your keymap, the `DPI_CONFIG` keycode will cycle through the values in the array each time you hit it. It stores this value in persistent memory, so it will remember your selection the next time the device powers up.
## Drag Scroll
Drag Scroll is a custom keycode for the Ploopy devices that allow you to hold or tap a button and have the mouse movement translate into scrolling instead.
Nothing needs to be enabled to use this functionality. Just add the `DRAG_SCROLL` to your keymap.
### Drag Scroll Configuration
* `#define PLOOPY_DRAGSCROLL_MOMENTARY` - Makes the key into a momentary key, rather than a toggle.
* `#define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75` - Sets the DPI multiplier to use when drag scroll is enabled.
* `#define PLOOPY_DRAGSCROLL_FIXED` - Normally, when activating Drag Scroll, it uses a fraction of the current DPI. You can define this to use a specific, set DPI rather than a fraction of the current DPI.
* `#define PLOOPY_DRAGSCROLL_DPI 100` - When the fixed DPI option is enabled, this sets the DPI to be used for Drag Scroll.
* `#define PLOOPY_DRAGSCROLL_INVERT` - This reverses the direction that the scroll is performed.

View File

@ -3,8 +3,4 @@ F_CPU = 8000000
POINTING_DEVICE_DRIVER = pmw3360 POINTING_DEVICE_DRIVER = pmw3360
ANALOG_DRIVER_REQUIRED = yes
SRC += opt_encoder.c
DEFAULT_FOLDER = ploopyco/trackball_thumb/rev1_001 DEFAULT_FOLDER = ploopyco/trackball_thumb/rev1_001

View File

@ -1,225 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trackball_thumb.h"
#include "encoder.h"
#ifndef OPT_DEBOUNCE
# define OPT_DEBOUNCE 5 // (ms) Time between scroll events
#endif
#ifndef SCROLL_BUTT_DEBOUNCE
# define SCROLL_BUTT_DEBOUNCE 100 // (ms) Time between scroll events
#endif
#ifndef PLOOPY_DPI_OPTIONS
# define PLOOPY_DPI_OPTIONS \
{ 600, 900, 1200, 1600 }
# ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 1
# endif
#endif
#ifndef PLOOPY_DPI_DEFAULT
# define PLOOPY_DPI_DEFAULT 0
#endif
#ifndef PLOOPY_DRAGSCROLL_DPI
# define PLOOPY_DRAGSCROLL_DPI 100 // Fixed-DPI Drag Scroll
#endif
#ifndef PLOOPY_DRAGSCROLL_MULTIPLIER
# define PLOOPY_DRAGSCROLL_MULTIPLIER 0.75 // Variable-DPI Drag Scroll
#endif
keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
// TODO: Implement libinput profiles
// https://wayland.freedesktop.org/libinput/doc/latest/pointer-acceleration.html
// Compile time accel selection
// Valid options are ACC_NONE, ACC_LINEAR, ACC_CUSTOM, ACC_QUADRATIC
// Trackball State
bool is_scroll_clicked = false;
uint16_t last_scroll = 0; // Previous confirmed wheel event
uint16_t last_mid_click = 0; // Stops scrollwheel from being read if it was pressed;
bool debug_encoder = false;
bool is_drag_scroll = false;
bool encoder_update_kb(uint8_t index, bool clockwise) {
if (!encoder_update_user(index, clockwise)) {
return false;
}
#ifdef MOUSEKEY_ENABLE
tap_code(clockwise ? KC_WH_U : KC_WH_D);
#else
report_mouse_t mouse_report = pointing_device_get_report();
mouse_report.v = clockwise ? 1 : -1;
pointing_device_set_report(mouse_report);
pointing_device_send();
#endif
return true;
}
void encoder_driver_init(void) { opt_encoder_init(); }
void encoder_driver_task(void) {
// Lovingly ripped from the Ploopy Source
// If the mouse wheel was just released, do not scroll.
if (timer_elapsed(last_mid_click) < SCROLL_BUTT_DEBOUNCE) {
return;
}
// Limit the number of scrolls per unit time.
if (timer_elapsed(last_scroll) < OPT_DEBOUNCE) {
return;
}
// Don't scroll if the middle button is depressed.
if (is_scroll_clicked) {
#ifndef IGNORE_SCROLL_CLICK
return;
#endif
}
last_scroll = timer_read();
uint16_t p1 = adc_read(OPT_ENC1_MUX);
uint16_t p2 = adc_read(OPT_ENC2_MUX);
if (debug_encoder) dprintf("OPT1: %d, OPT2: %d\n", p1, p2);
int dir = opt_encoder_handler(p1, p2);
if (dir == 0) return;
encoder_queue_event(0, dir == 1);
}
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
if (is_drag_scroll) {
mouse_report.h = mouse_report.x;
#ifdef PLOOPY_DRAGSCROLL_INVERT
// Invert vertical scroll direction
mouse_report.v = -mouse_report.y;
#else
mouse_report.v = mouse_report.y;
#endif
mouse_report.x = 0;
mouse_report.y = 0;
}
return pointing_device_task_user(mouse_report);
}
bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
// Update Timer to prevent accidental scrolls
if ((record->event.key.col == 1) && (record->event.key.row == 0)) {
last_mid_click = timer_read();
is_scroll_clicked = record->event.pressed;
}
if (!process_record_user(keycode, record)) {
return false;
}
if (keycode == DPI_CONFIG && record->event.pressed) {
keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
eeconfig_update_kb(keyboard_config.raw);
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
}
if (keycode == DRAG_SCROLL) {
#ifndef PLOOPY_DRAGSCROLL_MOMENTARY
if (record->event.pressed)
#endif
{
is_drag_scroll ^= 1;
}
#ifdef PLOOPY_DRAGSCROLL_FIXED
pointing_device_set_cpi(is_drag_scroll ? PLOOPY_DRAGSCROLL_DPI : dpi_array[keyboard_config.dpi_config]);
#else
pointing_device_set_cpi(is_drag_scroll ? (dpi_array[keyboard_config.dpi_config] * PLOOPY_DRAGSCROLL_MULTIPLIER) : dpi_array[keyboard_config.dpi_config]);
#endif
}
/* If Mousekeys is disabled, then use handle the mouse button
* keycodes. This makes things simpler, and allows usage of
* the keycodes in a consistent manner. But only do this if
* Mousekeys is not enable, so it's not handled twice.
*/
#ifndef MOUSEKEY_ENABLE
if (IS_MOUSEKEY_BUTTON(keycode)) {
report_mouse_t currentReport = pointing_device_get_report();
if (record->event.pressed) {
currentReport.buttons |= 1 << (keycode - KC_MS_BTN1);
} else {
currentReport.buttons &= ~(1 << (keycode - KC_MS_BTN1));
}
pointing_device_set_report(currentReport);
pointing_device_send();
}
#endif
return true;
}
// Hardware Setup
void keyboard_pre_init_kb(void) {
// debug_enable = true;
// debug_matrix = true;
// debug_mouse = true;
// debug_encoder = true;
setPinInput(OPT_ENC1);
setPinInput(OPT_ENC2);
/* Ground all output pins connected to ground. This provides additional
* pathways to ground. If you're messing with this, know this: driving ANY
* of these pins high will cause a short. On the MCU. Ka-blooey.
*/
#ifdef UNUSABLE_PINS
const pin_t unused_pins[] = UNUSABLE_PINS;
for (uint8_t i = 0; i < (sizeof(unused_pins) / sizeof(pin_t)); i++) {
setPinOutput(unused_pins[i]);
writePinLow(unused_pins[i]);
}
#endif
// This is the debug LED.
#if defined(DEBUG_LED_PIN)
setPinOutput(DEBUG_LED_PIN);
writePin(DEBUG_LED_PIN, debug_enable);
#endif
keyboard_pre_init_user();
}
void pointing_device_init_kb(void) { pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); }
void eeconfig_init_kb(void) {
keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
eeconfig_update_kb(keyboard_config.raw);
eeconfig_init_user();
}
void matrix_init_kb(void) {
// is safe to just read DPI setting since matrix init
// comes before pointing device init.
keyboard_config.raw = eeconfig_read_kb();
if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
eeconfig_init_kb();
}
matrix_init_user();
}

View File

@ -1,45 +0,0 @@
/* Copyright 2021 Colin Lam (Ploopy Corporation)
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
* Copyright 2019 Sunjun Kim
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "quantum.h"
#include "analog.h"
#include "opt_encoder.h"
// Sensor defs
#define OPT_ENC1 F4
#define OPT_ENC2 F0
#define OPT_ENC1_MUX 4
#define OPT_ENC2_MUX 0
typedef union {
uint32_t raw;
struct {
uint8_t dpi_config;
};
} keyboard_config_t;
_Static_assert(sizeof(keyboard_config_t) == sizeof(uint32_t), "keyboard_config_t size mismatch compared to EEPROM area");
extern keyboard_config_t keyboard_config;
extern uint16_t dpi_array[];
enum ploopy_keycodes {
DPI_CONFIG = QK_KB_0,
DRAG_SCROLL,
};