forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Keyboard] Add PloopyCo devices (qmk#7935)
* Initial Commit for Ploopyco Trackball This is a WIP at this point. Most of it compiles, but the SPI commands are non-functioning as they come from Arduino, so don't exist in LUFA * Convert SPI commands from arduino to LUFA But I have no idea if this is actually correct or not * Update keyboard readme * Clean up ploopyco trackball * Update readme * Update mouse key stuff * last minutue cleanup * Add caveat about scroll wheel * Fixup to code * Additional fixup * Add movement multiplier * Rename folders * mid changes * temp * Got it working!!!!! * Additional cleanup of code * Make unused pin calls more compact * Rotation info * Add debouncing checks * Make everything replaceable * Add info.json * Include ISP flashing info * Better handling for user customization * Reconfigure CPI stuff * fix issues with debug printing * Fix tiny scroll issue * Add and update scroll code from ploopy mouse * Update licensing * Add PloopyCo Mouse * Cleanup and layout stuff * Move common files to main folder for reuse * Increase polling rate * Update image for mouse * Apply changes from code review * Add VIA support
- Loading branch information
Showing
25 changed files
with
1,938 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* 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 "config_common.h" | ||
|
||
/* USB Device descriptor parameter */ | ||
#define VENDOR_ID 0x5043 | ||
#define PRODUCT_ID 0x4D6F | ||
#define DEVICE_VER 0x0001 | ||
#define MANUFACTURER Ploopyco | ||
#define PRODUCT Mouse | ||
|
||
/* key matrix size */ | ||
#define MATRIX_ROWS 1 | ||
#define MATRIX_COLS 8 | ||
|
||
/* | ||
* Keyboard Matrix Assignments | ||
* | ||
* Change this to how you wired your keyboard | ||
* COLS: AVR pins used for columns, left to right | ||
* ROWS: AVR pins used for rows, top to bottom | ||
* DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode) | ||
* ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode) | ||
* | ||
*/ | ||
#define DIRECT_PINS \ | ||
{ \ | ||
{ D4, D2, E6, B6, D7, C6, C7, B7 } \ | ||
} | ||
|
||
// These pins are not broken out, and cannot be used normally. | ||
// They are set as output and pulled high, by default | ||
#define UNUSED_PINS \ | ||
{ B4, D6, F1, F5, F6, F7 } | ||
|
||
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */ | ||
#define DEBOUNCE 5 | ||
|
||
/* Much more so than a keyboard, speed matters for a mouse. So we'll go for as high | ||
a polling rate as possible. */ | ||
#define USB_POLLING_INTERVAL_MS 1 | ||
|
||
/* define if matrix has ghost (lacks anti-ghosting diodes) */ | ||
//#define MATRIX_HAS_GHOST | ||
|
||
/* disable action features */ | ||
//#define NO_ACTION_LAYER | ||
//#define NO_ACTION_TAPPING | ||
//#define NO_ACTION_ONESHOT | ||
#define NO_ACTION_MACRO | ||
#define NO_ACTION_FUNCTION | ||
|
||
/* Bootmagic Lite key configuration */ | ||
#define BOOTMAGIC_LITE_ROW 0 | ||
#define BOOTMAGIC_LITE_COLUMN 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"keyboard_name": "PloopyCo Mouse", | ||
"url": "", | ||
"maintainer": "drashna", | ||
"width": 8, | ||
"height": 3, | ||
"layouts": { | ||
"LAYOUT": { | ||
"layout": [ | ||
{"x":1, "y":0, "h":2}, | ||
{"x":2, "y":0, "h":2}, | ||
{"x":3, "y":0.25, "h":1.25}, | ||
{"x":4, "y":0, "h":2}, | ||
{"x":5, "y":0, "h":2}, | ||
{"x":0, "y":0}, | ||
{"x":0, "y":1}, | ||
{"x":3, "y":1.5} | ||
] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
/* 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, KC_BTN2, C(KC_C), KC_BTN4, KC_BTN5, C(KC_Z)), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# The default keymap for Ploopyco Trackball |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* 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, KC_BTN2, C(KC_C), KC_BTN4, KC_BTN5, C(KC_Z)), | ||
[1] = LAYOUT(_______, _______, _______, _______, _______, _______, _______, _______), | ||
[2] = LAYOUT(_______, _______, _______, _______, _______, _______, _______, _______), | ||
[3] = LAYOUT(_______, _______, _______, _______, _______, _______, _______, _______), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
VIA_ENABLE = yes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
/* 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 | ||
|
||
#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 | ||
|
||
// 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; | ||
|
||
__attribute__((weak)) void process_wheel_user(report_mouse_t* mouse_report, int16_t h, int16_t v) { | ||
mouse_report->h = h; | ||
mouse_report->v = v; | ||
} | ||
|
||
__attribute__((weak)) void process_wheel(report_mouse_t* mouse_report) { | ||
// 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); | ||
|
||
uint8_t dir = opt_encoder_handler(p1, p2); | ||
|
||
if (dir == 0) return; | ||
process_wheel_user(mouse_report, mouse_report->h, (int)(mouse_report->v + (dir * OPT_SCALE))); | ||
} | ||
|
||
__attribute__((weak)) void process_mouse_user(report_mouse_t* mouse_report, int16_t x, int16_t y) { | ||
mouse_report->x = x; | ||
mouse_report->y = y; | ||
} | ||
|
||
__attribute__((weak)) void process_mouse(report_mouse_t* mouse_report) { | ||
report_pmw_t data = pmw_read_burst(); | ||
if (data.isOnSurface && data.isMotion) { | ||
// Reset timer if stopped moving | ||
if (!data.isMotion) { | ||
if (MotionStart != 0) MotionStart = 0; | ||
return; | ||
} | ||
|
||
// Set timer if new motion | ||
if ((MotionStart == 0) && data.isMotion) { | ||
if (debug_mouse) dprintf("Starting motion.\n"); | ||
MotionStart = timer_read(); | ||
} | ||
|
||
if (debug_mouse) { | ||
dprintf("Delt] d: %d t: %u\n", abs(data.dx) + abs(data.dy), MotionStart); | ||
} | ||
if (debug_mouse) { | ||
dprintf("Pre ] X: %d, Y: %d\n", data.dx, data.dy); | ||
} | ||
#if defined(PROFILE_LINEAR) | ||
float scale = float(timer_elaspsed(MotionStart)) / 1000.0; | ||
data.dx *= scale; | ||
data.dy *= scale; | ||
#elif defined(PROFILE_INVERSE) | ||
// TODO | ||
#else | ||
// no post processing | ||
#endif | ||
// apply multiplier | ||
// data.dx *= mouse_multiplier; | ||
// data.dy *= mouse_multiplier; | ||
|
||
// Wrap to HID size | ||
data.dx = constrain(data.dx, -127, 127); | ||
data.dy = constrain(data.dy, -127, 127); | ||
if (debug_mouse) dprintf("Cons] X: %d, Y: %d\n", data.dx, data.dy); | ||
// dprintf("Elapsed:%u, X: %f Y: %\n", i, pgm_read_byte(firmware_data+i)); | ||
|
||
process_mouse_user(mouse_report, data.dx, data.dy); | ||
} | ||
} | ||
|
||
bool process_record_kb(uint16_t keycode, keyrecord_t* record) { | ||
if (debug_mouse) { | ||
dprintf("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 == 2) && (record->event.key.row == 0)) { | ||
lastMidClick = timer_read(); | ||
is_scroll_clicked = record->event.pressed; | ||
} | ||
|
||
/* 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) { | ||
if (keycode == KC_MS_BTN1) | ||
currentReport.buttons |= MOUSE_BTN1; | ||
else if (keycode == KC_MS_BTN2) | ||
currentReport.buttons |= MOUSE_BTN2; | ||
else if (keycode == KC_MS_BTN3) | ||
currentReport.buttons |= MOUSE_BTN3; | ||
else if (keycode == KC_MS_BTN4) | ||
currentReport.buttons |= MOUSE_BTN4; | ||
else if (keycode == KC_MS_BTN5) | ||
currentReport.buttons |= MOUSE_BTN5; | ||
} else { | ||
if (keycode == KC_MS_BTN1) | ||
currentReport.buttons &= ~MOUSE_BTN1; | ||
else if (keycode == KC_MS_BTN2) | ||
currentReport.buttons &= ~MOUSE_BTN2; | ||
else if (keycode == KC_MS_BTN3) | ||
currentReport.buttons &= ~MOUSE_BTN3; | ||
else if (keycode == KC_MS_BTN4) | ||
currentReport.buttons &= ~MOUSE_BTN4; | ||
else if (keycode == KC_MS_BTN5) | ||
currentReport.buttons &= ~MOUSE_BTN5; | ||
} | ||
pointing_device_set_report(currentReport); | ||
} | ||
#endif | ||
|
||
return process_record_user(keycode, record); | ||
} | ||
|
||
// 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); | ||
|
||
// This is the debug LED. | ||
setPinOutput(F7); | ||
writePin(F7, debug_enable); | ||
|
||
/* 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 UNUSED_PINS | ||
const pin_t unused_pins[] = UNUSED_PINS; | ||
|
||
for (uint8_t i = 0; i < (sizeof(unused_pins) / sizeof(pin_t)); i++) { | ||
setPinOutput(unused_pins[i]); | ||
writePinLow(unused_pins[i]); | ||
} | ||
#endif | ||
keyboard_pre_init_user(); | ||
} | ||
|
||
void pointing_device_init(void) { | ||
// initialize ball sensor | ||
pmw_spi_init(); | ||
// initialize the scroll wheel's optical encoder | ||
opt_encoder_init(); | ||
} | ||
|
||
bool has_report_changed (report_mouse_t first, report_mouse_t second) { | ||
return !( | ||
(!first.buttons && first.buttons == second.buttons) && | ||
(!first.x && first.x == second.x) && | ||
(!first.y && first.y == second.y) && | ||
(!first.h && first.h == second.h) && | ||
(!first.v && first.v == second.v) ); | ||
} | ||
|
||
void pointing_device_task(void) { | ||
report_mouse_t mouse_report = pointing_device_get_report(); | ||
process_wheel(&mouse_report); | ||
process_mouse(&mouse_report); | ||
|
||
pointing_device_set_report(mouse_report); | ||
if (has_report_changed(mouse_report, pointing_device_get_report())) { | ||
pointing_device_send(); | ||
} | ||
} |
Oops, something went wrong.