* Added little fixes and bootmagic * Update keyboards/gergo/keymaps/oled/rules.mk Co-Authored-By: Drashna Jaelre <drashna@live.com> * whacked out quantum_libs
		
			
				
	
	
		
			419 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "sten.h"
 | |
| 
 | |
| // Chord state
 | |
| uint32_t cChord 		= 0;		// Current Chord
 | |
| int		 chordIndex 	= 0;		// Keys in previousachord
 | |
| int32_t  chordState[32];			// Full Chord history
 | |
| #define  QWERBUF		24			// Size of chords to buffer for output
 | |
| 
 | |
| bool	 repeatFlag 	= false;	// Should we repeat?
 | |
| uint32_t pChord 		= 0;		// Previous Chord
 | |
| int		 pChordIndex 	= 0;		// Keys in previousachord
 | |
| uint32_t pChordState[32];			// Previous chord sate 
 | |
| uint32_t stickyBits = 0;			// Or'd with every incoming press
 | |
| #ifndef NO_DEBUG
 | |
| char debugMsg[32];
 | |
| #endif
 | |
| 
 | |
| // StenoLayer
 | |
| uint32_t releasedChord	= 0;		// Keys released from current chord
 | |
| uint32_t tChord			= 0;		// Protects state of cChord
 | |
| 
 | |
| #ifndef STENOLAYERS
 | |
| uint32_t stenoLayers[] = { PWR };
 | |
| size_t 	 stenoLayerCount = sizeof(stenoLayers)/sizeof(stenoLayers[0]);
 | |
| #endif
 | |
| 
 | |
| // Mode state
 | |
| enum MODE { STENO = 0, QWERTY, COMMAND };
 | |
| enum MODE pMode;
 | |
| bool QWERSTENO = false;
 | |
| #ifdef ONLYQWERTY
 | |
| enum MODE cMode = QWERTY;
 | |
| #else
 | |
| enum MODE cMode = STENO;
 | |
| #endif
 | |
| 
 | |
| // Command State
 | |
| #define MAX_CMD_BUF   20
 | |
| uint8_t	 CMDLEN 	= 0;
 | |
| uint8_t	 CMDBUF[MAX_CMD_BUF];
 | |
| 
 | |
| // Key Repeat state
 | |
| bool     inChord  		= false;
 | |
| bool	 repEngaged 	= false;
 | |
| uint16_t repTimer 		= 0;
 | |
| #define  REP_INIT_DELAY 750
 | |
| #define  REP_DELAY 		25
 | |
| 
 | |
| // Mousekeys state
 | |
| bool	inMouse 		= false;
 | |
| int8_t	mousePress;
 | |
| 
 | |
| // All processing done at chordUp goes through here
 | |
| bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { 
 | |
| 	// Check for mousekeys, this is release
 | |
| #ifdef MOUSEKEY_ENABLE
 | |
| 	if (inMouse) {
 | |
| 		inMouse = false;
 | |
| 		mousekey_off(mousePress);
 | |
| 		mousekey_send();
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	// Toggle Serial/QWERTY steno
 | |
| 	if (cChord == (PWR | FN | ST1 | ST2)) {
 | |
| #ifndef NO_DEBUG
 | |
| 		uprintf("Fallback Toggle\n");
 | |
| #endif
 | |
| 		QWERSTENO = !QWERSTENO;
 | |
| 		
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	// handle command mode
 | |
| 	if (cChord == (PWR | FN | RD | RZ)) {
 | |
| #ifndef NO_DEBUG
 | |
| 		uprintf("COMMAND Toggle\n");
 | |
| #endif
 | |
| 		if (cMode != COMMAND) {   // Entering Command Mode
 | |
| 			CMDLEN = 0;
 | |
| 			pMode = cMode;
 | |
| 			cMode = COMMAND;
 | |
| 		} else {                  // Exiting Command Mode
 | |
| 			cMode = pMode;
 | |
| 
 | |
| 			// Press all and release all
 | |
| 			for (int i = 0; i < CMDLEN; i++) {
 | |
| 				register_code(CMDBUF[i]);
 | |
| 			}
 | |
| 			clear_keyboard();
 | |
| 		}
 | |
| 
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	// Handle Gaming Toggle,
 | |
| 	if (cChord == (PWR | FN | ST4 | ST3) && keymapsCount > 1) {
 | |
| #ifndef NO_DEBUG
 | |
| 		uprintf("Switching to QMK\n");
 | |
| #endif
 | |
| 		layer_on(1);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	// Lone FN press, toggle QWERTY
 | |
| #ifndef ONLYQWERTY
 | |
| 	if (cChord == FN) {
 | |
| 		(cMode == STENO) ? (cMode = QWERTY) : (cMode = STENO);
 | |
| 		goto out;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	// Check for Plover momentary
 | |
| 	if (cMode == QWERTY && (cChord & FN)) {
 | |
| 		cChord ^= FN;
 | |
| 		goto steno;
 | |
| 	}
 | |
| 
 | |
| 	// Do QWERTY and Momentary QWERTY
 | |
| 	if (cMode == QWERTY || (cMode == COMMAND) || (cChord & (FN | PWR))) {
 | |
| 		processChord(false);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	// Fallback NKRO Steno
 | |
| 	if (cMode == STENO && QWERSTENO) {
 | |
| 		processChord(true);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| steno:
 | |
| 	// Hey that's a steno chord!
 | |
| 	inChord = false;
 | |
| 	chordIndex = 0;
 | |
| 	cChord = 0;
 | |
| 	return true; 
 | |
| 
 | |
| out:
 | |
| 	cChord = 0;
 | |
| 	inChord = false;
 | |
| 	chordIndex = 0;
 | |
| 	clear_keyboard();
 | |
| 	repEngaged  = false;
 | |
| 	for (int i = 0; i < 32; i++)
 | |
| 		chordState[i] = 0xFFFF;
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| // Update Chord State 
 | |
| bool process_steno_user(uint16_t keycode, keyrecord_t *record) { 
 | |
| 	// Everything happens in here when steno keys come in.
 | |
| 	// Bail on keyup
 | |
| 	if (!record->event.pressed) return true;
 | |
| 
 | |
| 	// Update key repeat timers
 | |
| 	repTimer = timer_read();
 | |
| 	inChord  = true;
 | |
| 
 | |
| 	// Switch on the press adding to chord
 | |
| 	bool pr = record->event.pressed;
 | |
| 	switch (keycode) {
 | |
| 			// Mods and stuff
 | |
| 			case STN_ST1:			pr ? (cChord |= (ST1)): (cChord &= ~(ST1)); break;
 | |
| 			case STN_ST2:			pr ? (cChord |= (ST2)): (cChord &= ~(ST2)); break;
 | |
| 			case STN_ST3:			pr ? (cChord |= (ST3)): (cChord &= ~(ST3)); break;
 | |
| 			case STN_ST4:			pr ? (cChord |= (ST4)): (cChord &= ~(ST4)); break;
 | |
| 			case STN_FN:			pr ? (cChord |= (FN)) : (cChord &= ~(FN)); break;
 | |
| 			case STN_PWR:			pr ? (cChord |= (PWR)): (cChord &= ~(PWR)); break;
 | |
| 			case STN_N1...STN_N6:	pr ? (cChord |= (LNO)): (cChord &= ~(LNO)); break;
 | |
| 			case STN_N7...STN_NC:	pr ? (cChord |= (RNO)): (cChord &= ~(RNO)); break;
 | |
| 
 | |
| 			// All the letter keys
 | |
| 			case STN_S1:			pr ? (cChord |= (LSU)) : (cChord &= ~(LSU));  break;
 | |
| 			case STN_S2:			pr ? (cChord |= (LSD)) : (cChord &= ~(LSD));  break;
 | |
| 			case STN_TL:			pr ? (cChord |= (LFT)) : (cChord &= ~(LFT)); break;
 | |
| 			case STN_KL:			pr ? (cChord |= (LK)) : (cChord &= ~(LK)); break;
 | |
| 			case STN_PL:			pr ? (cChord |= (LP)) : (cChord &= ~(LP)); break;
 | |
| 			case STN_WL:			pr ? (cChord |= (LW)) : (cChord &= ~(LW)); break;
 | |
| 			case STN_HL:			pr ? (cChord |= (LH)) : (cChord &= ~(LH)); break;
 | |
| 			case STN_RL:			pr ? (cChord |= (LR)) : (cChord &= ~(LR)); break;
 | |
| 			case STN_A:				pr ? (cChord |= (LA)) : (cChord &= ~(LA)); break;
 | |
| 			case STN_O:				pr ? (cChord |= (LO)) : (cChord &= ~(LO)); break;
 | |
| 			case STN_E:				pr ? (cChord |= (RE)) : (cChord &= ~(RE)); break;
 | |
| 			case STN_U:				pr ? (cChord |= (RU)) : (cChord &= ~(RU)); break;
 | |
| 			case STN_FR:			pr ? (cChord |= (RF)) : (cChord &= ~(RF)); break;
 | |
| 			case STN_RR:			pr ? (cChord |= (RR)) : (cChord &= ~(RR)); break;
 | |
| 			case STN_PR:			pr ? (cChord |= (RP)) : (cChord &= ~(RP)); break;
 | |
| 			case STN_BR:			pr ? (cChord |= (RB)) : (cChord &= ~(RB)); break;
 | |
| 			case STN_LR:			pr ? (cChord |= (RL)) : (cChord &= ~(RL)); break;
 | |
| 			case STN_GR:			pr ? (cChord |= (RG)) : (cChord &= ~(RG)); break;
 | |
| 			case STN_TR:			pr ? (cChord |= (RT)) : (cChord &= ~(RT)); break;
 | |
| 			case STN_SR:			pr ? (cChord |= (RS)) : (cChord &= ~(RS)); break;
 | |
| 			case STN_DR:			pr ? (cChord |= (RD)) : (cChord &= ~(RD)); break;
 | |
| 			case STN_ZR:			pr ? (cChord |= (RZ)) : (cChord &= ~(RZ)); break;
 | |
| 	}
 | |
| 
 | |
| 	// Store previous state for fastQWER
 | |
| 	if (pr) {
 | |
| 		chordState[chordIndex] = cChord; 
 | |
| 		chordIndex++;
 | |
| 	}
 | |
| 
 | |
| 	return true; 
 | |
| }
 | |
| void matrix_scan_user(void) {
 | |
| 	// We abuse this for early sending of key
 | |
| 	// Key repeat only on QWER/SYMB layers
 | |
| 	if (cMode != QWERTY || !inChord) return;
 | |
| 
 | |
| 	// Check timers
 | |
| #ifndef NO_REPEAT
 | |
| 	if (repEngaged && timer_elapsed(repTimer) > REP_DELAY) {
 | |
| 		// Process Key for report
 | |
| 		processChord(false);
 | |
| 
 | |
| 		// Send report to host
 | |
| 		send_keyboard_report();
 | |
| 		clear_keyboard();
 | |
| 		repTimer = timer_read();
 | |
| 	}
 | |
| 
 | |
| 	if (!repEngaged && timer_elapsed(repTimer) > REP_INIT_DELAY) {
 | |
| 		repEngaged = true;
 | |
| 	}
 | |
| #endif
 | |
| };
 | |
| 
 | |
| // For Plover NKRO
 | |
| uint32_t processFakeSteno(bool lookup) { 
 | |
| 	P( LSU,				SEND(KC_Q););
 | |
| 	P( LSD,				SEND(KC_A););
 | |
| 	P( LFT,				SEND(KC_W););
 | |
| 	P( LP,				SEND(KC_E););
 | |
| 	P( LH,				SEND(KC_R););
 | |
| 	P( LK,				SEND(KC_S););
 | |
| 	P( LW,				SEND(KC_D););
 | |
| 	P( LR,				SEND(KC_F););
 | |
| 	P( ST1,				SEND(KC_T););
 | |
| 	P( ST2,				SEND(KC_G););
 | |
| 	P( LA,				SEND(KC_C););
 | |
| 	P( LO,				SEND(KC_V););
 | |
| 	P( RE,				SEND(KC_N););
 | |
| 	P( RU,				SEND(KC_M););
 | |
| 	P( ST3,				SEND(KC_Y););
 | |
| 	P( ST4,				SEND(KC_H););
 | |
| 	P( RF,				SEND(KC_U););
 | |
| 	P( RP,				SEND(KC_I););
 | |
| 	P( RL,				SEND(KC_O););
 | |
| 	P( RT,				SEND(KC_P););
 | |
| 	P( RD,				SEND(KC_LBRC););
 | |
| 	P( RR,				SEND(KC_J););
 | |
| 	P( RB,				SEND(KC_K););
 | |
| 	P( RG,				SEND(KC_L););
 | |
| 	P( RS,				SEND(KC_SCLN););
 | |
| 	P( RZ,				SEND(KC_COMM););
 | |
| 	P( LNO,				SEND(KC_1););
 | |
| 	P( RNO,				SEND(KC_1););
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| // Traverse the chord history to a given point
 | |
| // Returns the mask to use
 | |
| void processChord(bool useFakeSteno) {
 | |
| 	// Save the clean chord state
 | |
| 	uint32_t savedChord = cChord;
 | |
| 
 | |
| 	// Apply Stick Bits if needed
 | |
| 	if (stickyBits != 0) {
 | |
| 		cChord |= stickyBits;
 | |
| 		for (int i = 0; i <= chordIndex; i++)
 | |
| 			chordState[i] |= stickyBits;
 | |
| 	}
 | |
| 
 | |
| 	// Strip FN
 | |
| 	if (cChord & FN) cChord ^= FN;
 | |
| 
 | |
| 	// First we test if a whole chord was passsed
 | |
| 	// If so we just run it handling repeat logic
 | |
| 	if (useFakeSteno && processFakeSteno(true) == cChord) {
 | |
| 		processFakeSteno(false);
 | |
| 		return;
 | |
| 	} else if (processQwerty(true) == cChord) {
 | |
| 		processQwerty(false);
 | |
| 		// Repeat logic
 | |
| 		if (repeatFlag) {
 | |
| 			restoreState();
 | |
| 			repeatFlag = false;
 | |
| 			processChord(false);
 | |
| 		} else {
 | |
| 			saveState(cChord);
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	// Iterate through chord picking out the individual 
 | |
| 	// and longest chords
 | |
| 	uint32_t bufChords[QWERBUF];
 | |
| 	int 	 bufLen		= 0;
 | |
| 	uint32_t mask		= 0;
 | |
| 
 | |
| 	// We iterate over it multiple times to catch the longest
 | |
| 	// chord. Then that gets addded to the mask and re run.
 | |
| 	while (savedChord != mask) {
 | |
| 		uint32_t test  	 		= 0;
 | |
| 		uint32_t longestChord	= 0;
 | |
| 
 | |
| 		for (int i = 0; i <= chordIndex; i++) {
 | |
| 			cChord = chordState[i] & ~mask;
 | |
| 			if (cChord == 0)
 | |
| 				continue;
 | |
| 
 | |
| 			// Assume mid parse Sym is new chord
 | |
| 			if (i != 0 && test != 0 && (cChord ^ test) == PWR) {
 | |
| 				longestChord = test;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			// Lock SYM layer in once detected
 | |
| 			if (mask & PWR)
 | |
| 				cChord |= PWR;
 | |
| 
 | |
| 
 | |
| 			// Testing for keycodes
 | |
| 			if (useFakeSteno) {
 | |
| 				test = processFakeSteno(true);
 | |
| 			} else {
 | |
| 				test = processQwerty(true);
 | |
| 			}
 | |
| 		 
 | |
| 			if (test != 0) {
 | |
| 				longestChord = test;
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		mask |= longestChord;
 | |
| 		bufChords[bufLen] = longestChord;
 | |
| 		bufLen++;
 | |
| 
 | |
| 		// That's a loop of sorts, halt processing
 | |
| 		if (bufLen >= QWERBUF) {
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	// Now that the buffer is populated, we run it
 | |
| 	for (int i = 0; i < bufLen ; i++) {
 | |
| 		cChord = bufChords[i];
 | |
| 		if (useFakeSteno) {
 | |
| 			processFakeSteno(false);
 | |
| 		} else {
 | |
| 			processQwerty(false);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Save state in case of repeat
 | |
| 	if (!repeatFlag) {			
 | |
| 		saveState(savedChord);
 | |
| 	}
 | |
| 
 | |
| 	// Restore cChord for held repeat
 | |
| 	cChord = savedChord;
 | |
| 
 | |
| 	return;
 | |
| }
 | |
| void saveState(uint32_t cleanChord) {
 | |
| 	pChord = cleanChord;
 | |
| 	pChordIndex = chordIndex;
 | |
| 	for (int i = 0; i < 32; i++) 
 | |
| 		pChordState[i] = chordState[i];
 | |
| }
 | |
| void restoreState() {
 | |
| 	cChord = pChord;
 | |
| 	chordIndex = pChordIndex;
 | |
| 	for (int i = 0; i < 32; i++) 
 | |
| 		chordState[i] = pChordState[i];
 | |
| }
 | |
| 
 | |
| // Macros for calling from keymap.c
 | |
| void SEND(uint8_t kc) {
 | |
| 	// Send Keycode, Does not work for Quantum Codes
 | |
| 	if (cMode == COMMAND && CMDLEN < MAX_CMD_BUF) {
 | |
| #ifndef NO_DEBUG
 | |
| 		uprintf("CMD LEN: %d BUF: %d\n", CMDLEN, MAX_CMD_BUF);
 | |
| #endif
 | |
| 		CMDBUF[CMDLEN] = kc;
 | |
| 		CMDLEN++;
 | |
| 	} 
 | |
| 
 | |
| 	if (cMode != COMMAND) register_code(kc);
 | |
| 	return;
 | |
| }
 | |
| void REPEAT(void) {
 | |
| 	if (cMode != QWERTY)
 | |
| 		return;
 | |
| 
 | |
| 	repeatFlag = true;
 | |
| 	return;
 | |
| }
 | |
| void SET_STICKY(uint32_t stick) {
 | |
| 	stickyBits = stick;
 | |
| 	return;
 | |
| }
 | |
| void SWITCH_LAYER(int layer) {
 | |
| 	if (keymapsCount >= layer) 
 | |
| 		layer_on(layer);
 | |
| }
 | |
| void CLICK_MOUSE(uint8_t kc) {
 | |
| #ifdef MOUSEKEY_ENABLE
 | |
| 	mousekey_on(kc);
 | |
| 	mousekey_send();
 | |
| 
 | |
| 	// Store state for later use
 | |
| 	inMouse = true;
 | |
| 	mousePress = kc;
 | |
| #endif
 | |
| }
 |