📄 pathfinder2d.cpp
字号:
// PathFinder2D.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#include "stdio.h" //for sprintf
#include "mmsystem.h" //lib: winmm.lib, for playsound
#include "commdlg.h" //cm dlg
#include "PathFinder2D.h"
//
#include "Setup.h" //all the Generic-purpose functions that all algs share.
Setup *vSetup=NULL;
#include "Generic.h" //generic interface to all Setups
Generic *vGeneric=NULL;
//
HDC hdctmp;
HBITMAP hbmtmp;
HANDLE hOld;
BITMAPV4HEADER bi;
LPBYTE pwBits;
int TIMER_RATE;
int MINIMUM_CLIENT_WIDTH;
int MINIMUM_CLIENT_HEIGHT;
//
bool runflag;
bool zoom;
bool presearch_view;
bool drawmode;
//
bool pendown;
bool brushmode;
int elevation;
int lastx, lasty;
int mutex=0;
//
enum
{
TIMER_ID=1,
SCREEN_WIDTH=1000,
SCREEN_HEIGHT=620
};
//
HINSTANCE hInst;
#define MAX_LOADSTRING 100
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
void RefreshMenu(HWND hWnd)
{
LARGE_INTEGER freq; // 64 bit int
QueryPerformanceFrequency(&freq); // counts per second divisor
double ticks=1000.0*((double)vSetup->bigtick.QuadPart/(double)freq.QuadPart);
double gticks=1000.0*((double)vGeneric->bigtick.QuadPart/(double)freq.QuadPart);
char tmp[512];
sprintf(tmp,"%s - AI %d - Frame %d - Elapsed %f ms - Clock %I64d (Elapsed %f ms - Clock %I64d) %s %s",
szTitle,
vGeneric->ai,
vSetup->frame,
ticks,
(_int64)vSetup->bigtick.QuadPart,
gticks,
(_int64)vGeneric->bigtick.QuadPart,
runflag?"":" [PAUSED] ",
vGeneric->isDone()?" [DONE] ":""
);
SetWindowText(hWnd,tmp);
//
HMENU hMenu=GetMenu(hWnd);
//
CheckMenuItem(hMenu,IDM_DEVELOPMENT, (vGeneric->Alg==DEVELOPMENT_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ASTAR, (vGeneric->Alg==ASTAR_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ASTAR_HEAPINTEGER, (vGeneric->Alg==ASTAR_HEAPINTEGER_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ASTAR_HEAP, (vGeneric->Alg==ASTAR_HEAP_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ASTAR_COMPLETE, (vGeneric->Alg==ASTAR_COMPLETE_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ASTAR_LINKEDLIST, (vGeneric->Alg==ASTAR_LINKEDLIST_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ASTAR_ARRAY, (vGeneric->Alg==ASTAR_ARRAY_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_DIJKSTRA, (vGeneric->Alg==DIJKSTRA_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_BREADTHFIRST, (vGeneric->Alg==BREADTHFIRST_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_BESTFIRST, (vGeneric->Alg==BESTFIRST_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_DEPTHFIRST, (vGeneric->Alg==DEPTHFIRST_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_DSTAR, (vGeneric->Alg==DSTAR_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_RIGHTHANDRULE, (vGeneric->Alg==RIGHTHANDRULE_ALGORITHM)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_PRESEARCH, (vSetup->presearch_toggle)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_PRESEARCH_VIEW, (presearch_view)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_PAUSE_RESUME, (!runflag)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_DRAWMODE, (drawmode)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_ZOOM, (zoom)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_GAMEMODE, (vGeneric->gamemode)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_ROUTING_VIEW, (vGeneric->routing_view)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_FPS_10S, (TIMER_RATE==10000)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_FPS_1, (TIMER_RATE==1000)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_FPS_10, (TIMER_RATE==100)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_FPS_30, (TIMER_RATE==33)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_FPS_60, (TIMER_RATE==17)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_COLORSCHEME_WHITE, (vSetup->colorscheme==COLORSCHEME_WHITE)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COLORSCHEME_BLACK, (vSetup->colorscheme==COLORSCHEME_BLACK)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COLORSCHEME_GRAY, (vSetup->colorscheme==COLORSCHEME_GRAY)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COLORSCHEME_PAPER, (vSetup->colorscheme==COLORSCHEME_PAPER)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_MEDIAN_1, (vSetup->median_terrain_cost==1)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_MEDIAN_8, (vSetup->median_terrain_cost==8)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_MEDIAN_16, (vSetup->median_terrain_cost==16)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_MEDIAN_AUTO, (vSetup->median_terrain_cost==vSetup->median_terrain_cost_auto)?MF_CHECKED:MF_UNCHECKED);
//
MENUITEMINFO mii;
memset(&mii,0,sizeof(MENUITEMINFO));
mii.cbSize=sizeof(MENUITEMINFO);
mii.fMask=MIIM_TYPE;
mii.fType=MFT_STRING; //
mii.fState=0;
mii.wID=0; //
mii.hSubMenu=NULL;
//HBITMAP hbmpChecked;
//HBITMAP hbmpUnchecked;
//mii.dwItemData=tmp;
sprintf(tmp,"Auto (%f)",vSetup->median_terrain_cost_auto);
mii.dwTypeData=tmp;
mii.cch=strlen(tmp);
SetMenuItemInfo(hMenu,IDM_MEDIAN_AUTO,FALSE,&mii);
sprintf(tmp,"Game Mode (%d AIs - WARNING)",MAX_AIS); //\t'
mii.dwTypeData=tmp;
mii.cch=strlen(tmp);
SetMenuItemInfo(hMenu,IDM_GAMEMODE,FALSE,&mii);
//
if(vSetup->use_terrain==TRUE)
{
EnableMenuItem(hMenu,IDM_MEDIAN_1, MF_ENABLED);
EnableMenuItem(hMenu,IDM_MEDIAN_8, MF_ENABLED);
EnableMenuItem(hMenu,IDM_MEDIAN_16, MF_ENABLED);
EnableMenuItem(hMenu,IDM_MEDIAN_AUTO, MF_ENABLED);
}
else
{
EnableMenuItem(hMenu,IDM_MEDIAN_1, MF_GRAYED);
EnableMenuItem(hMenu,IDM_MEDIAN_8, MF_GRAYED);
EnableMenuItem(hMenu,IDM_MEDIAN_16, MF_GRAYED);
EnableMenuItem(hMenu,IDM_MEDIAN_AUTO, MF_GRAYED);
}
//
CheckMenuItem(hMenu,IDM_DIRECTIONS4, (vSetup->directions==4)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_DIRECTIONS8, (vSetup->directions==8)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_ITERATIONS_1, (vSetup->iterations_per_frame==1)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ITERATIONS_10, (vSetup->iterations_per_frame==10)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ITERATIONS_100, (vSetup->iterations_per_frame==100)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ITERATIONS_1000, (vSetup->iterations_per_frame==1000)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ITERATIONS_10000, (vSetup->iterations_per_frame==10000)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_ITERATIONS_FULL, (vSetup->iterations_per_frame==(WIDTH*HEIGHT))?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_COST_0, (vSetup->use_terrain==false && vSetup->cost==0.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_0_5, (vSetup->use_terrain==false && vSetup->cost==0.5f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_0_25, (vSetup->use_terrain==false && vSetup->cost==0.25f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_0_125, (vSetup->use_terrain==false && vSetup->cost==0.125f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_1, (vSetup->use_terrain==false && vSetup->cost==1.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_2, (vSetup->use_terrain==false && vSetup->cost==2.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_4, (vSetup->use_terrain==false && vSetup->cost==4.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_8, (vSetup->use_terrain==false && vSetup->cost==8.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_16, (vSetup->use_terrain==false && vSetup->cost==16.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_COST_BY_TERRAIN, (vSetup->use_terrain==TRUE)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_MANHATTAN_DISTANCE, (vSetup->distance_method==MANHATTAN_DISTANCE)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_DIAGONAL_DISTANCE, (vSetup->distance_method==DIAGONAL_DISTANCE)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_PYTHAGORAS_DISTANCE, (vSetup->distance_method==PYTHAGORAS_DISTANCE)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_SIMPLE_PYTHAGORAS_DISTANCE, (vSetup->distance_method==SIMPLE_PYTHAGORAS_DISTANCE)?MF_CHECKED:MF_UNCHECKED);
//
CheckMenuItem(hMenu,IDM_DIAGONAL_COST_1, (vSetup->diagonal_cost==1.0f)?MF_CHECKED:MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_DIAGONAL_COST_1_4, (vSetup->diagonal_cost==1.4f)?MF_CHECKED:MF_UNCHECKED);
//
if(vSetup->options.uniform_cost)
{
EnableMenuItem(hMenu,IDM_COST_0, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_0_5, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_0_25, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_0_125, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_1, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_2, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_4, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_8, MF_ENABLED);
EnableMenuItem(hMenu,IDM_COST_16, MF_ENABLED);
}
else
{
EnableMenuItem(hMenu,IDM_COST_0, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_0_5, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_0_25, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_0_125, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_1, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_2, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_4, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_8, MF_GRAYED);
EnableMenuItem(hMenu,IDM_COST_16, MF_GRAYED);
}
//
if(vSetup->options.terrain_cost)
{
EnableMenuItem(hMenu,IDM_COST_BY_TERRAIN, MF_ENABLED);
}
else
{
EnableMenuItem(hMenu,IDM_COST_BY_TERRAIN, MF_GRAYED);
}
// //diagonal_cost only matters with 8-point directions
if( (vSetup->options.terrain_cost || vSetup->options.uniform_cost) && vSetup->directions==8)
{
EnableMenuItem(hMenu,IDM_DIAGONAL_COST_1, MF_ENABLED);
EnableMenuItem(hMenu,IDM_DIAGONAL_COST_1_4, MF_ENABLED);
}
else
{
EnableMenuItem(hMenu,IDM_DIAGONAL_COST_1, MF_GRAYED);
EnableMenuItem(hMenu,IDM_DIAGONAL_COST_1_4, MF_GRAYED);
}
//
if(vSetup->options.distance)
{
EnableMenuItem(hMenu,IDM_PYTHAGORAS_DISTANCE, MF_ENABLED);
EnableMenuItem(hMenu,IDM_DIAGONAL_DISTANCE, MF_ENABLED);
EnableMenuItem(hMenu,IDM_MANHATTAN_DISTANCE, MF_ENABLED);
EnableMenuItem(hMenu,IDM_SIMPLE_PYTHAGORAS_DISTANCE, MF_ENABLED);
}
else
{
EnableMenuItem(hMenu,IDM_PYTHAGORAS_DISTANCE, MF_GRAYED);
EnableMenuItem(hMenu,IDM_DIAGONAL_DISTANCE, MF_GRAYED);
EnableMenuItem(hMenu,IDM_MANHATTAN_DISTANCE, MF_GRAYED);
EnableMenuItem(hMenu,IDM_SIMPLE_PYTHAGORAS_DISTANCE, MF_GRAYED);
}
//
if(vSetup->options.search_directions)
{
EnableMenuItem(hMenu,IDM_DIRECTIONS4, MF_ENABLED);
EnableMenuItem(hMenu,IDM_DIRECTIONS8, MF_ENABLED);
}
else
{
EnableMenuItem(hMenu,IDM_DIRECTIONS4, MF_GRAYED);
EnableMenuItem(hMenu,IDM_DIRECTIONS8, MF_GRAYED);
}
//
if(runflag)
{
SetClassLong(hWnd, GCL_HICON, (long)LoadIcon(hInst, (LPCTSTR)IDI_UNPAUSED));
SetClassLong(hWnd, GCL_HICONSM, (long)LoadIcon(hInst, (LPCTSTR)IDI_UNPAUSED));
}
else
{
SetClassLong(hWnd, GCL_HICON, (long)LoadIcon(hInst, (LPCTSTR)IDI_PAUSED));
SetClassLong(hWnd, GCL_HICONSM, (long)LoadIcon(hInst, (LPCTSTR)IDI_PAUSED));
}
}
void Redraw(HWND hWnd)
{
if(mutex==0)
{
mutex++;
InvalidateRect ( hWnd,NULL, FALSE );
mutex--;
}
}
void update(HWND hWnd)
{
vGeneric->ResetAI();
vGeneric->UpdateSettings();
vGeneric->UpdateWorld();
vGeneric->Reset();
Redraw(hWnd);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
hPrevInstance=hPrevInstance; //nix compiler warnings
lpCmdLine=lpCmdLine; //nix compiler warnings
// we're not paused... start off running.
runflag=true;
zoom=false;
presearch_view=false;
drawmode=false;
pendown=false;
brushmode=false;
elevation=IMPASSABLE_TERRAIN_COST;
lastx=lasty=0;
//
vSetup=new Setup();
vSetup->set_start(252,128);
vSetup->set_end(138,128);
vSetup->Load("labyrinth.tga");
//
vGeneric=new Generic(vSetup);
//
MINIMUM_CLIENT_WIDTH=(WIDTH+4)*3;
MINIMUM_CLIENT_HEIGHT=(HEIGHT*2+16);
// TODO: Place code here.
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_PATHFINDER2D, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_PATHFINDER2D);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
//
delete vGeneric;
delete vSetup;
vGeneric=NULL;
vSetup=NULL;
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage is only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_PATHFINDER2D);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = (LPCSTR)IDC_PATHFINDER2D;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL);
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
// center window
RECT rt;
GetWindowRect(hWnd,&rt);
int width=rt.right-rt.left;
int height=rt.bottom-rt.top;
int desktopWidth = GetSystemMetrics(SM_CXSCREEN);
int desktopHeight = GetSystemMetrics(SM_CYSCREEN);
MoveWindow(hWnd,((desktopWidth>>1)-(width>>1)),((desktopHeight>>1)-(height>>1)), width, height, TRUE);
//
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
//
ShowWindow(hWnd,SW_MAXIMIZE);
//
TIMER_RATE=100;
SetTimer(hWnd, TIMER_ID, TIMER_RATE, NULL); //start the update timer
//
return TRUE;
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//
void Zoom_Composite(LPBYTE pwBits,HWND hWnd)
{
if(pwBits)
{
//
RECT rt;
GetClientRect(hWnd, &rt);
int clientwidth = (rt.right-rt.left);
DWORD *spush,*s;
DWORD *dpush,*d;
s=spush=(DWORD *)pwBits+WIDTH-1+(HEIGHT-1)*clientwidth;
d=dpush=(DWORD *)pwBits+WIDTH*2-1+(HEIGHT-1)*clientwidth*2;
int y,x;
for(y=HEIGHT-1;y>=0;y--)
{
for(x=WIDTH-1;x>=0;x--)
{
DWORD color=*s;
*(d+0)=color;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -