Example #1
0
void viewTOTPcode(totp* tkn) {
  unsigned short key = 0; int keyCol, keyRow;
  Bdisp_AllClr_VRAM();
  drawScreenTitle(tkn->name);
  int shown_since_beginning = 0;
  while(key != KEY_PRGM_EXIT && key != KEY_PRGM_LEFT) {
    int ThirtySecCode = computeTOTP(tkn);
    char buffer[10];
    itoa_zeropad(tkn->totpcode, buffer, 6);
    long long int ms_spent_ll = currentUTCUEBT() - (long long int)ThirtySecCode * 30LL * 1000LL;
    int ms_spent = (int)(ms_spent_ll);

    drawCircularCountdownIndicator(LCD_WIDTH_PX/2, 104, 44, COLOR_BLACK, COLOR_WHITE,
                                   (ms_spent*43)/30000, getCurrentSecond() < 30 ? 0 : 1);
    // fade in/out animation for text
    int val = 0;
    if(ms_spent >= 29000) {
      val += (-29000 + ms_spent)/4;
    } else if (ms_spent <= 1020) {
      val += (1020 - ms_spent)/4;
    }
    int color = drawRGB24toRGB565(val, val, val);
    printCentered(buffer, 164, color, COLOR_WHITE);
    if(ms_spent < 2500) shown_since_beginning = 1;
    else if(ms_spent < 15000 && shown_since_beginning)
      DefineStatusMessage((char*)totpHelpMessages[(ms_spent-2500)/2500], 1, 0, 0);
    else
      DefineStatusMessage((char*)"", 1, 0, 0);
    DisplayStatusArea();
    Bdisp_PutDisp_DD();
    key = PRGM_GetKey();
    if(key == KEY_PRGM_MENU)
      GetKeyWait_OS(&keyCol, &keyRow, 2, 0, 0, &key); //this is here to handle the Menu key
    if(key == KEY_PRGM_OPTN) {
      DefineStatusMessage((char*)"", 1, 0, 0);
      GetKeyWait_OS(&keyCol, &keyRow, 2, 0, 0, &key); // clear keybuffer
      RTCunadjustedWizard(0, 1);
      setTimezone();
      return; // so we don't have to redraw etc.
      // Also, this way the Shift+Menu instruction shown in the adjustment wizard becomes vali
      // immediately, which is great if the user wants to repeat the adjustment.
    }
  }
  DefineStatusMessage((char*)"", 1, 0, 0);
  // clear keybuffer:
  GetKeyWait_OS(&keyCol, &keyRow, 2, 0, 0, &key);
}
Example #2
0
File: main.c Project: ExAcler/Prizm
void browse_main()
{
    /*
	    文件浏览器主函数
	*/

    char ncat[64], workdir[64] = "\\\\fls0";    //  当前目录
    f_name *a=get_file_list("\\\\fls0\\*.*");    //  存储文件列表的二维数组
	int pos=0,firstn=0;    //  列表光标位置、列表下移的行数
	unsigned int key;
	char subdir_fn[32];    //  供接收子目录文件名输入的缓冲区
	FONTCHARACTER fname[64];
	int handle = 0;
	
	DefineStatusAreaFlags(3, 0x01 | 0x02 | 0x100, 0, 0);
	
	beg:
	if (a) qsort(a, getn(a), sizeof(char *), cmp);
	
	font16 = open_font("\\\\fls0\\24PX.hzk");
	select_font(font16);
	
	draw_browser(workdir,firstn,pos,a);    //  绘制浏览器界面
	
	close_font(font16);
	
	//  显示当前工作目录于状态栏
	if (strcmp(workdir, "\\\\fls0") == 0)
		DefineStatusMessage("", 0, 0, 0);
	else
	{
		memset(ncat, 0, sizeof(ncat));
		GetDisplayDirName(workdir, ncat);
		DefineStatusMessage(ncat, 0, 0, 0);
	}
	
	while (1)
	{
	    GetKey(&key);
		switch (key)
		{
		    case KEY_CTRL_UP:    //  光标上移
			    if (a)
				{
				    aa(&pos,&firstn,getn(a));
					goto beg;
				}
				break;
				
			case KEY_CTRL_DOWN:    //  光标下移
			    if (a)
				{
				    bb(&pos,&firstn,getn(a));
					goto beg;
				}
				break;
			
			case KEY_CTRL_F6:    //  显示关于信息
			    Disp_About();
				goto beg;
				break;
			
			case KEY_CTRL_F1:    //  打开光标位置的文件
			case KEY_CTRL_EXE:
			    if (a)    //  如果文件列表不为空
			    {
			        if (strchr(a[pos+firstn].name,'['))    //  如果打开的是文件夹
				    {
				        memset(ncat,0,sizeof(ncat));
					    //strcat(ncat,"\\\\fls0\\");
						strcat(ncat, workdir); strcat(ncat, "\\");
				        strcat(ncat, ++a[pos+firstn].name);
					    memset(workdir, 0, sizeof(workdir));
					    strcpy(workdir, ncat);
					    strcat(ncat, "\\*.*");    //  解析出文件夹名称
					    a=get_file_list(ncat);    //  浏览该文件夹
						pos=0; firstn=0;    //  列表初始化
					    goto beg;
				    }
				    else    //  如果打开的是文本文件
				    {	
						memset(ncat,0,sizeof(ncat));
				        strcpy(ncat,workdir);
						strcat(ncat,"\\");
				        strcat(ncat,a[pos+firstn].name);    //  解析出文件名称
						
						iRead_main(ncat);    //  启动阅读器
						goto beg;
				    }
				}
				break;
				
			case KEY_CTRL_F2:	//  根据输入的文件名打开文件
				memset(subdir_fn, 0, sizeof(subdir_fn));
				if (Subdir_Open(subdir_fn))
				{
					memset(ncat, 0, sizeof(ncat));
				    strcpy(ncat, workdir);
					strcat(ncat, "\\");
				    strcat(ncat, subdir_fn);    //  连接上输入的文件名字
					strcat(ncat, ".txt");
						
					char_to_font(ncat, fname);
					handle = Bfile_OpenFile_OS(fname,0);
					if (handle <= 0)    //  如果文件未找到
					{
						Disp_FileNotFound();
						MsgBoxPop();
						goto beg; break;
					}
						
					MsgBoxPop();
					Bfile_CloseFile_OS(handle);
					
					//  重新绘制浏览器界面
					font16 = open_font("\\\\fls0\\24PX.hzk");
					select_font(font16);
	
					draw_browser(workdir, firstn, pos, a);
					close_font(font16);
					
					//  启动阅读器
					iRead_main(ncat);
				}
				
				goto beg; break;
			
			case KEY_CTRL_EXIT:    //  从文件夹返回根目录
			    if (strcmp(workdir,"\\\\fls0")!=0)    //  如果当前在文件夹内
			    {
			        memset(ncat,0,sizeof(ncat));
			        strncpy(ncat,workdir,strlen(workdir)-strlen(strrchr(workdir,'\\')));
				    memset(workdir,0,sizeof(workdir));
				    strcpy(workdir,ncat);
				    strcat(ncat,"\\*.*");    //  解析出上一级目录的名称
			        a=get_file_list(ncat);    //  浏览该文件夹
					pos=0;firstn=0;    //  初始化列表
				    goto beg;
				
				}
				break;
			
		}
	}
}
Example #3
0
File: main.c Project: ExAcler/Prizm
void iRead_main(const char* filename)
{
    /*
	    阅读界面主函数
		参数说明:
		    filename: 打开的文件名 (从文件浏览器得到)
	*/

    int key,handle;
	char* buf=(char*)malloc(461);
	FONTCHARACTER fname[64];
	
	char tip[64], tmp[64];
	
	page=0;cached=0;
	
	memset(bytes,0,sizeof(bytes));
	memset(bookmark,0,sizeof(bookmark));bookmark[3]=0;
	
	Read_Config(filename,&cached);    //  读取书签及分页配置
	
	//  如果分的页数不满 500 的整数倍,补分页满
	if (cached==0) divide_page(filename,500-cached,1);
	else
	    if (cached%500!=0) divide_page(filename,500-cached%500,1);   // 补至 500 的整数倍
	totbytes=0;
	
	/*  设置状态栏显示文字
		0x0001:显示电量
		0x0100:显示文字
	*/
	DefineStatusAreaFlags(3, 0x01 | 0x02 | 0x100, 0, 0);
	
	beg:
	font16=open_font("\\\\fls0\\24PX.hzk");
	select_font(font16);
	
	Bdisp_AllClr_VRAM();
    draw_pic(0,192,124,22,0,Menu_Read);
	draw_pic(126,192,61,22,0,Menu_Sub_Jump);
	
	//  若翻下一页时超出已缓存页面范围
	if (cached<=page)
	{
	    //  如果分的页数不满 500 的整数倍,补分页满
	    if (!divide_page(filename,1,0)) page=cached-1;
	    else if (cached%500!=0) divide_page(filename,500-cached%500,0);
		
		close_font(font16);
		goto beg;
	}
	totbytes=bytes[page];    //  修正读取字节指针位置
	
	char_to_font(filename,fname);
	handle=Bfile_OpenFile_OS(fname,0);    //  打开文件
	
	Bfile_ReadFile_OS(handle,buf,400,totbytes);
	Bfile_CloseFile_OS(handle);
	
	print_chs_page(0,24,totbytes,(unsigned char*)buf);    //  绘制一页
    close_font(font16);
	
	//  准备显示浏览进度
	char fn_ptr[64];
	memset(fn_ptr, 0, sizeof(fn_ptr));
	GetDisplayFileName(filename, fn_ptr);
	
	memset(tip, 0, sizeof(tip));
	memset(tmp, 0, sizeof(tmp));
	strcat(tip, fn_ptr); strcat(tip, " ");
	itoa(page + 1, tmp, 10); strcat(tip, tmp);
    strcat(tip, "/"); memset(tmp, 0, sizeof(tmp));
	itoa(cached, tmp, 10);strcat(tip, tmp);
	
	//  状态栏显示文件名及进度
	DefineStatusMessage(tip, 0, 0, 0);
	
	while (1)
	{
	    GetKey(&key);
	    switch (key)
		{
		    case KEY_CTRL_UP:    //  跳到上一页
			    if (page>0)
				{
			        --page;
				    goto beg;
				}
				break;
				
		    case KEY_CTRL_DOWN:    //  跳到下一页
			    ++page;
			    goto beg;
				break;
				
			case KEY_CTRL_EXIT:    //  离开,返回文件浏览器
			    Save_Config(filename,cached+1);
				DefineStatusAreaFlags(3, 0x01 | 0x02 | 0x100, 0, 0);
			    return;break;
				
			case KEY_CTRL_F2:    //  打开存储书签对话框
			    Save_Bookmark(filename,page,cached+1);
				goto beg;break;
				
			case KEY_CTRL_F1:    //  打开读取书签对话框
			    Read_Bookmark(filename,&page,&cached);
				goto beg;break;
				
			case KEY_CTRL_F3:    //  打开跳页对话框
			    Page_Jump(filename);
				goto beg;break;
		}
 	}
}
Example #4
0
void input_eval_loop(int isRecording) {
  char** recHistory = NULL; int curRecHistEntry = 0;
  if(isRecording) recHistory = (char**)alloca(200); // space for 200 pointers to history entries
  while (1) {
    DefineStatusMessage((char*)"", 1, 0, 0);
    strcpy(expr, (char*)"");
    printf("\x1e");
    dConsoleRedraw();
    int res = gets(expr,INPUTBUFLEN);
    if(res == 2) {
      dConsolePut("\n");
      select_script_and_run();
      continue;
    }
    if(res == 4) {
      dConsolePut("\n");
      select_strip_script();
      continue;
    }
    if(res == 3) {
      dConsolePut("\n");
      char buf[100] = "";
      sprintf(buf, "prizmUIkeyHandler(%d,%d)", custom_key_to_handle, custom_key_to_handle_modifier);
      strcpy(expr, (char*)buf);
      execution_in_progress = 1;
      run(buf);
      execution_in_progress = 0;
      check_do_graph();
      if(run_startup_script_again) { run_startup_script_again = 0; run_startup_script(); }
      continue;
    }
    puts(expr);
    update_cmd_history(expr);
    dConsoleRedraw();
    if(strcmp(expr, "testmode") == 0) {
      TestMode(1);
    } else if(strcmp(expr, "meminfo") == 0) {
      print_mem_info();
    } else if(strcmp(expr, "memgc") == 0) {
      gc();
    } else if(strcmp(expr, "record") == 0) {
      if(!isRecording) script_recorder();
      else {
        // create and save a script. this must be done here, because we used alloca
        // the "clean" way would be using malloc&free, but on the Prizm the heap is already being heavily used by the Eigenmath core.
        if(curRecHistEntry == 0) {
          printf("Nothing to record.\n");
          return;
        }
        printf("Recording stopped.\n");
        printf("Type a name for the script, or\n");
        printf("leave empty to discard.\n:");
        char inputname[MAX_FILENAME_SIZE+1] = "";
        gets(inputname,MAX_FILENAME_SIZE-50);
        puts(inputname);
        if(!strlen(inputname)) {
          // user aborted
          printf("Recording discarded.\n");
          return;
        }
        if (aborttimer > 0) {
          Timer_Stop(aborttimer);
          Timer_Deinstall(aborttimer);
        }
        char filename[MAX_FILENAME_SIZE+1] = "";
        sprintf(filename, "\\\\fls0\\%s.txt", inputname);
        unsigned short pFile[MAX_FILENAME_SIZE+1];
        Bfile_StrToName_ncpy(pFile, (unsigned char*)filename, strlen(filename)+1);
        // calculate size
        int size = 0;
        int maxHistory = curRecHistEntry - 1; //because we ++'ed at the end of last addition
        for(int i=0; i <= maxHistory; i++) {
          size = size + strlen(recHistory[i]) + 1; // 1 byte for \n. we will use unix line termination
        }
        int BCEres = Bfile_CreateEntry_OS(pFile, CREATEMODE_FILE, &size);
        if(BCEres >= 0) // Did it create?
        {
          BCEres = Bfile_OpenFile_OS(pFile, READWRITE, 0); // Get handle
          for(int i=0; i <= maxHistory; i++) {
            char* buf = (char*)alloca(strlen(recHistory[i])+5);
            strcpy(buf, recHistory[i]);
            strcat(buf, (char*)"\n");
            Bfile_WriteFile_OS(BCEres, buf, strlen(recHistory[i])+1);
          }
          Bfile_CloseFile_OS(BCEres);
          printf("Script created.\n");
        } else {
          printf("An error occurred when creating the script for recording.\n");
        }
        aborttimer = Timer_Install(0, check_execution_abort, 100);
        if (aborttimer > 0) Timer_Start(aborttimer);
        return;
      }
    } else {
      execution_in_progress = 1;
      has_drawn_graph = 0;
      run(expr);
      // run_startup_script cannot run from inside eval_clear because then it would be a run() inside a run()
      if(run_startup_script_again) { run_startup_script_again = 0; run_startup_script(); }
      execution_in_progress = 0;
      
      // if recording, add input to record
      if(isRecording && curRecHistEntry <= 200) {
        recHistory[curRecHistEntry] = (char*)alloca(strlen(expr)+2); // 2 bytes for security
        strcpy(recHistory[curRecHistEntry], expr);
        curRecHistEntry++;
      }
      check_do_graph();
    }
  }
}
Example #5
0
int doMenu(Menu* menu, MenuItemIcon* icontable) { // returns code telling what user did. selection is on menu->selection. menu->selection starts at 1!
  int itemsStartY=menu->startY; // char Y where to start drawing the menu items. Having a title increases this by one
  int itemsHeight=menu->height;
  int showtitle = menu->title != NULL;
  if (showtitle) {
    itemsStartY++;
    itemsHeight--;
  }

  if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
    menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
  if(menu->selection-1 < menu->scroll)
    menu->scroll = menu->selection -1;
  
  while(1) {
    if(menu->statusText != NULL) DefineStatusMessage(menu->statusText, 1, 0, 0);
    // Clear the area of the screen we are going to draw on
    if(0 == menu->pBaRtR) drawRectangle(18*(menu->startX-1), 24*(menu->miniMiniTitle ? itemsStartY:menu->startY), 18*menu->width+(menu->scrollbar && menu->scrollout?6:0), 24*menu->height-(menu->miniMiniTitle ? 24:0), COLOR_WHITE);
    if (menu->numitems>0) {
      for(int curitem=0; curitem < menu->numitems; curitem++) {
        // print the menu item only when appropriate
        if(menu->scroll < curitem+1 && menu->scroll > curitem-itemsHeight) {
          char menuitem[70] = "";
          if(menu->type == MENUTYPE_MULTISELECT) strcpy(menuitem, "  "); //allow for the folder and selection icons on MULTISELECT menus (e.g. file browser)
          strncat(menuitem, menu->items[curitem].text, 68);
          if(menu->items[curitem].type != MENUITEM_SEPARATOR) {
            //make sure we have a string big enough to have background when item is selected:          
            // MB_ElementCount is used instead of strlen because multibyte chars count as two with strlen, while graphically they are just one char, making fillerRequired become wrong
            int fillerRequired = menu->width - MB_ElementCount(menu->items[curitem].text) - (menu->type == MENUTYPE_MULTISELECT ? 2 : 0);
            for(int i = 0; i < fillerRequired; i++) strcat(menuitem, " ");
            mPrintXY(menu->startX,curitem+itemsStartY-menu->scroll,(char*)menuitem, (menu->selection == curitem+1 ? TEXT_MODE_INVERT : TEXT_MODE_TRANSPARENT_BACKGROUND), menu->items[curitem].color);
          } else {
            /*int textX = (menu->startX-1) * 18;
            int textY = curitem*24+itemsStartY*24-menu->scroll*24-24+6;
            clearLine(menu->startX, curitem+itemsStartY-menu->scroll, (menu->selection == curitem+1 ? textColorToFullColor(menu->items[curitem].color) : COLOR_WHITE));
            drawLine(textX, textY+24-4, LCD_WIDTH_PX-2, textY+24-4, COLOR_GRAY);
            PrintMini(&textX, &textY, (unsigned char*)menuitem, 0, 0xFFFFFFFF, 0, 0, (menu->selection == curitem+1 ? COLOR_WHITE : textColorToFullColor(menu->items[curitem].color)), (menu->selection == curitem+1 ? textColorToFullColor(menu->items[curitem].color) : COLOR_WHITE), 1, 0);*/
          }
          // deal with menu items of type MENUITEM_CHECKBOX
          if(menu->items[curitem].type == MENUITEM_CHECKBOX) {
            mPrintXY(menu->startX+menu->width-1,curitem+itemsStartY-menu->scroll,
              (menu->items[curitem].value == MENUITEM_VALUE_CHECKED ? (char*)"\xe6\xa9" : (char*)"\xe6\xa5"),
              (menu->selection == curitem+1 ? TEXT_MODE_INVERT : (menu->pBaRtR == 1? TEXT_MODE_TRANSPARENT_BACKGROUND : TEXT_MODE_NORMAL)), menu->items[curitem].color);
          }
          // deal with multiselect menus
          if(menu->type == MENUTYPE_MULTISELECT) {
            if((curitem+itemsStartY-menu->scroll)>=itemsStartY &&
              (curitem+itemsStartY-menu->scroll)<=(itemsStartY+itemsHeight) &&
              icontable != NULL
            ) {
              if (menu->items[curitem].isfolder == 1) {
                // assumes first icon in icontable is the folder icon
                CopySpriteMasked(icontable[0].data, (menu->startX)*18, (curitem+itemsStartY-menu->scroll)*24, 0x12, 0x18, 0xf81f  );
              } else {
                if(menu->items[curitem].icon >= 0) CopySpriteMasked(icontable[menu->items[curitem].icon].data, (menu->startX)*18, (curitem+itemsStartY-menu->scroll)*24, 0x12, 0x18, 0xf81f  );
              }
            }
            if (menu->items[curitem].isselected) {
              if (menu->selection == curitem+1) {
                mPrintXY(menu->startX,curitem+itemsStartY-menu->scroll,(char*)"\xe6\x9b", TEXT_MODE_TRANSPARENT_BACKGROUND, (menu->items[curitem].color ==  TEXT_COLOR_GREEN ? TEXT_COLOR_BLUE : TEXT_COLOR_GREEN));
              } else {
                mPrintXY(menu->startX,curitem+itemsStartY-menu->scroll,(char*)"\xe6\x9b", TEXT_MODE_NORMAL, TEXT_COLOR_PURPLE);
              }
            }
          }
        }
      }
      if (menu->scrollbar) {
        TScrollbar sb;
        sb.I1 = 0;
        sb.I5 = 0;
        sb.indicatormaximum = menu->numitems;
        sb.indicatorheight = itemsHeight;
        sb.indicatorpos = menu->scroll;
        sb.barheight = itemsHeight*24;
        sb.bartop = (itemsStartY-1)*24;
        sb.barleft = menu->startX*18+menu->width*18 - 18 - (menu->scrollout ? 0 : 5);
        sb.barwidth = 6;
        Scrollbar(&sb);
      }
      //if(menu->type==MENUTYPE_MULTISELECT && menu->fkeypage == 0) drawFkeyLabels(0x0037); // SELECT (white)
    } else {
      printCentered((unsigned char*)menu->nodatamsg, (itemsStartY*24)+(itemsHeight*24)/2-12, COLOR_BLACK, COLOR_WHITE);
    }
    if(showtitle) {
      if(menu->miniMiniTitle) {
        int textX = 0, textY=(menu->startY-1)*24;
        PrintMiniMini( &textX, &textY, (unsigned char*)menu->title, 16, menu->titleColor, 0 );
      } else mPrintXY(menu->startX, menu->startY, menu->title, TEXT_MODE_TRANSPARENT_BACKGROUND, menu->titleColor);
      if(menu->subtitle != NULL) {
        int textX=(MB_ElementCount(menu->title)+menu->startX-1)*18+10, textY=6;
        PrintMini(&textX, &textY, (unsigned char*)menu->subtitle, 0, 0xFFFFFFFF, 0, 0, COLOR_BLACK, COLOR_WHITE, 1, 0);
      }
    }
    /*if(menu->darken) {
      DrawFrame(COLOR_BLACK);
      VRAMInvertArea(menu->startX*18-18, menu->startY*24, menu->width*18-(menu->scrollout || !menu->scrollbar ? 0 : 5), menu->height*24);
    }*/
    if(menu->type == MENUTYPE_NO_KEY_HANDLING) return MENU_RETURN_INSTANT; // we don't want to handle keys
    int key;
    GetKey(&key);
    switch(key) {
      case KEY_CTRL_DOWN:
        if(menu->selection == menu->numitems)
        {
          if(menu->returnOnInfiniteScrolling) {
            return MENU_RETURN_SCROLLING;
          } else {
            menu->selection = 1;
            menu->scroll = 0;
          }
        }
        else
        {
          menu->selection++;
          if(menu->selection > menu->scroll+(menu->numitems>itemsHeight ? itemsHeight : menu->numitems))
            menu->scroll = menu->selection -(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
        }
        if(menu->pBaRtR==1) return MENU_RETURN_INSTANT;
        break;
      case KEY_CTRL_UP:
        if(menu->selection == 1)
        {
          if(menu->returnOnInfiniteScrolling) {
            return MENU_RETURN_SCROLLING;
          } else {
            menu->selection = menu->numitems;
            menu->scroll = menu->selection-(menu->numitems>itemsHeight ? itemsHeight : menu->numitems);
          }
        }
        else
        {
          menu->selection--;
          if(menu->selection-1 < menu->scroll)
            menu->scroll = menu->selection -1;
        }
        if(menu->pBaRtR==1) return MENU_RETURN_INSTANT;
        break;
      case KEY_CTRL_F1:
        if(menu->type==MENUTYPE_MULTISELECT && menu->fkeypage == 0 && menu->numitems > 0) {
          /*if(menu->items[menu->selection-1].isselected) {
            menu->items[menu->selection-1].isselected=0;
            menu->numselitems = menu->numselitems-1;
          } else {
            menu->items[menu->selection-1].isselected=1;
            menu->numselitems = menu->numselitems+1;
          }
          return key; //return on F1 too so that parent subroutines have a chance to e.g. redraw fkeys*/
        } else if (menu->type == MENUTYPE_FKEYS) {
          return key;
        }
        break;
      case KEY_CTRL_F2:
      case KEY_CTRL_F3:
      case KEY_CTRL_F4:
      case KEY_CTRL_F5:
      case KEY_CTRL_F6:
        if (menu->type == MENUTYPE_FKEYS || menu->type==MENUTYPE_MULTISELECT) return key; // MULTISELECT also returns on Fkeys
        break;
      case KEY_CTRL_PASTE:
        if (menu->type==MENUTYPE_MULTISELECT) return key; // MULTISELECT also returns on paste
      case KEY_CTRL_OPTN:
        if (menu->type==MENUTYPE_FKEYS || menu->type==MENUTYPE_MULTISELECT) return key;
        break;
      case KEY_CTRL_FORMAT:
        if (menu->type==MENUTYPE_FKEYS) return key; // return on the Format key so that event lists can prompt to change event category
        break;
      case KEY_CTRL_RIGHT:
        if(menu->type != MENUTYPE_MULTISELECT) break;
        // else fallthrough
      case KEY_CTRL_EXE:
        if(menu->numitems>0) return MENU_RETURN_SELECTION;
        break;
      case KEY_CTRL_LEFT:
        if(menu->type != MENUTYPE_MULTISELECT) break;
        // else fallthrough
      case KEY_CTRL_EXIT: return MENU_RETURN_EXIT;
        break;
      case KEY_CHAR_1:
      case KEY_CHAR_2:
      case KEY_CHAR_3:
      case KEY_CHAR_4:
      case KEY_CHAR_5:
      case KEY_CHAR_6:
      case KEY_CHAR_7:
      case KEY_CHAR_8:
      case KEY_CHAR_9:
        if(menu->numitems>=(key-0x30)) {menu->selection = (key-0x30); return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_0:
        if(menu->numitems>=10) {menu->selection = 10; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CTRL_XTT:
        if(menu->numitems>=11) {menu->selection = 11; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_LOG:
        if(menu->numitems>=12) {menu->selection = 12; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_LN:
        if(menu->numitems>=13) {menu->selection = 13; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_SIN:
      case KEY_CHAR_COS:
      case KEY_CHAR_TAN:
        if(menu->numitems>=(key-115)) {menu->selection = (key-115); return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_FRAC:
        if(menu->numitems>=17) {menu->selection = 17; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CTRL_FD:
        if(menu->numitems>=18) {menu->selection = 18; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_LPAR:
      case KEY_CHAR_RPAR:
        if(menu->numitems>=(key-21)) {menu->selection = (key-21); return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_COMMA:
        if(menu->numitems>=21) {menu->selection = 21; return MENU_RETURN_SELECTION; }
        break;
      case KEY_CHAR_STORE:
        if(menu->numitems>=22) {menu->selection = 22; return MENU_RETURN_SELECTION; }
        break;
    }
  }
  return MENU_RETURN_EXIT;
}