ft2-clone

Fasttracker 2 clone
Log | Files | Refs | README | LICENSE

ft2_keyboard.c (26645B)


      1 // for finding memory leaks in debug mode with Visual Studio
      2 #if defined _DEBUG && defined _MSC_VER
      3 #include <crtdbg.h>
      4 #endif
      5 
      6 #include <stdint.h>
      7 #include <stdbool.h>
      8 #include <string.h>
      9 #include "ft2_header.h"
     10 #include "ft2_keyboard.h"
     11 #include "ft2_gui.h"
     12 #include "ft2_about.h"
     13 #include "ft2_video.h"
     14 #include "ft2_edit.h"
     15 #include "ft2_config.h"
     16 #include "ft2_help.h"
     17 #include "ft2_mouse.h"
     18 #include "ft2_nibbles.h"
     19 #include "ft2_inst_ed.h"
     20 #include "ft2_pattern_ed.h"
     21 #include "ft2_diskop.h"
     22 #include "ft2_wav_renderer.h"
     23 #include "ft2_sample_ed.h"
     24 #include "ft2_audio.h"
     25 #include "ft2_trim.h"
     26 #include "ft2_sample_ed_features.h"
     27 #include "ft2_midi.h"
     28 #include "ft2_structs.h"
     29 
     30 keyb_t keyb; // globalized
     31 
     32 static const uint8_t scancodeKey2Note[52] = // keys (USB usage page standard) to FT2 notes look-up table
     33 {
     34 	0x08, 0x05, 0x04, 0x11, 0x00, 0x07, 0x09, 0x19,
     35 	0x0B, 0x00, 0x0E, 0x0C, 0x0A, 0x1B, 0x1D, 0x0D,
     36 	0x12, 0x02, 0x14, 0x18, 0x06, 0x0F, 0x03, 0x16,
     37 	0x01, 0x00, 0x0E, 0x10, 0x00, 0x13, 0x15, 0x17,
     38 	0x00, 0x1A, 0x1C, 0x22, 0x00, 0x00, 0x00, 0x00,
     39 	0x00, 0x1F, 0x1E, 0x20, 0x13, 0x00, 0x10, 0x00,
     40 	0x00, 0x0D, 0x0F, 0x11
     41 };
     42 
     43 static void handleKeys(SDL_Keycode keycode, SDL_Scancode scanKey);
     44 static bool checkModifiedKeys(SDL_Keycode keycode);
     45 
     46 int8_t scancodeKeyToNote(SDL_Scancode scancode)
     47 {
     48 	if (scancode == SDL_SCANCODE_CAPSLOCK || scancode == SDL_SCANCODE_NONUSBACKSLASH)
     49 		return NOTE_OFF;
     50 
     51 	// translate key to note
     52 	int8_t note = 0;
     53 	if (scancode >= SDL_SCANCODE_B && scancode <= SDL_SCANCODE_SLASH)
     54 		note = scancodeKey2Note[(int32_t)scancode - SDL_SCANCODE_B];
     55 
     56 	if (note == 0)
     57 		return -1; // not a note key, do further key handling
     58 
     59 	return note + (editor.curOctave * 12);
     60 }
     61 
     62 void readKeyModifiers(void)
     63 {
     64 	const SDL_Keymod modState = SDL_GetModState();
     65 
     66 	keyb.leftCtrlPressed = (modState & KMOD_LCTRL) ? true : false;
     67 	keyb.leftAltPressed = (modState & KMOD_LALT) ? true : false;
     68 	keyb.leftShiftPressed = (modState & KMOD_LSHIFT) ? true : false;
     69 #ifdef __APPLE__
     70 	keyb.leftCommandPressed = (modState & KMOD_LGUI) ? true : false;
     71 #endif
     72 	keyb.keyModifierDown = (modState & (KMOD_LSHIFT | KMOD_LCTRL | KMOD_LALT | KMOD_LGUI)) ? true : false;
     73 
     74 
     75 #ifdef _WIN32
     76 	keyb.leftWinKeyDown = (modState & KMOD_LGUI) ? true : false;
     77 #endif
     78 }
     79 
     80 void keyUpHandler(SDL_Scancode scancode, SDL_Keycode keycode)
     81 {
     82 	if (editor.editTextFlag || ui.sysReqShown)
     83 		return; // kludge: don't handle key up! (XXX: Is this hack really needed anymore?)
     84 
     85 	/* Yet another kludge for not leaving a ghost key-up event after an inputBox/okBox
     86 	** was exited with a key press. They could be picked up as note release events.
     87 	*/
     88 	if (keyb.ignoreCurrKeyUp)
     89 	{
     90 		keyb.ignoreCurrKeyUp = false;
     91 		return;
     92 	}
     93 
     94 	if (cursor.object == CURSOR_NOTE && !keyb.keyModifierDown)
     95 		testNoteKeysRelease(scancode);
     96 
     97 	if (scancode == SDL_SCANCODE_KP_PLUS)
     98 		keyb.numPadPlusPressed = false;
     99 
    100 	keyb.keyRepeat = false;
    101 
    102 	(void)keycode;
    103 }
    104 
    105 void keyDownHandler(SDL_Scancode scancode, SDL_Keycode keycode, bool keyWasRepeated)
    106 {
    107 	if (keycode == SDLK_UNKNOWN)
    108 		return;
    109 
    110 	// revert "delete/rename" mouse modes (disk op.)
    111 	if (mouse.mode != MOUSE_MODE_NORMAL)
    112 		setMouseMode(MOUSE_MODE_NORMAL);
    113 
    114 	if (ui.sysReqShown)
    115 	{
    116 		if (keycode == SDLK_RETURN)
    117 			ui.sysReqEnterPressed = true;
    118 		else if (keycode == SDLK_ESCAPE)
    119 			ui.sysReqShown = false;
    120 
    121 		return;
    122 	}
    123 
    124 	if (testNibblesCheatCodes(keycode))
    125 		return; // current key (+ modifiers) matches nibbles cheat code sequence, ignore current key here
    126 
    127 	if (keyWasRepeated)
    128 	{
    129 		if (editor.NI_Play || !keyb.keyRepeat)
    130 			return; // do NOT repeat keys in Nibbles or if keyRepeat is disabled
    131 	}
    132 
    133 	if (scancode != SDL_SCANCODE_ESCAPE)
    134 		keyb.keyRepeat = true;
    135 
    136 	// handle certain keys (home/end/left/right etc) when editing text
    137 	if (editor.editTextFlag)
    138 	{
    139 		handleTextEditControl(keycode);
    140 		return;
    141 	}
    142 
    143 	if (editor.NI_Play)
    144 	{
    145 		nibblesKeyAdministrator(scancode);
    146 		return;
    147 	}
    148 
    149 	if (keycode == SDLK_ESCAPE)
    150 	{
    151 		if (quitBox(false) == 1)
    152 			editor.throwExit = true;
    153 
    154 		return;
    155 	}
    156 
    157 	if (scancode == SDL_SCANCODE_KP_PLUS)
    158 		keyb.numPadPlusPressed = true;
    159 
    160 	if (handleEditKeys(keycode, scancode))
    161 		return;
    162 
    163 	if (keyb.keyModifierDown && checkModifiedKeys(keycode))
    164 		return;
    165 
    166 	handleKeys(keycode, scancode); // no pattern editing, do general key handling
    167 }
    168 
    169 static void handleKeys(SDL_Keycode keycode, SDL_Scancode scanKey)
    170 {
    171 	// if we're holding numpad plus but not pressing bank keys, don't check any other key
    172 	if (keyb.numPadPlusPressed && !keyb.leftCtrlPressed)
    173 	{
    174 		if (scanKey != SDL_SCANCODE_NUMLOCKCLEAR && scanKey != SDL_SCANCODE_KP_DIVIDE &&
    175 			scanKey != SDL_SCANCODE_KP_MULTIPLY  && scanKey != SDL_SCANCODE_KP_MINUS)
    176 		{
    177 			return;
    178 		}
    179 	}
    180 
    181 	// handle scankeys (actual key on keyboard, using US keyb. layout)
    182 	switch (scanKey)
    183 	{
    184 		case SDL_SCANCODE_KP_ENTER: pbSwapInstrBank(); return;
    185 
    186 		case SDL_SCANCODE_NUMLOCKCLEAR:
    187 		{
    188 			if (keyb.numPadPlusPressed)
    189 			{
    190 				if (editor.instrBankSwapped)
    191 					pbSetInstrBank13();
    192 				else
    193 					pbSetInstrBank5();
    194 			}
    195 			else
    196 			{
    197 				if (editor.instrBankSwapped)
    198 					pbSetInstrBank9();
    199 				else
    200 					pbSetInstrBank1();
    201 			}
    202 		}
    203 		return;
    204 
    205 		case SDL_SCANCODE_KP_DIVIDE:
    206 		{
    207 			if (keyb.numPadPlusPressed)
    208 			{
    209 				if (editor.instrBankSwapped)
    210 					pbSetInstrBank14();
    211 				else
    212 					pbSetInstrBank6();
    213 			}
    214 			else
    215 			{
    216 				if (editor.instrBankSwapped)
    217 					pbSetInstrBank10();
    218 				else
    219 					pbSetInstrBank2();
    220 			}
    221 		}
    222 		return;
    223 
    224 		case SDL_SCANCODE_KP_MULTIPLY:
    225 		{
    226 			if (keyb.numPadPlusPressed)
    227 			{
    228 				if (editor.instrBankSwapped)
    229 					pbSetInstrBank15();
    230 				else
    231 					pbSetInstrBank7();
    232 			}
    233 			else
    234 			{
    235 				if (editor.instrBankSwapped)
    236 					pbSetInstrBank11();
    237 				else
    238 					pbSetInstrBank3();
    239 			}
    240 		}
    241 		return;
    242 
    243 		case SDL_SCANCODE_KP_MINUS:
    244 		{
    245 			if (keyb.leftCtrlPressed) // non-FT2 feature: Decrease master volume by 16
    246 			{
    247 				if (config.masterVol >= 16)
    248 					config.masterVol -= 16;
    249 				else
    250 					config.masterVol = 0;
    251 
    252 				setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
    253 				if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO)
    254 					showConfigScreen();
    255 			}
    256 			else
    257 			{
    258 				if (keyb.numPadPlusPressed)
    259 				{
    260 					if (editor.instrBankSwapped)
    261 						pbSetInstrBank16();
    262 					else
    263 						pbSetInstrBank8();
    264 				}
    265 				else
    266 				{
    267 					if (editor.instrBankSwapped)
    268 						pbSetInstrBank12();
    269 					else
    270 						pbSetInstrBank4();
    271 				}
    272 			}
    273 		}
    274 		return;
    275 
    276 		case SDL_SCANCODE_KP_PLUS:
    277 		{
    278 			if (keyb.leftCtrlPressed) // non-FT2 feature: Increase master volume by 16
    279 			{
    280 				if (config.masterVol <= 256-16)
    281 					config.masterVol += 16;
    282 				else
    283 					config.masterVol = 256;
    284 
    285 				setAudioAmp(config.boostLevel, config.masterVol, !!(config.specialFlags & BITDEPTH_32));
    286 				if (ui.configScreenShown && editor.currConfigScreen == CONFIG_SCREEN_AUDIO)
    287 					showConfigScreen();
    288 			}
    289 		}
    290 		return;
    291 
    292 		case SDL_SCANCODE_KP_PERIOD:
    293 		{
    294 			if (editor.curInstr > 0)
    295 			{
    296 				if (keyb.leftShiftPressed) // this only triggers if num lock is off. Probably an SDL bug...
    297 				{
    298 					clearSample();
    299 				}
    300 				else
    301 				{
    302 					if (editor.curInstr == 0 || instr[editor.curInstr] == NULL)
    303 						return;
    304 
    305 					if (okBox(1, "System request", "Clear instrument?", NULL) == 1)
    306 					{
    307 						freeInstr(editor.curInstr);
    308 						memset(song.instrName[editor.curInstr], 0, sizeof(song.instrName[editor.curInstr]));
    309 						updateNewInstrument();
    310 						setSongModifiedFlag();
    311 					}
    312 				}
    313 			}
    314 		}
    315 		return;
    316 
    317 		case SDL_SCANCODE_KP_0: setNewInstr(0); return;
    318 		case SDL_SCANCODE_KP_1: setNewInstr(editor.instrBankOffset+1); return;
    319 		case SDL_SCANCODE_KP_2: setNewInstr(editor.instrBankOffset+2); return;
    320 		case SDL_SCANCODE_KP_3: setNewInstr(editor.instrBankOffset+3); return;
    321 		case SDL_SCANCODE_KP_4: setNewInstr(editor.instrBankOffset+4); return;
    322 		case SDL_SCANCODE_KP_5: setNewInstr(editor.instrBankOffset+5); return;
    323 		case SDL_SCANCODE_KP_6: setNewInstr(editor.instrBankOffset+6); return;
    324 		case SDL_SCANCODE_KP_7: setNewInstr(editor.instrBankOffset+7); return;
    325 		case SDL_SCANCODE_KP_8: setNewInstr(editor.instrBankOffset+8); return;
    326 
    327 		case SDL_SCANCODE_GRAVE: // "key below esc"
    328 		{
    329 			if (keyb.leftShiftPressed)
    330 			{
    331 				// decrease edit skip
    332 				if (editor.editRowSkip == 0)
    333 					editor.editRowSkip = 16;
    334 				else
    335 					editor.editRowSkip--;
    336 			}
    337 			else
    338 			{
    339 				// increase edit skip
    340 				if (editor.editRowSkip == 16)
    341 					editor.editRowSkip = 0;
    342 				else
    343 					editor.editRowSkip++;
    344 			}
    345 
    346 			if (!ui.nibblesShown     && !ui.configScreenShown &&
    347 				!ui.aboutScreenShown && !ui.diskOpShown       &&
    348 				!ui.helpScreenShown  && !ui.extendedPatternEditor)
    349 			{
    350 				drawIDAdd();
    351 			}
    352 		}
    353 		return;
    354 
    355 		default: break;
    356 	}
    357 
    358 	// no normal key (keycode) pressed (XXX: shouldn't happen..?)
    359 	if (keycode == SDLK_UNKNOWN)
    360 		return;
    361 
    362 	// handle normal keys (keycodes - affected by keyb. layout in OS)
    363 	switch (keycode)
    364 	{
    365 		default: return;
    366 
    367 		case SDLK_DELETE: // non-FT2 addition
    368 		{
    369 			if (ui.sampleEditorShown)
    370 				sampCut();
    371 		}
    372 		break;
    373 
    374 		// This is maybe not an ideal key for this anymore...
    375 		//case SDLK_PRINTSCREEN: togglePatternEditorExtended(); break;
    376 
    377 		// EDIT/PLAY KEYS
    378 
    379 		// record pattern
    380 		case SDLK_RSHIFT: startPlaying(PLAYMODE_RECPATT, 0); break;
    381 
    382 		// play song
    383 #ifdef __APPLE__
    384 		case SDLK_RGUI: // fall-through for Apple keyboards
    385 #endif
    386 		case SDLK_RCTRL:
    387 			startPlaying(PLAYMODE_SONG, 0);
    388 		break;
    389 
    390 		// play pattern
    391 		case SDLK_RALT:
    392 		{
    393 			if (!keyb.leftCtrlPressed) // kludge for Mac (toggle fullscreen)
    394 				startPlaying(PLAYMODE_PATT, 0);
    395 		}
    396 		break;
    397 
    398 		case SDLK_SPACE:
    399 		{
    400 			if (playMode == PLAYMODE_IDLE)
    401 			{
    402 				lockMixerCallback();
    403 				memset(editor.keyOnTab, 0, sizeof (editor.keyOnTab));
    404 				playMode = PLAYMODE_EDIT;
    405 				ui.updatePosSections = true; // for updating mode text
    406 				unlockMixerCallback();
    407 			}
    408 			else
    409 			{
    410 				stopPlaying();
    411 			}
    412 		}
    413 		break;
    414 
    415 		case SDLK_TAB:
    416 		{
    417 			if (keyb.leftShiftPressed)
    418 				cursorTabLeft();
    419 			else
    420 				cursorTabRight();
    421 		}
    422 		break;
    423 
    424 		case SDLK_LEFT:  cursorLeft();  break;
    425 		case SDLK_RIGHT: cursorRight(); break;
    426 
    427 		// function Keys (F1..F12)
    428 
    429 		case SDLK_F1:
    430 		{
    431 			     if (keyb.leftShiftPressed) trackTranspAllInsDn();
    432 			else if (keyb.leftCtrlPressed)  pattTranspAllInsDn();
    433 			else if (keyb.leftAltPressed)   blockTranspAllInsDn();
    434 			else                            editor.curOctave = 0;
    435 		}
    436 		break;
    437 
    438 		case SDLK_F2:
    439 		{
    440 			     if (keyb.leftShiftPressed) trackTranspAllInsUp();
    441 			else if (keyb.leftCtrlPressed)  pattTranspAllInsUp();
    442 			else if (keyb.leftAltPressed)   blockTranspAllInsUp();
    443 			else                            editor.curOctave = 1;
    444 		}
    445 		break;
    446 
    447 		case SDLK_F3:
    448 		{
    449 			     if (keyb.leftShiftPressed) cutTrack();
    450 			else if (keyb.leftCtrlPressed)  cutPattern();
    451 			else if (keyb.leftAltPressed)   cutBlock();
    452 			else                            editor.curOctave = 2;
    453 		}
    454 		break;
    455 
    456 		case SDLK_F4:
    457 		{
    458 			     if (keyb.leftShiftPressed) copyTrack();
    459 			else if (keyb.leftCtrlPressed)  copyPattern();
    460 			else if (keyb.leftAltPressed)   copyBlock();
    461 			else                            editor.curOctave = 3;
    462 		}
    463 		break;
    464 
    465 		case SDLK_F5:
    466 		{
    467 			     if (keyb.leftShiftPressed) pasteTrack();
    468 			else if (keyb.leftCtrlPressed)  pastePattern();
    469 			else if (keyb.leftAltPressed)   pasteBlock();
    470 			else                            editor.curOctave = 4;
    471 		}
    472 		break;
    473 
    474 		case SDLK_F6: editor.curOctave = 5; break;
    475 
    476 		case SDLK_F7:
    477 		{
    478 			     if (keyb.leftShiftPressed) trackTranspCurInsDn();
    479 			else if (keyb.leftCtrlPressed)  pattTranspCurInsDn();
    480 			else if (keyb.leftAltPressed)   blockTranspCurInsDn();
    481 			else                            editor.curOctave = 6;
    482 		}
    483 		break;
    484 
    485 		case SDLK_F8:
    486 		{
    487 			     if (keyb.leftShiftPressed) trackTranspCurInsUp();
    488 			else if (keyb.leftCtrlPressed)  pattTranspCurInsUp();
    489 			else if (keyb.leftAltPressed)   blockTranspCurInsUp();
    490 			else                            editor.curOctave = 6;
    491 		}
    492 		break;
    493 
    494 		case SDLK_F9:
    495 		{
    496 			lockAudio();
    497 
    498 			song.row = editor.ptnJumpPos[0];
    499 			if (song.row >= song.currNumRows)
    500 				song.row = song.currNumRows - 1;
    501 
    502 			if (!songPlaying)
    503 			{
    504 				editor.row = (uint8_t)song.row;
    505 				ui.updatePatternEditor = true;
    506 			}
    507 
    508 			unlockAudio();
    509 		}
    510 		break;
    511 
    512 		case SDLK_F10:
    513 		{
    514 			lockAudio();
    515 
    516 			song.row = editor.ptnJumpPos[1];
    517 			if (song.row >= song.currNumRows)
    518 				song.row = song.currNumRows - 1;
    519 
    520 			if (!songPlaying)
    521 			{
    522 				editor.row = (uint8_t)song.row;
    523 				ui.updatePatternEditor = true;
    524 			}
    525 
    526 			unlockAudio();
    527 		}
    528 		break;
    529 
    530 		case SDLK_F11:
    531 		{
    532 			lockAudio();
    533 
    534 			song.row = editor.ptnJumpPos[2];
    535 			if (song.row >= song.currNumRows)
    536 				song.row  = song.currNumRows - 1;
    537 
    538 			if (!songPlaying)
    539 			{
    540 				editor.row = (uint8_t)song.row;
    541 				ui.updatePatternEditor = true;
    542 			}
    543 
    544 			unlockAudio();
    545 		}
    546 		break;
    547 
    548 		case SDLK_F12:
    549 		{
    550 			lockAudio();
    551 
    552 			song.row = editor.ptnJumpPos[3];
    553 			if (song.row >= song.currNumRows)
    554 				song.row = song.currNumRows - 1;
    555 
    556 			if (!songPlaying)
    557 			{
    558 				editor.row = (uint8_t)song.row;
    559 				ui.updatePatternEditor = true;
    560 			}
    561 
    562 			unlockAudio();
    563 		}
    564 		break;
    565 
    566 		// PATTERN EDITOR POSITION KEYS
    567 		
    568 		case SDLK_INSERT:
    569 		{
    570 			if (keyb.leftShiftPressed)
    571 				insertPatternLine();
    572 			else
    573 				insertPatternNote();
    574 		}
    575 		break;
    576 
    577 		case SDLK_BACKSPACE:
    578 		{
    579 			     if (ui.diskOpShown) diskOpGoParent();
    580 			else if (keyb.leftShiftPressed) deletePatternLine();
    581 			else                            deletePatternNote();
    582 		}
    583 		break;
    584 
    585 		case SDLK_UP:
    586 		{
    587 			if (keyb.leftShiftPressed)
    588 			{
    589 				decCurIns();
    590 			}
    591 			else
    592 			{
    593 				if (keyb.leftAltPressed)
    594 					keybPattMarkUp();
    595 				else
    596 					rowOneUpWrap();
    597 			}
    598 			break;
    599 		}
    600 		break;
    601 
    602 		case SDLK_DOWN:
    603 		{
    604 			if (keyb.leftShiftPressed)
    605 			{
    606 				incCurIns();
    607 			}
    608 			else
    609 			{
    610 				if (keyb.leftAltPressed)
    611 					keybPattMarkDown();
    612 				else
    613 					rowOneDownWrap();
    614 			}
    615 		}
    616 		break;
    617 
    618 		case SDLK_PAGEUP:
    619 		{
    620 			const bool audioWasntLocked = !audio.locked;
    621 			if (audioWasntLocked)
    622 				lockAudio();
    623 
    624 			song.row -= 16;
    625 			if (song.row < 0)
    626 				song.row = 0;
    627 
    628 			if (!songPlaying)
    629 			{
    630 				editor.row = (uint8_t)song.row;
    631 				ui.updatePatternEditor = true;
    632 			}
    633 
    634 			if (audioWasntLocked)
    635 				unlockAudio();
    636 		}
    637 		break;
    638 
    639 		case SDLK_PAGEDOWN:
    640 		{
    641 			const bool audioWasntLocked = !audio.locked;
    642 			if (audioWasntLocked)
    643 				lockAudio();
    644 
    645 			song.row += 16;
    646 			if (song.row >= song.currNumRows)
    647 				song.row = song.currNumRows-1;
    648 
    649 			if (!songPlaying)
    650 			{
    651 				editor.row = (uint8_t)song.row;
    652 				ui.updatePatternEditor = true;
    653 			}
    654 
    655 			if (audioWasntLocked)
    656 				unlockAudio();
    657 		}
    658 		break;
    659 
    660 		case SDLK_HOME:
    661 		{
    662 			const bool audioWasntLocked = !audio.locked;
    663 			if (audioWasntLocked)
    664 				lockAudio();
    665 
    666 			song.row = 0;
    667 			if (!songPlaying)
    668 			{
    669 				editor.row = (uint8_t)song.row;
    670 				ui.updatePatternEditor = true;
    671 			}
    672 
    673 			if (audioWasntLocked)
    674 				unlockAudio();
    675 		}
    676 		break;
    677 
    678 		case SDLK_END:
    679 		{
    680 			const bool audioWasntLocked = !audio.locked;
    681 			if (audioWasntLocked)
    682 				lockAudio();
    683 
    684 			song.row = song.currNumRows - 1;
    685 			if (!songPlaying)
    686 			{
    687 				editor.row = (uint8_t)song.row;
    688 				ui.updatePatternEditor = true;
    689 			}
    690 
    691 			if (audioWasntLocked)
    692 				unlockAudio();
    693 		}
    694 		break;
    695 	}
    696 }
    697 
    698 static bool checkModifiedKeys(SDL_Keycode keycode)
    699 {
    700 	// normal keys
    701 	switch (keycode)
    702 	{
    703 		default: break;
    704 
    705 		case SDLK_KP_ENTER:
    706 		case SDLK_RETURN:
    707 		{
    708 			if (keyb.leftAltPressed && !keyb.leftCtrlPressed)
    709 			{
    710 				toggleFullscreen();
    711 				return true;
    712 			}
    713 			else if (keyb.leftCommandPressed || keyb.leftCtrlPressed)
    714 			{
    715 				if (keyb.leftShiftPressed)
    716 					insertPatternLine();
    717 				else
    718 					insertPatternNote();
    719 			}
    720 		}
    721 		break;
    722 
    723 		case SDLK_F9:
    724 		{
    725 			if (keyb.leftCtrlPressed)
    726 			{
    727 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[0]);
    728 				return true;
    729 			}
    730 			else if (keyb.leftShiftPressed)
    731 			{
    732 				editor.ptnJumpPos[0] = (uint8_t)editor.row;
    733 				return true;
    734 			}
    735 		}
    736 		break;
    737 
    738 		case SDLK_F10:
    739 		{
    740 			if (keyb.leftCtrlPressed)
    741 			{
    742 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[1]);
    743 				return true;
    744 			}
    745 			else if (keyb.leftShiftPressed)
    746 			{
    747 				editor.ptnJumpPos[1] = (uint8_t)editor.row;
    748 				return true;
    749 			}
    750 		}
    751 		break;
    752 
    753 		case SDLK_F11:
    754 		{
    755 			if (keyb.leftCtrlPressed)
    756 			{
    757 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[2]);
    758 				return true;
    759 			}
    760 			else if (keyb.leftShiftPressed)
    761 			{
    762 				editor.ptnJumpPos[2] = (uint8_t)editor.row;
    763 				return true;
    764 			}
    765 		}
    766 		break;
    767 
    768 		case SDLK_F12:
    769 		{
    770 			if (keyb.leftCtrlPressed)
    771 			{
    772 				startPlaying(PLAYMODE_PATT, editor.ptnJumpPos[3]);
    773 				return true;
    774 			}
    775 			else if (keyb.leftShiftPressed)
    776 			{
    777 				editor.ptnJumpPos[3] = (uint8_t)editor.row;
    778 				return true;
    779 			}
    780 		}
    781 		break;
    782 
    783 		case SDLK_a:
    784 		{
    785 			if (ui.sampleEditorShown)
    786 			{
    787 #ifdef __APPLE__
    788 				if (keyb.leftCtrlPressed || keyb.leftAltPressed || keyb.leftCommandPressed)
    789 #else
    790 				if (keyb.leftCtrlPressed || keyb.leftAltPressed)
    791 #endif
    792 				{
    793 					rangeAll();
    794 					return true;
    795 				}
    796 			}
    797 			else if (keyb.leftCtrlPressed)
    798 			{
    799 				showAdvEdit();
    800 				return true;
    801 			}
    802 			else if (keyb.leftAltPressed)
    803 			{
    804 				jumpToChannel(8);
    805 				return true;
    806 			}
    807 		}
    808 		break;
    809 
    810 		case SDLK_b:
    811 		{
    812 			if (keyb.leftCtrlPressed)
    813 			{
    814 				if (!ui.aboutScreenShown)
    815 					showAboutScreen();
    816 
    817 				return true;
    818 			}
    819 		}
    820 		break;
    821 
    822 		case SDLK_c:
    823 		{
    824 #ifdef __APPLE__
    825 			if (keyb.leftAltPressed || keyb.leftCommandPressed)
    826 #else
    827 			if (keyb.leftAltPressed)
    828 #endif
    829 			{
    830 				if (ui.sampleEditorShown)
    831 				{
    832 					sampCopy();
    833 				}
    834 				else
    835 				{
    836 					// mark current track (non-FT2 feature)
    837 					pattMark.markX1 = cursor.ch;
    838 					pattMark.markX2 = pattMark.markX1;
    839 					pattMark.markY1 = 0;
    840 					pattMark.markY2 = patternNumRows[editor.editPattern];
    841 
    842 					ui.updatePatternEditor = true;
    843 				}
    844 
    845 				return true;
    846 			}
    847 			else if (keyb.leftCtrlPressed)
    848 			{
    849 				if (ui.sampleEditorShown)
    850 					sampCopy();
    851 				else
    852 					showConfigScreen();
    853 
    854 				return true;
    855 			}
    856 		}
    857 		break;
    858 
    859 		case SDLK_d:
    860 		{
    861 			if (keyb.leftAltPressed)
    862 			{
    863 				jumpToChannel(10);
    864 				return true;
    865 			}
    866 			else if (keyb.leftCtrlPressed)
    867 			{
    868 				if (!ui.diskOpShown)
    869 					showDiskOpScreen();
    870 
    871 				return true;
    872 			}
    873 		}
    874 		break;
    875 
    876 		case SDLK_e:
    877 		{
    878 			if (keyb.leftAltPressed)
    879 			{
    880 				jumpToChannel(2);
    881 				return true;
    882 			}
    883 			else if (keyb.leftCtrlPressed)
    884 			{
    885 				if (ui.aboutScreenShown)  hideAboutScreen();
    886 				if (ui.configScreenShown) hideConfigScreen();
    887 				if (ui.helpScreenShown)   hideHelpScreen();
    888 				if (ui.nibblesShown)      hideNibblesScreen();
    889 
    890 				showSampleEditorExt();
    891 				return true;
    892 			}
    893 		}
    894 		break;
    895 
    896 		case SDLK_f:
    897 		{
    898 #ifdef __APPLE__
    899 			if (keyb.leftCommandPressed && keyb.leftCtrlPressed)
    900 			{
    901 				toggleFullscreen();
    902 				return true;
    903 			}
    904 			else
    905 #endif
    906 			if (keyb.leftShiftPressed && keyb.leftCtrlPressed)
    907 			{
    908 				resetFPSCounter();
    909 				video.showFPSCounter ^= 1;
    910 				if (!video.showFPSCounter)
    911 				{
    912 					if (ui.extendedPatternEditor) // yet another kludge...
    913 						exitPatternEditorExtended();
    914 
    915 					showTopScreen(false);
    916 				}
    917 			}
    918 			else if (keyb.leftAltPressed)
    919 			{
    920 				jumpToChannel(11);
    921 				return true;
    922 			}
    923 		}
    924 		break;
    925 
    926 		case SDLK_g:
    927 		{
    928 			if (keyb.leftAltPressed)
    929 			{
    930 				jumpToChannel(12);
    931 				return true;
    932 			}
    933 		}
    934 		break;
    935 
    936 		case SDLK_h:
    937 		{
    938 			if (keyb.leftAltPressed)
    939 			{
    940 				jumpToChannel(13);
    941 				return true;
    942 			}
    943 			else if (keyb.leftCtrlPressed)
    944 			{
    945 				showHelpScreen();
    946 				return true;
    947 			}
    948 		}
    949 		break;
    950 
    951 		case SDLK_i:
    952 		{
    953 			if (keyb.leftAltPressed)
    954 			{
    955 				jumpToChannel(7);
    956 				return true;
    957 			}
    958 			else if (keyb.leftCtrlPressed)
    959 			{
    960 				showInstEditor();
    961 				return true;
    962 			}
    963 		}
    964 		break;
    965 
    966 		case SDLK_j:
    967 		{
    968 			if (keyb.leftAltPressed)
    969 			{
    970 				jumpToChannel(14);
    971 				return true;
    972 			}
    973 		}
    974 		break;
    975 
    976 		case SDLK_k:
    977 		{
    978 			if (keyb.leftAltPressed)
    979 			{
    980 				jumpToChannel(15);
    981 				return true;
    982 			}
    983 		}
    984 		break;
    985 
    986 		case SDLK_m:
    987 		{
    988 			if (keyb.leftCtrlPressed)
    989 			{
    990 				if (ui.aboutScreenShown)  hideAboutScreen();
    991 				if (ui.configScreenShown) hideConfigScreen();
    992 				if (ui.helpScreenShown)   hideHelpScreen();
    993 				if (ui.nibblesShown)      hideNibblesScreen();
    994 
    995 				showInstEditorExt();
    996 
    997 				return true;
    998 			}
    999 		}
   1000 		break;
   1001 
   1002 		case SDLK_n:
   1003 		{
   1004 			if (keyb.leftCtrlPressed)
   1005 			{
   1006 				showNibblesScreen();
   1007 				return true;
   1008 			}
   1009 		}
   1010 		break;
   1011 
   1012 		case SDLK_p:
   1013 		{
   1014 			if (keyb.leftCtrlPressed)
   1015 			{
   1016 				if (!ui.patternEditorShown)
   1017 				{
   1018 					if (ui.sampleEditorShown)    hideSampleEditor();
   1019 					if (ui.sampleEditorExtShown) hideSampleEditorExt();
   1020 					if (ui.instEditorShown)      hideInstEditor();
   1021 
   1022 					showPatternEditor();
   1023 				}
   1024 
   1025 				return true;
   1026 			}
   1027 		}
   1028 		break;
   1029 
   1030 		case SDLK_q:
   1031 		{
   1032 			if (keyb.leftAltPressed)
   1033 			{
   1034 				jumpToChannel(0);
   1035 				return true;
   1036 			}
   1037 		}
   1038 		break;
   1039 
   1040 		case SDLK_r:
   1041 		{
   1042 			if (keyb.leftAltPressed)
   1043 			{
   1044 				if (ui.sampleEditorShown)
   1045 					sampCrop();
   1046 				else
   1047 					jumpToChannel(3);
   1048 
   1049 				return true;
   1050 			}
   1051 			else if (keyb.leftCtrlPressed)
   1052 			{
   1053 				showTrimScreen();
   1054 				return true;
   1055 			}
   1056 		}
   1057 		break;
   1058 
   1059 		case SDLK_s:
   1060 		{
   1061 			if (keyb.leftAltPressed)
   1062 			{
   1063 				if (ui.sampleEditorShown)
   1064 					showRange();
   1065 				else
   1066 					jumpToChannel(9);
   1067 
   1068 				return true;
   1069 			}
   1070 			else if (keyb.leftCtrlPressed)
   1071 			{
   1072 				showSampleEditor();
   1073 				return true;
   1074 			}
   1075 		}
   1076 		break;
   1077 
   1078 		case SDLK_t:
   1079 		{
   1080 			if (keyb.leftAltPressed)
   1081 			{
   1082 				jumpToChannel(4);
   1083 				return true;
   1084 			}
   1085 			else if (keyb.leftCtrlPressed)
   1086 			{
   1087 				showTranspose();
   1088 				return true;
   1089 			}
   1090 		}
   1091 		break;
   1092 
   1093 		case SDLK_u:
   1094 		{
   1095 			if (keyb.leftAltPressed)
   1096 			{
   1097 				jumpToChannel(6);
   1098 				return true;
   1099 			}
   1100 		}
   1101 		break;
   1102 
   1103 		case SDLK_v:
   1104 		{
   1105 #ifdef __APPLE__
   1106 			if (keyb.leftAltPressed || keyb.leftCommandPressed)
   1107 #else
   1108 			if (keyb.leftAltPressed)
   1109 #endif
   1110 			{
   1111 				if (ui.sampleEditorShown)
   1112 					sampPaste();
   1113 				else if (!ui.instEditorShown)
   1114 					scaleFadeVolumeBlock();
   1115 
   1116 				return true;
   1117 			}
   1118 			else if (keyb.leftCtrlPressed)
   1119 			{
   1120 				if (ui.sampleEditorShown)
   1121 					sampPaste();
   1122 				else if (!ui.instEditorShown)
   1123 					scaleFadeVolumePattern();
   1124 
   1125 				return true;
   1126 			}
   1127 			else if (keyb.leftShiftPressed)
   1128 			{
   1129 				if (!ui.sampleEditorShown && !ui.instEditorShown)
   1130 				{
   1131 					keyb.ignoreTextEditKey = true; // ignore key from first frame
   1132 					scaleFadeVolumeTrack();
   1133 				}
   1134 
   1135 				return true;
   1136 			}
   1137 		}
   1138 		break;
   1139 
   1140 		case SDLK_w:
   1141 		{
   1142 			if (keyb.leftAltPressed)
   1143 			{
   1144 				jumpToChannel(1);
   1145 				return true;
   1146 			}
   1147 		}
   1148 		break;
   1149 
   1150 		case SDLK_x:
   1151 		{
   1152 #ifdef __APPLE__
   1153 			if (keyb.leftAltPressed || keyb.leftCommandPressed)
   1154 #else
   1155 			if (keyb.leftAltPressed)
   1156 #endif
   1157 			{
   1158 				if (ui.sampleEditorShown)
   1159 					sampCut();
   1160 
   1161 				return true;
   1162 			}
   1163 			else if (keyb.leftCtrlPressed)
   1164 			{
   1165 				if (ui.extendedPatternEditor)
   1166 					exitPatternEditorExtended();
   1167 
   1168 				if (ui.sampleEditorShown)    hideSampleEditor();
   1169 				if (ui.sampleEditorExtShown) hideSampleEditorExt();
   1170 				if (ui.instEditorShown)      hideInstEditor();
   1171 				if (ui.instEditorExtShown)   hideInstEditorExt();
   1172 				if (ui.transposeShown)       hideTranspose();
   1173 				if (ui.aboutScreenShown)     hideAboutScreen();
   1174 				if (ui.configScreenShown)    hideConfigScreen();
   1175 				if (ui.helpScreenShown)      hideHelpScreen();
   1176 				if (ui.nibblesShown)         hideNibblesScreen();
   1177 				if (ui.diskOpShown)          hideDiskOpScreen();
   1178 				if (ui.advEditShown)         hideAdvEdit();
   1179 				if (ui.wavRendererShown)     hideWavRenderer();
   1180 				if (ui.trimScreenShown)      hideTrimScreen();
   1181 
   1182 				showTopScreen(false);
   1183 				showBottomScreen();
   1184 
   1185 				showPatternEditor();
   1186 
   1187 				return true;
   1188 			}
   1189 		}
   1190 		break;
   1191 
   1192 		case SDLK_y:
   1193 		{
   1194 			if (keyb.leftAltPressed)
   1195 			{
   1196 				jumpToChannel(5);
   1197 				return true;
   1198 			}
   1199 		}
   1200 		break;
   1201 
   1202 		case SDLK_z:
   1203 		{
   1204 			if (keyb.leftAltPressed)
   1205 			{
   1206 				if (ui.sampleEditorShown)
   1207 					zoomOut();
   1208 
   1209 				return true;
   1210 			}
   1211 			else if (keyb.leftCtrlPressed)
   1212 			{
   1213 				togglePatternEditorExtended();
   1214 				return true;
   1215 			}
   1216 		}
   1217 		break;
   1218 
   1219 		case SDLK_1:
   1220 		{
   1221 			if (keyb.leftAltPressed)
   1222 			{
   1223 				if (keyb.leftShiftPressed)
   1224 					writeToMacroSlot(1-1);
   1225 				else
   1226 					writeFromMacroSlot(1-1);
   1227 
   1228 				return true;
   1229 			}
   1230 			else if (keyb.leftCtrlPressed)
   1231 			{
   1232 				editor.currConfigScreen = 0;
   1233 				showConfigScreen();
   1234 				checkRadioButton(RB_CONFIG_AUDIO);
   1235 
   1236 				return true;
   1237 			}
   1238 		}
   1239 		break;
   1240 
   1241 		case SDLK_2:
   1242 		{
   1243 			if (keyb.leftAltPressed)
   1244 			{
   1245 				if (keyb.leftShiftPressed)
   1246 					writeToMacroSlot(2-1);
   1247 				else
   1248 					writeFromMacroSlot(2-1);
   1249 
   1250 				return true;
   1251 			}
   1252 			else if (keyb.leftCtrlPressed)
   1253 			{
   1254 				editor.currConfigScreen = 1;
   1255 				showConfigScreen();
   1256 				checkRadioButton(RB_CONFIG_LAYOUT);
   1257 
   1258 				return true;
   1259 			}
   1260 		}
   1261 		break;
   1262 
   1263 		case SDLK_3:
   1264 		{
   1265 			if (keyb.leftAltPressed)
   1266 			{
   1267 				if (keyb.leftShiftPressed)
   1268 					writeToMacroSlot(3-1);
   1269 				else
   1270 					writeFromMacroSlot(3-1);
   1271 
   1272 				return true;
   1273 			}
   1274 			else if (keyb.leftCtrlPressed)
   1275 			{
   1276 				editor.currConfigScreen = 2;
   1277 				showConfigScreen();
   1278 				checkRadioButton(RB_CONFIG_MISCELLANEOUS);
   1279 
   1280 				return true;
   1281 			}
   1282 		}
   1283 		break;
   1284 
   1285 		case SDLK_4:
   1286 		{
   1287 			if (keyb.leftAltPressed)
   1288 			{
   1289 				if (keyb.leftShiftPressed)
   1290 					writeToMacroSlot(4-1);
   1291 				else
   1292 					writeFromMacroSlot(4-1);
   1293 
   1294 				return true;
   1295 			}
   1296 			else if (keyb.leftCtrlPressed)
   1297 			{
   1298 #ifdef HAS_MIDI
   1299 				editor.currConfigScreen = 3;
   1300 				showConfigScreen();
   1301 				checkRadioButton(RB_CONFIG_MIDI_INPUT);
   1302 #endif
   1303 				return true;
   1304 			}
   1305 		}
   1306 		break;
   1307 
   1308 		case SDLK_5:
   1309 		{
   1310 			if (keyb.leftAltPressed)
   1311 			{
   1312 				if (keyb.leftShiftPressed)
   1313 					writeToMacroSlot(5-1);
   1314 				else
   1315 					writeFromMacroSlot(5-1);
   1316 
   1317 				return true;
   1318 			}
   1319 		}
   1320 		break;
   1321 
   1322 		case SDLK_6:
   1323 		{
   1324 			if (keyb.leftAltPressed)
   1325 			{
   1326 				if (keyb.leftShiftPressed)
   1327 					writeToMacroSlot(6-1);
   1328 				else
   1329 					writeFromMacroSlot(6-1);
   1330 
   1331 				return true;
   1332 			}
   1333 		}
   1334 		break;
   1335 
   1336 		case SDLK_7:
   1337 		{
   1338 			if (keyb.leftAltPressed)
   1339 			{
   1340 				if (keyb.leftShiftPressed)
   1341 					writeToMacroSlot(7-1);
   1342 				else
   1343 					writeFromMacroSlot(7-1);
   1344 
   1345 				return true;
   1346 			}
   1347 		}
   1348 		break;
   1349 
   1350 		case SDLK_8:
   1351 		{
   1352 			if (keyb.leftAltPressed)
   1353 			{
   1354 				if (keyb.leftShiftPressed)
   1355 					writeToMacroSlot(8-1);
   1356 				else
   1357 					writeFromMacroSlot(8-1);
   1358 
   1359 				return true;
   1360 			}
   1361 		}
   1362 		break;
   1363 
   1364 		case SDLK_9:
   1365 		{
   1366 			if (keyb.leftAltPressed)
   1367 			{
   1368 				if (keyb.leftShiftPressed)
   1369 					writeToMacroSlot(9-1);
   1370 				else
   1371 					writeFromMacroSlot(9-1);
   1372 
   1373 				return true;
   1374 			}
   1375 		}
   1376 		break;
   1377 
   1378 		case SDLK_0:
   1379 		{
   1380 			if (keyb.leftAltPressed)
   1381 			{
   1382 				if (keyb.leftShiftPressed)
   1383 					writeToMacroSlot(10-1);
   1384 				else
   1385 					writeFromMacroSlot(10-1);
   1386 
   1387 				return true;
   1388 			}
   1389 		}
   1390 		break;
   1391 
   1392 		case SDLK_LEFT:
   1393 		{
   1394 			if (keyb.leftShiftPressed)
   1395 			{
   1396 				decSongPos();
   1397 				return true;
   1398 			}
   1399 			else if (keyb.leftCtrlPressed)
   1400 			{
   1401 				pbEditPattDown();
   1402 				return true;
   1403 			}
   1404 			else if (keyb.leftAltPressed)
   1405 			{
   1406 				keybPattMarkLeft();
   1407 				return true;
   1408 			}
   1409 		}
   1410 		break;
   1411 
   1412 		case SDLK_RIGHT:
   1413 		{
   1414 			if (keyb.leftShiftPressed)
   1415 			{
   1416 				incSongPos();
   1417 				return true;
   1418 			}
   1419 			else if (keyb.leftCtrlPressed)
   1420 			{
   1421 				pbEditPattUp();
   1422 				return true;
   1423 			}
   1424 			else if (keyb.leftAltPressed)
   1425 			{
   1426 				keybPattMarkRight();
   1427 				return true;
   1428 			}
   1429 		}
   1430 		break;
   1431 	}
   1432 
   1433 	return false;
   1434 }