1 ///////////////////////////////////////////////////////////////////////////////
2 //Telnet Win32 : an ANSI telnet client.
3 //Copyright (C) 1998  Paul Brannan
4 //Copyright (C) 1998  I.Ioannou
5 //Copyright (C) 1997  Brad Johnson
6 //
7 //This program is free software; you can redistribute it and/or
8 //modify it under the terms of the GNU General Public License
9 //as published by the Free Software Foundation; either version 2
10 //of the License, or (at your option) any later version.
11 //
12 //This program is distributed in the hope that it will be useful,
13 //but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //GNU General Public License for more details.
16 //
17 //You should have received a copy of the GNU General Public License
18 //along with this program; if not, write to the Free Software
19 //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 //I.Ioannou
22 //roryt@hol.gr
23 //
24 ///////////////////////////////////////////////////////////////////////////
25 
26 // TMouse.cpp
27 // A simple class for handling mouse events
28 // Written by Paul Brannan <pbranna@clemson.edu>
29 // Last modified August 30, 1998
30 
31 #include "precomp.h"
32 
TMouse(Tnclip & RefClipboard)33 TMouse::TMouse(Tnclip &RefClipboard): Clipboard(RefClipboard) {
34 	hConsole = GetStdHandle(STD_INPUT_HANDLE);
35 	hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
36 }
37 
~TMouse()38 TMouse::~TMouse() {
39 }
40 
get_coords(COORD * start_coords,COORD * end_coords,COORD * first_coords,COORD * last_coords)41 void TMouse::get_coords(COORD *start_coords, COORD *end_coords,
42 				COORD *first_coords, COORD *last_coords) {
43 	if(end_coords->Y < start_coords->Y ||
44 		(end_coords->Y == start_coords->Y && end_coords->X < start_coords->X))
45 	{
46 		*first_coords = *end_coords;
47 		*last_coords = *start_coords;
48 	} else {
49 		*first_coords = *start_coords;
50 		*last_coords = *end_coords;
51 	}
52 	last_coords->X++;
53 }
54 
doMouse_init()55 void TMouse::doMouse_init() {
56 	GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
57 	chiBuffer = newBuffer();
58 	saveScreen(chiBuffer);
59 }
60 
doMouse_cleanup()61 void TMouse::doMouse_cleanup() {
62 	restoreScreen(chiBuffer);
63 	delete[] chiBuffer;
64 }
65 
move_mouse(COORD start_coords,COORD end_coords)66 void TMouse::move_mouse(COORD start_coords, COORD end_coords) {
67 	COORD screen_start = {0, 0};
68 	COORD first_coords, last_coords;
69 	DWORD Result;
70 
71 	FillConsoleOutputAttribute(hStdout, normal,
72 		ConsoleInfo.dwSize.X * ConsoleInfo.dwSize.Y, screen_start, &Result);
73 
74 	get_coords(&start_coords, &end_coords, &first_coords, &last_coords);
75 	FillConsoleOutputAttribute(hStdout, inverse, ConsoleInfo.dwSize.X *
76 		(last_coords.Y - first_coords.Y) + (last_coords.X - first_coords.X),
77 		first_coords, &Result);
78 }
79 
doClip(COORD start_coords,COORD end_coords)80 void TMouse::doClip(COORD start_coords, COORD end_coords) {
81 	// COORD screen_start = {0, 0};
82 	COORD first_coords, last_coords;
83 	DWORD Result;
84 
85 	get_coords(&start_coords, &end_coords, &first_coords, &last_coords);
86 
87 	// Allocate the minimal size buffer
88 	int data_size = 3 + ConsoleInfo.dwSize.X *
89 		(last_coords.Y - first_coords.Y) + (last_coords.X - first_coords.X);
90 	HGLOBAL clipboard_data = GlobalAlloc(GMEM_MOVEABLE + GMEM_DDESHARE,
91 		data_size);
92 	LPVOID mem_ptr = GlobalLock(clipboard_data);
93 
94 	// Reset data_size so we can count the actual data size
95 	data_size = 0;
96 
97 	// Read the console, put carriage returns at the end of each line if
98 	// reading more than one line (Paul Brannan 9/17/98)
99 	for(int j = first_coords.Y; j <= last_coords.Y; j++) {
100 
101 		// Read line at (0,j)
102 		COORD coords;
103 		coords.X = 0;
104 		coords.Y = j;
105 		int length = ConsoleInfo.dwSize.X;
106 
107 		if(j == first_coords.Y) {
108 			coords.X = first_coords.X;
109 			length = ConsoleInfo.dwSize.X - first_coords.X;
110 		} else {
111 			// Add a carriage return to the end of the previous line
112 			*((char *)mem_ptr + data_size++) = '\r';
113 			*((char *)mem_ptr + data_size++) = '\n';
114 		}
115 
116 		if(j == last_coords.Y) {
117 			length -= (ConsoleInfo.dwSize.X - last_coords.X);
118 		}
119 
120 		// Read the next line
121 		ReadConsoleOutputCharacter(hStdout, (LPTSTR)((char *)mem_ptr +
122 			data_size), length, coords, &Result);
123 		data_size += Result;
124 
125 		// Strip the spaces at the end of the line
126 		if((j != last_coords.Y) && (first_coords.Y != last_coords.Y))
127 			while(*((char *)mem_ptr + data_size - 1) == ' ') data_size--;
128 	}
129 	if(first_coords.Y != last_coords.Y) {
130 		// Add a carriage return to the end of the last line
131 		*((char *)mem_ptr + data_size++) = '\r';
132 		*((char *)mem_ptr + data_size++) = '\n';
133 	}
134 
135 	*((char *)mem_ptr + data_size) = 0;
136 	GlobalUnlock(clipboard_data);
137 
138 	Clipboard.Copy(clipboard_data);
139 }
140 
doMouse()141 void TMouse::doMouse() {
142 	INPUT_RECORD InputRecord;
143 	DWORD Result;
144 	InputRecord.EventType = KEY_EVENT; // just in case
145 	while(InputRecord.EventType != MOUSE_EVENT) {
146 		if (!ReadConsoleInput(hConsole, &InputRecord, 1, &Result))
147 			return; // uh oh!  we don't know the starting coordinates!
148 	}
149 	if(InputRecord.Event.MouseEvent.dwButtonState == 0) return;
150 	if(!(InputRecord.Event.MouseEvent.dwButtonState &
151 		FROM_LEFT_1ST_BUTTON_PRESSED)) {
152 		Clipboard.Paste();
153 		return;
154 	}
155 
156 	COORD screen_start = {0, 0};
157     COORD start_coords = InputRecord.Event.MouseEvent.dwMousePosition;
158 	COORD end_coords = start_coords;
159 	BOOL done = FALSE;
160 
161 	// init vars
162 	doMouse_init();
163 	int normal_bg = ini.get_normal_bg();
164 	int normal_fg = ini.get_normal_fg();
165 	if(normal_bg == -1) normal_bg = 0;		// FIX ME!!  This is just a hack
166 	if(normal_fg == -1) normal_fg = 7;
167 	normal = (normal_bg << 4) | normal_fg;
168 	inverse = (normal_fg << 4) | normal_bg;
169 
170 	// make screen all one attribute
171 	FillConsoleOutputAttribute(hStdout, normal, ConsoleInfo.dwSize.X *
172 		ConsoleInfo.dwSize.Y, screen_start, &Result);
173 
174 	while(!done) {
175 
176 		switch (InputRecord.EventType) {
177 		case MOUSE_EVENT:
178 			switch(InputRecord.Event.MouseEvent.dwEventFlags) {
179 			case 0: // only copy if the mouse button has been released
180 				if(!InputRecord.Event.MouseEvent.dwButtonState) {
181 					doClip(start_coords, end_coords);
182 					done = TRUE;
183 				}
184 				break;
185 
186 			case MOUSE_MOVED:
187 				end_coords = InputRecord.Event.MouseEvent.dwMousePosition;
188 				move_mouse(start_coords, end_coords);
189 				break;
190 			}
191 			break;
192 		// If we are changing focus, we don't want to highlight anything
193 		// (Paul Brannan 9/2/98)
194 		case FOCUS_EVENT:
195 			return;
196 		}
197 
198 		WaitForSingleObject(hConsole, INFINITE);
199 		if (!ReadConsoleInput(hConsole, &InputRecord, 1, &Result))
200 			done = TRUE;
201 
202 	}
203 
204 	doMouse_cleanup();
205 }
206 
scrollMouse()207 void TMouse::scrollMouse() {
208 	doMouse();
209 }
210