1 /*-----------------------------------------------------------------------------
3 *-----------------------------------------------------------------------------
4 * Copyright (c) 2004-2005 Kazuo Ishii <k-ishii@wb4.so-net.ne.jp>
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *---------------------------------------------------------------------------*/
23 static int gSelectMode = 0;
24 static COORD gSelectPos = { -1, -1 }; // pick point
25 static SMALL_RECT gSelectRect = { -1, -1, -1, -1 }; // expanded selection area
27 static const wchar_t WORD_BREAK_CHARS[] = {
28 L' ', L'\t', L'\"', L'&', L'\'', L'(', L')', L'*',
29 L',', L';', L'<', L'=', L'>', L'?', L'@', L'[',
30 L'\\', L']', L'^', L'`', L'{', L'}', L'~',
38 /*****************************************************************************/
40 #define SCRN_InvalidArea(x,y) \
41 (y < gCSI->srWindow.Top || \
42 y > gCSI->srWindow.Bottom || \
43 x < gCSI->srWindow.Left || \
44 x > gCSI->srWindow.Right)
46 #define SELECT_GetScrn(x,y) \
47 (gScreen + CSI_WndCols(gCSI) * (y - gCSI->srWindow.Top) + x)
49 static void __select_word_expand_left()
51 if(SCRN_InvalidArea(gSelectRect.Left, gSelectRect.Top))
53 CHAR_INFO* base = SELECT_GetScrn(gSelectRect.Left, gSelectRect.Top);
54 CHAR_INFO* ptr = base;
55 int c = gSelectRect.Left;
57 for( ; c >= gCSI->srWindow.Left ; c--, ptr--) {
58 if(wcschr(WORD_BREAK_CHARS, ptr->Char.UnicodeChar)) {
66 if(gSelectRect.Left > c)
70 static void __select_word_expand_right()
72 if(SCRN_InvalidArea(gSelectRect.Right, gSelectRect.Bottom))
74 CHAR_INFO* base = SELECT_GetScrn(gSelectRect.Right, gSelectRect.Bottom);
75 CHAR_INFO* ptr = base;
76 int c = gSelectRect.Right;
78 for( ; c <= gCSI->srWindow.Right ; c++, ptr++) {
79 if(wcschr(WORD_BREAK_CHARS, ptr->Char.UnicodeChar)) {
84 if(gSelectRect.Right < c)
85 gSelectRect.Right = c;
88 static void __select_char_expand()
92 if(SCRN_InvalidArea(gSelectRect.Left, gSelectRect.Top)) {
94 else if(gSelectRect.Left-1 >= gCSI->srWindow.Left) {
95 base = SELECT_GetScrn(gSelectRect.Left, gSelectRect.Top);
96 if(base->Attributes & COMMON_LVB_TRAILING_BYTE)
100 if(SCRN_InvalidArea(gSelectRect.Right, gSelectRect.Bottom)) {
103 base = SELECT_GetScrn(gSelectRect.Right, gSelectRect.Bottom);
104 if(base->Attributes & COMMON_LVB_TRAILING_BYTE)
109 inline void __select_expand()
111 if(gSelectMode == 0) {
112 __select_char_expand();
114 else if(gSelectMode == 1) {
115 __select_word_expand_left();
116 __select_word_expand_right();
118 else if(gSelectMode == 2) {
119 gSelectRect.Left = gCSI->srWindow.Left;
120 gSelectRect.Right = gCSI->srWindow.Right+1;
124 static void window_to_charpos(int& x, int& y)
132 x += gCSI->srWindow.Left;
133 y += gCSI->srWindow.Top;
134 if(x > gCSI->srWindow.Right) x = gCSI->srWindow.Right+1;
135 if(y > gCSI->srWindow.Bottom) y = gCSI->srWindow.Bottom;
138 /*****************************************************************************/
140 static inline bool __select_invalid()
142 return ( gSelectRect.Top > gSelectRect.Bottom ||
143 (gSelectRect.Top == gSelectRect.Bottom &&
144 gSelectRect.Left >= gSelectRect.Right) );
148 BOOL selectionGetArea(SMALL_RECT& sr)
150 if( __select_invalid() )
157 void selectionClear(HWND hWnd)
159 if( __select_invalid() )
161 gSelectRect.Left = gSelectRect.Right = \
162 gSelectRect.Top = gSelectRect.Bottom = 0;
163 InvalidateRect(hWnd, NULL, FALSE);
167 wchar_t * selectionGetString()
169 if( __select_invalid() )
174 if(gSelectRect.Top == gSelectRect.Bottom) {
175 nb = gSelectRect.Right - gSelectRect.Left;
178 nb = gCSI->srWindow.Right - gSelectRect.Left+1;
179 for(y = gSelectRect.Top+1 ; y <= gSelectRect.Bottom-1 ; y++)
180 nb += CSI_WndCols(gCSI);
181 nb += gSelectRect.Right - gCSI->srWindow.Left;
184 COORD size = { CSI_WndCols(gCSI), 1 };
185 CHAR_INFO* work = new CHAR_INFO[ size.X ];
186 wchar_t* buffer = new wchar_t[ nb +32 ];
187 wchar_t* wp = buffer;
189 SMALL_RECT sr = { gCSI->srWindow.Left, 0, gCSI->srWindow.Right, 0 };
193 if(gSelectRect.Top == gSelectRect.Bottom) {
194 sr.Top = sr.Bottom = gSelectRect.Top;
195 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
196 copyChar(wp, work, gSelectRect.Left, gSelectRect.Right-1, false);
199 sr.Top = sr.Bottom = gSelectRect.Top;
200 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
201 copyChar(wp, work, gSelectRect.Left, gCSI->srWindow.Right);
202 for(y = gSelectRect.Top+1 ; y <= gSelectRect.Bottom-1 ; y++) {
203 sr.Top = sr.Bottom = y;
204 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
205 copyChar(wp, work, gCSI->srWindow.Left, gCSI->srWindow.Right);
207 sr.Top = sr.Bottom = gSelectRect.Bottom;
208 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
209 copyChar(wp, work, gCSI->srWindow.Left, gSelectRect.Right-1, false);
217 void onLBtnDown(HWND hWnd, int x, int y)
219 static DWORD prev_time = 0;
220 static int prevX = -100;
221 static int prevY = -100;
224 /* calc click count */
225 DWORD now_time = GetTickCount();
227 if(prev_time > now_time)
228 stime = now_time + ~prev_time+1;
230 stime = now_time - prev_time;
231 if(stime <= GetDoubleClickTime()) {
232 int sx = (prevX > x) ? prevX-x : x-prevX;
233 int sy = (prevY > y) ? prevY-y : y-prevY;
234 if(sx <= GetSystemMetrics(SM_CXDOUBLECLK) &&
235 sy <= GetSystemMetrics(SM_CYDOUBLECLK)) {
236 if(++gSelectMode > 2)
246 prev_time = now_time;
251 if(!gScreen || !gCSI)
253 window_to_charpos(x, y);
258 gSelectRect.Left = gSelectRect.Right = x;
259 gSelectRect.Top = gSelectRect.Bottom = y;
262 InvalidateRect(hWnd, NULL, FALSE);
266 void onLBtnUp(HWND hWnd, int x, int y)
268 if(hWnd != GetCapture())
271 if(!gScreen || !gCSI)
273 //window_to_charpos(x, y);
275 wchar_t* str = selectionGetString();
278 copyStringToClipboard( hWnd, str );
284 void onMouseMove(HWND hWnd, int x, int y)
286 if(hWnd != GetCapture())
288 if(!gScreen || !gCSI)
290 window_to_charpos(x, y);
292 SMALL_RECT bak = gSelectRect;
294 if(y < gSelectPos.Y || (y == gSelectPos.Y && x < gSelectPos.X)) {
295 gSelectRect.Left = x;
297 gSelectRect.Right = gSelectPos.X;
298 gSelectRect.Bottom = gSelectPos.Y;
301 gSelectRect.Left = gSelectPos.X;
302 gSelectRect.Top = gSelectPos.Y;
303 gSelectRect.Right = x;
304 gSelectRect.Bottom = y;
308 if(memcmp(&bak, &gSelectRect, sizeof(bak))) {
309 InvalidateRect(hWnd, NULL, FALSE);