summaryrefslogtreecommitdiffstats
path: root/historic/selection/selection.c
diff options
context:
space:
mode:
Diffstat (limited to 'historic/selection/selection.c')
-rw-r--r--historic/selection/selection.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/historic/selection/selection.c b/historic/selection/selection.c
new file mode 100644
index 000000000..058936fc5
--- /dev/null
+++ b/historic/selection/selection.c
@@ -0,0 +1,237 @@
+/* implement copying and pasting in Linux virtual consoles */
+/* Andrew Haylett, 17th June 1993 */
+/* Wed Feb 15 09:33:16 1995, faith@cs.unc.edu changed tty0 to console, since
+ most systems don't have a tty0 any more. */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <termios.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/kd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include "mouse.h"
+
+extern int ms_copy_button, ms_paste_button;
+
+static const int SCALE = 10;
+static const long CLICK_INTERVAL = 250; /* msec */
+static const char *console = "/dev/console";
+
+typedef enum { character = 0, word = 1, line = 2 } sel_mode;
+
+static int open_console(const int mode);
+static void set_sel(const int xs, const int ys, const int xe,
+ const int ye, const sel_mode mode);
+static void paste(void);
+static long interval(const struct timeval *t1, const struct timeval *t2);
+static int check_mode(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct ms_event ev;
+ struct winsize win;
+ struct timeval tv1, tv2;
+ int xs, ys, xe, ye, x1, y1, fd, clicks = 0;
+ sel_mode mode;
+
+ fd = open_console(O_RDONLY);
+ ioctl(fd, TIOCGWINSZ, &win);
+ close(fd);
+ if (! win.ws_col || ! win.ws_row)
+ {
+ fprintf(stderr, "selection: zero screen dimension, assuming 80x25.\n");
+ win.ws_col = 80;
+ win.ws_row = 25;
+ }
+
+ ms_params(argc, argv);
+
+ if (ms_init(win.ws_col * SCALE - 1, win.ws_row * SCALE - 1))
+ exit(1);
+
+ if (fork() > 0)
+ exit(0);
+ setsid();
+
+ gettimeofday(&tv1, (struct timezone *)NULL);
+
+restart:
+ while (1)
+ {
+ if (check_mode())
+ goto restart;
+ if (get_ms_event(&ev))
+ exit(1);
+ if (ev.ev_butstate == ms_copy_button)
+ {
+ ++clicks;
+ gettimeofday(&tv2, (struct timezone *)NULL);
+ xs = ev.ev_x / SCALE + 1;
+ ys = ev.ev_y / SCALE + 1;
+ if (interval(&tv1, &tv2) < CLICK_INTERVAL && clicks == 1)
+ {
+ mode = word;
+ set_sel(xs, ys, xs, ys, mode);
+ }
+ else if (interval(&tv1, &tv2) < CLICK_INTERVAL && clicks == 2)
+ {
+ mode = line;
+ set_sel(xs, ys, xs, ys, mode);
+ }
+ else
+ {
+ mode = character;
+ clicks = 0;
+ do /* wait for left button up */
+ {
+ if (check_mode())
+ goto restart;
+ if (get_ms_event(&ev))
+ exit(1);
+ } while (ev.ev_butstate);
+ x1 = y1 = 0;
+ do /* track start selection until left button down */
+ {
+ xs = ev.ev_x / SCALE + 1;
+ ys = ev.ev_y / SCALE + 1;
+ if (xs != x1 || ys != y1)
+ {
+ set_sel(xs, ys, xs, ys, mode);
+ x1 = xs; y1 = ys;
+ }
+ if (check_mode())
+ goto restart;
+ if (get_ms_event(&ev))
+ exit(1);
+ } while (ev.ev_butstate != ms_copy_button);
+ }
+ x1 = y1 = 0;
+ gettimeofday(&tv1, (struct timezone *)NULL);
+ do /* track end selection until left button up */
+ {
+ xe = ev.ev_x / SCALE + 1;
+ ye = ev.ev_y / SCALE + 1;
+ if (xe != x1 || ye != y1)
+ {
+ set_sel(xs, ys, xe, ye, mode);
+ x1 = xe; y1 = ye;
+ }
+ if (check_mode())
+ goto restart;
+ if (get_ms_event(&ev))
+ exit(1);
+ } while (ev.ev_butstate == ms_copy_button);
+ } else if (ev.ev_butstate == ms_paste_button)
+ { /* paste selection */
+ paste();
+ do /* wait for right button up */
+ {
+ if (check_mode())
+ goto restart;
+ if (get_ms_event(&ev))
+ exit(1);
+ } while (ev.ev_butstate);
+ gettimeofday(&tv1, (struct timezone *)NULL);
+ clicks = 0;
+ }
+ }
+}
+
+/* We have to keep opening and closing the console because (a) /dev/tty0
+ changed its behaviour at some point such that the current VC is fixed
+ after the open(), rather than being re-evaluated at each write(), and (b)
+ because we seem to lose our grip on /dev/tty? after someone logs in if
+ this is run from /etc/rc. */
+
+static int
+open_console(const int mode)
+{
+ int fd;
+
+ if ((fd = open(console, mode)) < 0)
+ {
+ perror("selection: open_console()");
+ exit(1);
+ }
+ return fd;
+}
+
+/* mark selected text on screen. */
+static void
+set_sel(const int xs, const int ys,
+ const int xe, const int ye, const sel_mode mode)
+{
+ unsigned char buf[sizeof(char) + 5 * sizeof(short)];
+ unsigned short *arg = (unsigned short *)(buf + 1);
+ int fd;
+
+ buf[0] = 2;
+
+ arg[0] = xs;
+ arg[1] = ys;
+ arg[2] = xe;
+ arg[3] = ye;
+ arg[4] = mode;
+
+ fd = open_console(O_WRONLY);
+ if (ioctl(fd, TIOCLINUX, buf) < 0)
+ {
+ perror("selection: ioctl(..., TIOCLINUX, ...)");
+ exit(1);
+ }
+ close(fd);
+}
+
+/* paste contents of selection buffer into console. */
+static void
+paste(void)
+{
+ char c = 3;
+ int fd;
+
+ fd = open_console(O_WRONLY);
+ if (ioctl(fd, TIOCLINUX, &c) < 0)
+ {
+ perror("selection: ioctl(..., TIOCLINUX, ...)");
+ exit(1);
+ }
+ close(fd);
+}
+
+/* evaluate interval between times. */
+static long
+interval(const struct timeval *t1, const struct timeval *t2)
+{
+ return (t2->tv_sec - t1->tv_sec) * 1000
+ + (t2->tv_usec - t1->tv_usec) / 1000;
+}
+
+/* Check whether console is in graphics mode; if so, wait until it isn't. */
+static int
+check_mode(void)
+{
+ int fd, ch = 0;
+ long kd_mode;
+
+ do
+ {
+ fd = open_console(O_RDONLY);
+ if (ioctl(fd, KDGETMODE, &kd_mode) < 0)
+ {
+ perror("selection: ioctl(..., KDGETMODE, ...)");
+ exit(1);
+ }
+ close(fd);
+ if (kd_mode != KD_TEXT)
+ {
+ ++ch;
+ sleep(2);
+ }
+ } while (kd_mode != KD_TEXT);
+ return (ch > 0);
+}