/************************************************************************ * "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. * * * * Copyright (C) 1985, 1990 Lugaru Software Ltd. All rights reserved. * * * * Limited permission is hereby granted to reproduce and modify this * * copyrighted material provided that the resulting code is used only in * * conjunction with Lugaru products and that this notice is retained in * * any such reproduction or modification. * ************************************************************************* * The previous copyright and trademark notice applies to some of the * * code herein. All other changes, enhancements and extension routines * * * * Copyright (C) 1989, 1990 by Jonas H. Hedberg. All rights reserved. * * * * These changes may be redistributed free allowed for any purpose * * providing both the Lugaru and my copyrights remain intact. * * I assume no liability for the use or inability to use * * this software. Neither do I take responsibility for any damage * * cased by this software extension. * * This extension may NOT be redistributed for profit. * ************************************************************************* * File.......: MOUSE.E * * Ver........: 1.00 * * Date.......: 1990-08-16 * * īpsilon ver: 5.0 * * By.........: Jonas Hedberg * * Title..: Software Engineer * * Company: TEAMSTER AB * * Address: P.O. Box 8321 * * S-402 79 G™TEBORG * * Country: SWEDEN * * Tel....: Int +46-31-22 22 65 (GMT + 1h) * * Fax....: Int +46-31-22 75 46 * * Description: Mouse driver for Epsilon. * * * * Commands: * * ------------------------------------------------- * * mouse = Toggle mouse on/off * * set_double_click = Set the dobble click intervall * * in n*0.055s parts. * * * * Buttons: * * ------------------------------------------------- * * Single left = Move cursor to mouse cursor. * * If in echo area move to point in * * buffer. * * | ECHO AREA | * * 0% 50% 100% * * If mouse cursor is in another window * * that isn't current the window is * * made the current one. * * If the button is held down, a mark is * * set at the current mouse position. * * Single right = Delete from mark to mouse cursor. * * Doubble left = Runs the Epsilon command: * * exchange-point-and-mark * * Doubble right= Yank at mouse cursor * * * * Other: * * ------------------------------------------------- * * If mouse cursor in top of screen and mouse still * * beeing move upwords scroll down, it works the * * same way the other way. It also can scroll left * * and right witch works so that if the mouse cursor * * is at the left edge of screen and columns of text * * is "hidden" beound the window scrolls right. It's * * the same way to the right exept that the text * * cursor must be on a row that reatches so long * * that you want to scroll. * * Algorithm..: * * Comments...: Tested with Microsoft mouse driver version 7.04. * * Change log * * Date | Ver | Change * * ----------+-------+-------------------------------------------------- * * | | * * | | * * | | * ************************************************************************/ #include "eel.h" #include "lowlevel.h" char mouse_present = 0; /* non-zero if a mouse is present */ int double_click_interval = 10; /* int ticks, 18.2 ticks per second */ #define MOUSE_IO 0x33 /* Interrupt 33H for mouse services */ #define CHAR_SIZE 8 /* Pixels per character */ #define LEFT_BUTTON 0 #define RIGHT_BUTTON 1 #define BUTTON_MASK(button) (1 << button) /* Button mask for button word */ #define SCROLL_VERT -1 #define SCROLL_HORZ -2 /* Initiate the mouse and check for a mouse */ init_mouse() { if (!mouse_present) { m_regs.w.ax = 0; /* Mouse installed */ do_interrupt(MOUSE_IO, &m_regs); } if (m_regs.w.ax) { mouse_present = m_regs.w.ax; m_regs.w.ax = 0x1130; /* Get screen size from video card */ m_regs.b.bh = 0; m_regs.b.bl = 24; do_interrupt(VIDEO_IO, &m_regs); m_regs.w.ax = 8; /* Set min and max vertikal position */ m_regs.w.cx = 0; /* for mouse */ m_regs.w.dx = (m_regs.b.dl + 1)*CHAR_SIZE - 1; do_interrupt(MOUSE_IO, &m_regs); } } /* Show mouse cursor on screen */ show_mouse_cursor() { m_regs.w.ax = 1; /* Show cursor */ do_interrupt(MOUSE_IO, &m_regs); m_regs.w.ax = 11; /* Read mouse motion counters */ do_interrupt(MOUSE_IO, &m_regs); } /* Turn of mouse cursor */ hide_mouse_cursor() { m_regs.w.ax = 2; /* Hide cursor */ do_interrupt(MOUSE_IO, &m_regs); } /* Redraw screen, but hide mouse first, then show it again */ refresh_for_mouse() { hide_mouse_cursor(); refresh(); show_mouse_cursor(); } /* Wrap the mouse cursor to the hardware cursor */ mouse_to_cursor() { m_regs.b.ah = 3; /* Get position an buttom status */ m_regs.b.bh = 0; do_interrupt(VIDEO_IO, &m_regs); set_mouse_cursor(m_regs.b.dh * CHAR_SIZE, m_regs.b.dl * CHAR_SIZE); } /* Set the mouse cursor to given row and column */ set_mouse_cursor(row, col) { m_regs.w.ax = 4; /* Set mouse cursor position */ m_regs.w.cx = col; m_regs.w.dx = row; do_interrupt(MOUSE_IO, &m_regs); } /* Return the nuber of BIOS ticks */ bios_ticks() { int ticks; m_regs.b.ah = 0; do_interrupt(0x1A, &m_regs); if (m_regs.b.al == 0) { /* Calculate ticks */ ticks = (m_regs.w.cx << 16) + m_regs.w.dx; } else { /* We have passed midnight since last call, make sure pasue() exits */ ticks = 0x7FFFFFFFL; } return ticks; } /* Waits for the specified number of BIOS ticks */ pause(ticks) { int alarm; alarm = bios_ticks() + ticks; while (alarm > bios_ticks()) { } } /* Reset mouse buttons */ flash_mouse_buttons() { short button; for (button = LEFT_BUTTON; button <= RIGHT_BUTTON; ++button) { m_regs.w.ax = 5; /* Get button press information */ m_regs.w.bx = button; do_interrupt(MOUSE_IO, &m_regs); } } /* screen_set_point takes mouse row and column coordinates and sets point there */ /* If the coordinates lie in another window, it's made current */ /* Non-zero is returned if the specified row is an editable line */ /* Otherwise (modeline or echo line) zero is returned */ screen_set_point(row, col) { int r, current_window = window_number, window_size = window_height; row /= CHAR_SIZE; col /= CHAR_SIZE; /* Find which window the coordinates lie in */ if (number_of_windows() == 1) window_number = 0; else for (window_number = number_of_windows() - 1; !((row >= window_edge(VERTICAL, TOPLEFT)) && (row <= window_edge(VERTICAL, BOTTOMRIGHT)) && (col >= window_edge(HORIZONTAL, TOPLEFT)) && (col <= window_edge(HORIZONTAL, BOTTOMRIGHT))) && (window_number >= 0); --window_number) r = window_number; if ((screen_lines - 1) > row) { /* If row = mode line, don't change point */ if (row < window_edge(VERTICAL, BOTTOMRIGHT)) { col = col - window_edge(HORIZONTAL, TOPLEFT) + display_column; row = row - window_edge(VERTICAL, TOPLEFT); point = window_start; point = next_screen_line(row); r = current_column(); move_to_column(r + col); r = current_column() - (r + col); if (r > 0) point -= r; return 1; } else { current_window = window_number; return 0; } } else { r += window_size + 1; /* Row in echo area, don't do anything */ window_number = current_window; return 0; } } /* Return 1 if any mouse nutton is pressed */ /* At the same time check for vertical or horizontal scrolling */ /* an preform the scrolling */ mouse_button_pressed() { short status, row, col, i; for(;;) { m_regs.w.ax = 3; /* Get position and button status */ do_interrupt(MOUSE_IO, &m_regs); status = m_regs.w.bx & (BUTTON_MASK(LEFT_BUTTON) + BUTTON_MASK(RIGHT_BUTTON)); row = m_regs.w.dx / CHAR_SIZE; col = m_regs.w.cx / CHAR_SIZE; m_regs.w.ax = 11; /* Read mouse motion counters */ do_interrupt(MOUSE_IO, &m_regs); /* Check if not much horizontal motion */ if (!(m_regs.w.cx / 8) && (((row == 0) && (m_regs.w.dx < 0)) || (row == (screen_lines - 1) && (m_regs.w.dx > 0)))) { if (prev_cmd == SCROLL_VERT) { window_scroll(m_regs.w.dx / 4); refresh_for_mouse(); } else { pause(3); prev_cmd = SCROLL_VERT; m_regs.w.ax = 11; /* Read mouse motion counters */ do_interrupt(MOUSE_IO, &m_regs); } } else { if ((prev_cmd == SCROLL_VERT) && (row > 0) && (row < (screen_lines - 1))) prev_cmd = 0; if (!(m_regs.w.dx / 8) && (((col == 0) && (m_regs.w.cx < 0)) || (col == (screen_cols - 1) && (m_regs.w.cx > 0))) && (row < screen_lines - 2)) { if (prev_cmd == SCROLL_HORZ) { if ((col == 0) && (display_column > (0 + -m_regs.w.cx / 4) - 1)) { int old_iter = iter, old_arg = has_arg; int old_prev = prev_cmd, old_this = this_cmd; iter = -m_regs.w.cx / 4; has_arg = 0; prev_cmd = 0; scroll_right(); refresh_for_mouse(); iter = old_iter, has_arg = old_arg; prev_cmd = old_prev, this_cmd = old_this; break; } if (col == screen_cols -1) { int old_iter = iter, old_arg = has_arg; int old_prev = prev_cmd, old_this = this_cmd; iter = m_regs.w.cx / 4; has_arg = 0; prev_cmd = 0; scroll_left(); refresh_for_mouse(); iter = old_iter, has_arg = old_arg; prev_cmd = old_prev, this_cmd = old_this; break; } } else { pause(3); prev_cmd = SCROLL_HORZ; m_regs.w.ax = 11; /* Read mouse motion counters */ do_interrupt(MOUSE_IO, &m_regs); } } else { break; } } } return status; } /* If any mouse button were pressed do the proper thing for each button */ do_mouse_command() { short status; pause(double_click_interval); /* Give user time to doble click */ m_regs.w.ax = 5; /* Get button press information */ m_regs.w.bx = LEFT_BUTTON; do_interrupt(MOUSE_IO, &m_regs); status = m_regs.w.ax; switch(m_regs.w.bx) { case 1: /* Check if user clicked i echo area */ if ((m_regs.w.dx / CHAR_SIZE) == (screen_lines -1)) { point = size() * m_regs.w.cx / (screen_cols - 1) / CHAR_SIZE; build_first = 1; break; } /* Single click left -> set point at mouse cursor */ screen_set_point(m_regs.w.dx, m_regs.w.cx); refresh_for_mouse(); /* Check if the button is still being held down -> set mark at point */ /* Then set point at new mouse cursor when button is released */ if (status & BUTTON_MASK(LEFT_BUTTON)) { set_mark(); while (mouse_button_pressed() & BUTTON_MASK(LEFT_BUTTON)); m_regs.w.ax = 6; /* Get button release information */ m_regs.w.bx = LEFT_BUTTON; do_interrupt(MOUSE_IO, &m_regs); screen_set_point(m_regs.w.dx, m_regs.w.cx); refresh_for_mouse(); } break; case 2: /* Double click left -> xhange mark and cursor */ /* Then set point and mouse cursor to previous mark */ /* screen_set_point(m_regs.w.dx, m_regs.w.cx); */ exchange_point_and_mark(); refresh_for_mouse(); return; case 0: /* No left clicks, check the right button */ m_regs.w.ax = 5; /* Get button press information */ m_regs.w.bx = RIGHT_BUTTON; do_interrupt(MOUSE_IO, &m_regs); switch(m_regs.w.bx) { int *point_save, pos; case 0: return; case 1: /* Check if user clicked in echo area */ if ((m_regs.w.dx / CHAR_SIZE) == (screen_lines - 1)) { break; } case 2: /* Click right -> delete from mark to mouse cursor */ /* Double click right -> yank at mouse cursor */ point_save = alloc_spot(); if (screen_set_point(m_regs.w.dx, m_regs.w.cx)) { if (m_regs.w.bx == 1) kill_region(); else yank(); refresh_for_mouse(); point = *point_save; } else maybe_ding(); free_spot(point_save); break; default: goto too_many_clicks; } break; default: too_many_clicks: maybe_ding(); return; } hide_mouse_cursor(); maybe_refresh(); show_mouse_cursor(); } /* Turn mouse functions on and off */ command mouse() { if ((iter == 0) || (!has_arg && mouse_present)) { mouse_present = 0; say("Mouse off."); } else { init_mouse(); if (mouse_present) say("Mouse on."); else error("No mouse were found!"); } iter = 1; } /* Allow you to set the double click wait interval */ command set_double_click() { char prompt[80]; sprintf(prompt, "Current double click interval is %d. New value: ", double_click_interval); double_click_interval = get_number(prompt); } new_mouse_getkey() { if (!cmd_len && !char_avail() && mouse_present && !another) { flash_mouse_buttons(); show_mouse_cursor(); while (!char_avail()) { if (mouse_button_pressed()) { prev_cmd = 0; do_mouse_command(); flash_mouse_buttons(); } } hide_mouse_cursor(); } return mouse_getkey(); } new_next_video() { mouse_next_video(); if (mouse_present) init_mouse(); } new_set_video() { mouse_set_video(); if (mouse_present) init_mouse(); } when_loading() { sayput("MOUSE-module Ver 1.00 (C) 1990 by Jonas Hedberg. Loading..."); /* Change Epsilon's getkey() */ if (!find_index("mouse_getkey")) replace_name("getkey", "mouse_getkey"); else drop_name("getkey"); replace_name("new_mouse_getkey", "getkey"); /* Change Epsilon's next_video() */ if (!find_index("mouse_next_video")) replace_name("next_video", "mouse_next_video"); else drop_name("next_video"); replace_name("new_next_video", "next_video"); /* Change Epsilon's set_video() */ if (!find_index("mouse_set_video")) replace_name("set_video", "mouse_set_video"); else drop_name("set_video"); replace_name("new_set_video", "set_video"); delay(300, COND_KEY); }