/* * Copyright (c) 2014-2015, Claudio Lapilli and the newRPL Team * All rights reserved. * This file is released under the 3-clause BSD license. * See the file LICENSE.txt that shipped with this distribution. */ #include #include unsigned int __cpu_intoff(); void __cpu_inton(unsigned int); void __tmr_eventreschedule(); // KEYBOARD, LOW LEVEL GLOBAL VARIABLES unsigned short int __keyb_buffer[KEYB_BUFFER] __SYSTEM_GLOBAL__; volatile int __keyb_lock __SYSTEM_GLOBAL__; int __keyflags __SYSTEM_GLOBAL__; int __kused __SYSTEM_GLOBAL__,__kcurrent __SYSTEM_GLOBAL__; keymatrix __kmat __SYSTEM_GLOBAL__; unsigned int __keyplane __SYSTEM_GLOBAL__; int __keynumber __SYSTEM_GLOBAL__,__keycount __SYSTEM_GLOBAL__; int __keyb_repeattime __SYSTEM_GLOBAL__,__keyb_longpresstime __SYSTEM_GLOBAL__,__keyb_debounce __SYSTEM_GLOBAL__; // LOW-LEVEL ROUTINE TO BE USED BY THE IRQ HANDLERS AND EXCEPTION // HANDLERS ONLY keymatrix __keyb_getmatrix(); // WRAPPER TO DISABLE INTERRUPTS WHILE READING THE KEYBOARD // NEEDED ONLY WHEN CALLED FROM WITHIN AN EXCEPTION HANDLER keymatrix __keyb_getmatrixEX(); void __keyb_waitrelease(); // RETURNS THE CURRENT WORKING MATRIX INSTEAD OF // MESSING WITH THE HARDWARE, BUT ONLY IF KEYBOARD HANDLERS WERE STARTED keymatrix keyb_getmatrix(); // LOW-LEVEL FUNCTION TO BE USED BY THE // EXCEPTION SUBSYSTEM ONLY const unsigned short const __keyb_shiftconvert[8]={ 0, SHIFT_ALPHA|SHIFT_ALPHAHOLD, SHIFT_LS|SHIFT_LSHOLD, SHIFT_ALPHA|SHIFT_ALPHAHOLD|SHIFT_LS|SHIFT_LSHOLD, SHIFT_RS|SHIFT_RSHOLD, SHIFT_ALPHA|SHIFT_ALPHAHOLD|SHIFT_RS|SHIFT_RSHOLD, SHIFT_LS|SHIFT_LSHOLD|SHIFT_RS|SHIFT_RSHOLD, SHIFT_LS|SHIFT_LSHOLD|SHIFT_ALPHA|SHIFT_ALPHAHOLD|SHIFT_RS|SHIFT_RSHOLD }; int __keyb_getkey(int wait) { keymatrix m; m=__keyb_getmatrixEX(); if(wait) { // wait for a non-shift key to be pressed while( (m&0x8fffffffffffffffLL )==0LL ) m=__keyb_getmatrixEX(); } int kcode,shft=(m>>60)&0x7; unsigned char *mbytes=(unsigned char *)&m; int k; for(k=0,kcode=0;k<8;++mbytes,++k,kcode+=8) { if(*mbytes!=0) { k=*mbytes; while( !(k&1) ) { k>>=1; ++kcode; } break; } } if(wait) { while( (m&0x8fffffffffffffffLL )!=0 ) m=__keyb_getmatrixEX(); if(kcode>=60) kcode=63; } if(kcode<60) return kcode | __keyb_shiftconvert[shft]; if(kcode<64) return kcode; return 0; } #define LONG_KEYPRESSTIME (__keyb_longpresstime) #define REPEAT_KEYTIME (__keyb_repeattime) #define BOUNCE_KEYTIME (__keyb_debounce) #define KF_RUNNING 1 #define KF_ALPHALOCK 2 #define KF_NOREPEAT 4 #define KF_UPDATED 8 void __keyb_postmsg(unsigned int msg) { __keyb_buffer[__kcurrent]=msg; __kcurrent=(__kcurrent+1)&(KEYB_BUFFER-1); // CHECK FOR BUFFER OVERRUN if(__kcurrent==__kused) { // BUFFER OVERRUN, DROP LAST KEY __kcurrent=(__kcurrent-1)&(KEYB_BUFFER-1); } } void keyb_postmsg(unsigned int msg) { // WARNING: PROBLEMS MAY ARISE IF THE INTERRUPT SERVICE WANTS // TO POST A MESSAGE WHILE THE USER IS POSTING ONE. while(cpu_getlock(1,&__keyb_lock)); __keyb_postmsg(msg); __keyb_lock=0; } unsigned int keyb_getmsg() { if(__kused==__kcurrent) return 0; unsigned int msg=__keyb_buffer[__kused]; __kused=(__kused+1)&(KEYB_BUFFER-1); return msg; } // CHECK IF ANY AVAILABLE KEYSTROKES int keyb_anymsg() { if(__kused==__kcurrent) return 0; return 1; } // FLUSH KEYBOARD BUFFER void keyb_flush() { while(keyb_getmatrix()!=0LL); __kused=__kcurrent; } // FLUSH KEYBOARD BUFFER WITHOUT WAITING void keyb_flushnowait() { __kused=__kcurrent; } // RETURN TRUE IF AN UPDATE HAPPENED // USED TO DETECT IF AN INTERRUPT WAS DUE TO THE KEYBOARD int keyb_wasupdated() { int k=__keyflags&KF_UPDATED; __keyflags^=k; return k; } // ANALYZE CHANGES IN THE KEYBOARD STATUS AND POST MESSAGES ACCORDINGLY #define ALPHALOCK (SHIFT_ALPHA<<17) #define OTHER_KEY (SHIFT_ALPHA<<18) #define ONE_PRESS (SHIFT_ALPHA<<19) #define ALPHASWAP (SHIFT_ALPHA<<20) void __keyb_update() { if(cpu_getlock(1,&__keyb_lock)) return; keymatrix a,b; __keyflags|=KF_UPDATED; doupdate: a=__keyb_getmatrix(); b=a^__kmat; __kmat=a; // ANALYZE CHANGES if(b!=0) { // POST MESSAGE int key=0; while(b!=0) { if(b&1) { if(a&1) { // POST KEYDN MESSAGE if(__keynumber==-key) { // DISREGARD SPURIOUS KEYPRESS __kmat&=~(1LL<>16))); } } } else { __keyb_postmsg(KM_KEYUP + key); if(key<60 || (__keynumber==KB_ALPHA)) { if(__keynumber>0) __keynumber=-__keynumber; __keycount=-BOUNCE_KEYTIME; __keyplane&=~((SHIFT_LS|SHIFT_RS)<<16); if(!(__keyplane& (SHIFT_HOLD | SHIFT_ALHOLD | SHIFT_ONHOLD))) { unsigned int oldkeyplane=__keyplane; __keyplane&=~(SHIFT_LS|SHIFT_RS|SHIFT_ALPHA); // KILL ALL SHIFT PLANES if(__keyplane&ALPHALOCK) __keyplane|=SHIFT_ALPHA; // KEEP ALPHA IF LOCKED __keyplane&=~((SHIFT_ALPHA)<<16); if(oldkeyplane!=__keyplane) __keyb_postmsg(KM_SHIFT | (__keyplane&SHIFT_ANY) | MKOLDSHIFT(oldkeyplane|((oldkeyplane&ALPHALOCK)>>16))); } else { if(__keyplane&SHIFT_ALPHA) { // THIS IS A PRESS AND HOLD KEY BEING RAISED __keyplane|=OTHER_KEY; } if(!(__keyplane&(SHIFT_HOLD))) { unsigned int oldkeyplane=__keyplane; // IT WAS ALPHA-HOLD OR ON-HOLD, KILL SHIFTS __keyplane&=~(SHIFT_LS|SHIFT_RS); // KILL ALL SHIFT PLANES if(oldkeyplane!=__keyplane) __keyb_postmsg(KM_SHIFT | (__keyplane&SHIFT_ANY) | MKOLDSHIFT(oldkeyplane|((oldkeyplane&ALPHALOCK)>>16))); } } } else { unsigned int oldkeyplane=__keyplane; if(key==KB_LSHIFT) { __keyplane&=~((SHIFT_LSHOLD|SHIFT_LS)^((__keyplane>>16)&SHIFT_LS)); if(!(oldkeyplane&SHIFT_ALHOLD)) __keyplane&=~((SHIFT_ALPHA)^(((__keyplane>>16)|(__keyplane>>17))&SHIFT_ALPHA)); } if(key==KB_RSHIFT) { __keyplane&=~((SHIFT_RSHOLD|SHIFT_RS)^((__keyplane>>16)&SHIFT_RS)); if(!(oldkeyplane&SHIFT_ALHOLD)) __keyplane&=~((SHIFT_ALPHA)^(((__keyplane>>16)|(__keyplane>>17))&SHIFT_ALPHA)); } if(key==KB_ALPHA) { if(__keyplane&ALPHASWAP) { // ALPHA WAS PRESSED WHILE ALREADY IN ALPHA MODE if(__keyplane&OTHER_KEY) { // ANOTHER KEY WAS PRESSED BEFORE RELEASING ALPHA __keyplane&=~ONE_PRESS; } else { // ALPHA WAS PRESSED AND RELEASED, NO OTHER KEYS if(__keyplane&ONE_PRESS) { // THIS IS THE SECOND PRESS, KILL ALPHA MODE __keyplane&=~ALPHALOCK; __keyplane&=~SHIFT_ALPHA; } else __keyplane|=ONE_PRESS; // SEND MESSAGE THAT ALPHA MODE CYCLING WAS REQUESTED __keyb_postmsg(KM_PRESS + key + (__keyplane&SHIFT_ANY)); __keynumber=key; __keycount=0; } __keyplane&=~ALPHASWAP; } else { // ALPHA WAS PRESSED FOR THE FIRST TIME FROM OTHER MODE if(__keyplane&OTHER_KEY) { __keyplane&=~SHIFT_ALPHAHOLD; } else { // ALPHA WAS PRESSED AND RELEASED __keyplane|=ALPHALOCK; } __keyplane&=~ONE_PRESS; } __keyplane&=~SHIFT_ALHOLD; } if(key==KB_ON) { __keyplane&=~SHIFT_ONHOLD; } __keyb_postmsg(KM_SHIFT | (__keyplane&SHIFT_ANY) | MKOLDSHIFT(oldkeyplane|((oldkeyplane&ALPHALOCK)>>16))); __keynumber=-key; __keycount=-BOUNCE_KEYTIME; } } } b>>=1; a>>=1; ++key; } } // ANALYZE STATUS OF CURRENT KEYPRESS if(__keynumber>=0) { if(__kmat & (1LL<<__keynumber)) { // KEY STILL PRESSED, INCREASE COUNTER ++__keycount; if( (__keycount>LONG_KEYPRESSTIME) ) { //if(!(__keyflags&KF_NOREPEAT)) { // ONLY CERTAIN KEYS WILL AUTOREPEAT switch(__keynumber) { case KB_SPC: case KB_BKS: if(__keyplane&(SHIFT_LS|SHIFT_RS|SHIFT_HOLD|SHIFT_ALHOLD)) { __keyb_postmsg(KM_LPRESS | __keynumber | (__keyplane&SHIFT_ANY)); __keycount=-LONG_KEYPRESSTIME; break; } // OTHERWISE DO REPEAT case KB_UP: case KB_DN: case KB_LF: case KB_RT: // THESE ALWAYS REPEAT, EVEN SHIFTED __keyb_postmsg(KM_REPEAT | __keynumber | (__keyplane&SHIFT_ANY)); __keycount=-REPEAT_KEYTIME; break; default: // DO NOT AUTOREPEAT, DO LONG PRESS __keyb_postmsg(KM_LPRESS | __keynumber | (__keyplane&SHIFT_ANY)); __keycount=-LONG_KEYPRESSTIME; } } if(!__keycount) { switch(__keynumber) { case KB_SPC: case KB_BKS: if(__keyplane&(SHIFT_LS|SHIFT_RS|SHIFT_HOLD|SHIFT_ALHOLD)) { __keyb_postmsg(KM_LREPEAT | __keynumber | (__keyplane&SHIFT_ANY)); __keycount-=LONG_KEYPRESSTIME; break; } // OTHERWISE DO REPEAT case KB_UP: case KB_DN: case KB_LF: case KB_RT: // THESE ALWAYS REPEAT, EVEN SHIFTED __keyb_postmsg(KM_REPEAT | __keynumber | (__keyplane&SHIFT_ANY)); __keycount-=REPEAT_KEYTIME; break; default: // DO NOT AUTOREPEAT, DO LONG PRESS __keyb_postmsg(KM_LREPEAT | __keynumber | (__keyplane&SHIFT_ANY)); __keycount-=LONG_KEYPRESSTIME; } } } } // REPEATER if(__kmat==0) { if(__keycount>=0) { tmr_events[0].status=0; __keynumber=0; } else { ++__keycount; } } else { if(!(tmr_events[0].status&1)) { // ACTIVATE THE TIMER EVENT IF NOT ALREADY RUNNING tmr_events[0].ticks=tmr_ticks()+tmr_events[0].delay; tmr_events[0].status=3; __tmr_eventreschedule(); } } // On-C and On-A-F handling if(__kmat== ((1ULL<>16))); }