📄 os_msdos.c
字号:
* Get a characters from the keyboard.
* If time == 0 do not wait for characters.
* If time == n wait a short time for characters.
* If time == -1 wait forever for characters.
*
* return the number of characters obtained
*/
int
mch_inchar(
char_u *buf,
int maxlen,
long time)
{
int len = 0;
int c;
static int nextchar = 0; /* may keep character when maxlen == 1 */
/*
* if we got a ctrl-C when we were busy, there will be a "^C" somewhere
* on the sceen, so we need to redisplay it.
*/
if (delayed_redraw)
{
delayed_redraw = FALSE;
update_screen(CLEAR);
setcursor();
out_flush();
}
/* return remaining character from last call */
if (nextchar)
{
*buf = nextchar;
nextchar = 0;
return 1;
}
#ifdef USE_MOUSE
if (time != 0)
show_mouse(TRUE);
#endif
if (time >= 0)
{
if (WaitForChar(time) == 0) /* no character available */
{
#ifdef USE_MOUSE
show_mouse(FALSE);
#endif
return 0;
}
}
else /* time == -1 */
{
/*
* If there is no character available within 2 seconds (default)
* write the autoscript file to disk
*/
if (WaitForChar(p_ut) == 0)
updatescript(0);
}
WaitForChar(FOREVER); /* wait for key or mouse click */
/*
* Try to read as many characters as there are, until the buffer is full.
*/
/*
* we will get at least one key. Get more if they are available
* After a ctrl-break we have to read a 0 (!) from the buffer.
* bioskey(1) will return 0 if no key is available and when a
* ctrl-break was typed. When ctrl-break is hit, this does not always
* implies a key hit.
*/
cbrk_pressed = FALSE;
#ifdef USE_MOUSE
if (mouse_click >= 0 && maxlen >= 5)
{
len = 5;
*buf++ = ESC + 128;
*buf++ = 'M';
*buf++ = mouse_click;
*buf++ = mouse_x + '!';
*buf++ = mouse_y + '!';
mouse_click = -1;
}
else
#endif
{
#ifdef USE_MOUSE
mouse_hidden = TRUE;
#endif
if (p_biosk)
{
while ((len == 0 || bioskey(1)) && len < maxlen)
{
c = bioskey(0); /* get the key */
/*
* translate a few things for inchar():
* 0x0000 == CTRL-break -> 3 (CTRL-C)
* 0x0300 == CTRL-@ -> NUL
* 0xnn00 == extended key code -> K_NUL, nn
* K_NUL -> K_NUL, 3
*/
if (c == 0)
c = 3;
else if (c == 0x0300)
c = NUL;
else if ((c & 0xff) == 0 || c == K_NUL)
{
if (c == K_NUL)
c = 3;
else
c >>= 8;
*buf++ = K_NUL;
++len;
}
if (len < maxlen)
{
*buf++ = c;
len++;
}
else
nextchar = c;
}
}
else
{
while ((len == 0 || kbhit()) && len < maxlen)
{
switch (c = getch())
{
case 0:
/* NUL means that there is another character.
* Get it immediately, because kbhit() doesn't always
* return TRUE for the second character.
*/
*buf++ = K_NUL;
++len;
c = getch();
break;
case K_NUL:
*buf++ = K_NUL;
++len;
c = 3;
break;
case 3:
cbrk_pressed = TRUE;
/*FALLTHROUGH*/
default:
break;
}
if (len < maxlen)
{
*buf++ = c;
++len;
}
else
nextchar = c;
}
}
}
#ifdef USE_MOUSE
show_mouse(FALSE);
#endif
beep_count = 0; /* may beep again now that we got some chars */
return len;
}
/*
* return non-zero if a character is available
*/
int
mch_char_avail(void)
{
return WaitForChar(0L);
}
#ifdef DJGPP
# define INT_ARG int
#else
# define INT_ARG
#endif
/*
* function for ctrl-break interrupt
*/
static void interrupt
#ifdef DJGPP
catch_cbrk(int a)
#else
catch_cbrk(void)
#endif
{
cbrk_pressed = TRUE;
ctrlc_pressed = TRUE;
}
/*
* ctrl-break handler for DOS. Never called when a ctrl-break is typed, because
* we catch interrupt 1b. If you type ctrl-C while Vim is waiting for a
* character this function is not called. When a ctrl-C is typed while Vim is
* busy this function may be called. By that time a ^C has been displayed on
* the screen, so we have to redisplay the screen. We can't do that here,
* because we may be called by DOS. The redraw is in mch_inchar().
*/
static int _cdecl
cbrk_handler(void)
{
delayed_redraw = TRUE;
return 1; /* resume operation after ctrl-break */
}
/*
* function for critical error interrupt
* For DOS 1 and 2 return 0 (Ignore).
* For DOS 3 and later return 3 (Fail)
*/
static void interrupt
catch_cint(bp, di, si, ds, es, dx, cx, bx, ax)
unsigned bp, di, si, ds, es, dx, cx, bx, ax;
{
ax = (ax & 0xff00); /* set AL to 0 */
if (_osmajor >= 3)
ax |= 3; /* set AL to 3 */
}
/*
* Set the interrupt vectors for use with Vim on or off.
* on == TRUE means as used within Vim
*/
static void
set_interrupts(int on)
{
static int saved_cbrk;
#ifndef DJGPP
static void interrupt (*old_cint)();
#endif
static void interrupt (*old_cbrk)(INT_ARG);
if (on)
{
saved_cbrk = getcbrk(); /* save old ctrl-break setting */
setcbrk(0); /* do not check for ctrl-break */
#ifdef DJGPP
old_cbrk = signal(SIGINT, catch_cbrk); /* critical error interrupt */
#else
old_cint = getvect(0x24); /* save old critical error interrupt */
setvect(0x24, catch_cint); /* install our critical error interrupt */
old_cbrk = getvect(0x1B); /* save old ctrl-break interrupt */
setvect(0x1B, catch_cbrk); /* install our ctrl-break interrupt */
ctrlbrk(cbrk_handler); /* vim's ctrl-break handler */
#endif
if (term_console)
out_str(T_ME); /* set colors */
}
else
{
setcbrk(saved_cbrk); /* restore ctrl-break setting */
#ifdef DJGPP
signal(SIGINT,old_cbrk); /* critical error interrupt */
#else
setvect(0x24, old_cint); /* restore critical error interrupt */
setvect(0x1B, old_cbrk); /* restore ctrl-break interrupt */
#endif
/* restore ctrl-break handler, how ??? */
if (term_console)
mynormvideo(); /* restore screen colors */
}
}
/*
* We have no job control, fake it by starting a new shell.
*/
void
mch_suspend(void)
{
suspend_shell();
}
extern int _fmode;
/*
* Prepare window for use by Vim.
* we do not use windows, there is not much to do here
*/
void
mch_windinit(void)
{
union REGS regs;
term_console = TRUE; /* assume using the console for the things here */
_fmode = O_BINARY; /* we do our own CR-LF translation */
out_flush();
set_interrupts(TRUE); /* catch interrupts */
#ifdef DJGPP
/*
* Use Long File Names by default, if $LFN not set.
*/
if (getenv("LFN") == NULL)
putenv("LFN=y");
get_screenbase();
#endif
#ifdef USE_MOUSE
/* find out if a MS compatible mouse is available */
regs.x.ax = 0;
(void)int86(0x33, ®s, ®s);
mouse_avail = regs.x.ax;
/* best guess for mouse coordinate computations */
mch_get_winsize();
if (Columns <= 40)
mouse_x_div = 16;
if (Rows == 30)
mouse_y_div = 16;
#endif
/*
* Try switching to 16 colors for background, instead of 8 colors and
* blinking. Does this always work? Can the old value be restored?
*/
regs.x.ax = 0x1003;
regs.h.bl = 0x00;
regs.h.bh = 0x00;
int86(0x10, ®s, ®s);
/* Save the old cursor shape */
mch_restore_cursor_shape(FALSE);
/* Initialise the cursor shape */
mch_update_cursor();
}
int
mch_check_win(
int argc,
char **argv)
{
/* store argv[0], may be used for $VIM */
if (*argv[0] != NUL)
exe_name = FullName_save((char_u *)argv[0], FALSE);
if (isatty(1))
return OK;
return FAIL;
}
/*
* Return TRUE if the input comes from a terminal, FALSE otherwise.
*/
int
mch_input_isatty(void)
{
if (isatty(read_cmd_fd))
return TRUE;
return FALSE;
}
#ifdef USE_FNAME_CASE
/*
* fname_case(): Set the case of the file name, if it already exists.
*/
void
fname_case(char_u *name)
{
char_u *tail;
struct ffblk fb;
slash_adjust(name);
if (findfirst(name, &fb, 0) == 0)
{
tail = gettail(name);
if (STRLEN(tail) == STRLEN(fb.ff_name))
STRCPY(tail, fb.ff_name);
}
}
#endif
/*
* mch_settitle(): set titlebar of our window.
* Dos console has no title.
*/
void
mch_settitle(
char_u *title,
char_u *icon)
{
}
/*
* Restore the window/icon title. (which we don't have)
*/
void
mch_restore_title(int which)
{
}
int
mch_can_restore_title(void)
{
return FALSE;
}
int
mch_can_restore_icon(void)
{
return FALSE;
}
/*
* Insert user name in s[len].
*/
int
mch_get_user_name(
char_u *s,
int len)
{
*s = NUL;
return FAIL;
}
/*
* Insert host name is s[len].
*/
void
mch_get_host_name(
char_u *s,
int len)
{
#ifdef DJGPP
STRNCPY(s, "PC (32 bits Vim)", len);
#else
STRNCPY(s, "PC (16 bits Vim)", len);
#endif
}
/*
* return process ID
*/
long
mch_get_pid(void)
{
return (long)0;
}
/*
* Get name of current directory into buffer 'buf' of length 'len' bytes.
* Return OK for success, FAIL for failure.
*/
int
mch_dirname(
char_u *buf,
int len)
{
#ifdef DJGPP
if (getcwd((char *)buf, len) == NULL)
return FAIL;
/* turn the '/'s returned by DJGPP into '\'s */
slash_adjust(buf);
return OK;
#else
return (getcwd((char *)buf, len) != NULL ? OK : FAIL);
#endif
}
/*
* Change default drive (just like _chdrive of Borland C 3.1)
*/
static int
change_drive(int drive)
{
union REGS regs;
regs.h.ah = 0x0e;
regs.h.dl = drive - 1;
intdos(®s, ®s); /* set default drive */
regs.h.ah = 0x19;
intdos(®s, ®s); /* get default drive */
if (regs.h.al == drive - 1)
return 0;
else
return -1;
}
/*
* Get absolute file name into buffer 'buf' of length 'len' bytes.
* All slashes are replaced with backslashes, to avoid trouble when comparing
* file names.
*
* return FAIL for failure, OK otherwise
*/
int
mch_FullName(
char_u *fname,
char_u *buf,
int len,
int force)
{
if (fname == NULL) /* always fail */
{
*buf = NUL;
return FAIL;
}
if (!force && mch_isFullName(fname)) /* allready expanded */
{
STRNCPY(buf, fname, len);
slash_adjust(buf);
return OK;
}
#ifdef __BORLANDC__ /* the old Turbo C does not have this */
if (_fullpath((char *)buf, (char *)fname, len - 1) == NULL)
{
STRNCPY(buf, fname, len); /* failed, use the relative path name */
slash_adjust(buf);
return FAIL;
}
if (mch_isdir(fname))
STRCAT(buf, "\\");
slash_adjust(buf);
return OK;
#else /* almost the same as mch_FullName in os_unix.c */
{
int l;
char_u olddir[MAXPATHL];
char_u *p, *q;
int c;
int retval = OK;
*buf = 0;
/*
* change to the directory for a moment,
* and then do the getwd() (and get back to where we were).
* This will get the correct path name with "../" things.
*/
p = vim_strrchr(fname, '/');
q = vim_strrchr(fname, '\\');
if (q != NULL && (p == NULL || q > p))
p = q;
q = vim_strrchr(fname, ':');
if (q != NULL && (p == NULL || q > p))
p = q;
if (p != NULL)
{
if (getcwd(olddir, MAXPATHL) == NULL)
{
p = NULL; /* can't get current dir: don't chdir */
retval = FAIL;
}
else
{
if ((q + 1) == p) /* ... c:\foo */
q = p + 1; /* -> c:\ */
else /* but c:\foo\bar */
q = p; /* -> c:\foo */
c = *q; /* truncate at start of fname */
*q = NUL;
#ifdef DJGPP
STRCPY(buf, fname);
slash_adjust(buf); /* needed when fname starts with \ */
if (mch_chdir(buf)) /* change to the directory */
#else
if (mch_chdir(fname)) /* change to the directory */
#endif
retval = FAIL;
else
{
fname = q;
if (c == '\\') /* if we cut the name at a */
fname++; /* '\', don't add it again */
}
*q = c;
}
}
if (getcwd(buf, len) == NULL)
{
retval = FAIL;
*buf = NUL;
}
/*
* Concatenate the file name to the path.
*/
l = STRLEN(buf);
if (l && buf[l - 1] != '/' && buf[l - 1] != '\\')
strcat(buf, "/");
if (p)
mch_chdir(olddir);
strcat(buf, fname);
slash_adjust(buf);
return retval;
}
#endif
}
/*
* Replace all slashes by backslashes.
* This used to be the other way around, but MS-DOS sometimes has problems
* with slashes (e.g. in a command name). We can't have mixed slashes and
* backslashes, because comparing file names will not work correctly. The
* commands that use a file name should try to avoid the need to type a
* backslash twice.
*/
void
slash_adjust(char_u *p)
{
#ifdef OLD_DJGPP /* this seems to have been fixed in DJGPP 2.01 */
/* DJGPP can't handle a file name that starts with a backslash, and when it
* starts with a slash there should be no backslashes */
if (*p == '\\' || *p == '/')
while (*p)
{
if (*p == '\\')
*p = '/';
++p;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -