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 copy_char(wchar_t*& p, CHAR_INFO* src, SHORT start, SHORT end, bool ret = true)
126 CHAR_INFO* pend = src + end;
127 CHAR_INFO* test = src + start;
128 CHAR_INFO* last = test-1;
130 /* search last char */
131 for( ; test <= pend ; test++) {
132 if(test->Char.UnicodeChar > 0x20)
136 for(test = src+start ; test <= last ; test++) {
137 if(!(test->Attributes & COMMON_LVB_TRAILING_BYTE))
138 *p++ = test->Char.UnicodeChar;
140 if(ret && last < pend) {
147 static void window_to_charpos(int& x, int& y)
155 x += gCSI->srWindow.Left;
156 y += gCSI->srWindow.Top;
157 if(x > gCSI->srWindow.Right) x = gCSI->srWindow.Right+1;
158 if(y > gCSI->srWindow.Bottom) y = gCSI->srWindow.Bottom;
161 /*****************************************************************************/
163 #define SELECT_Invalid \
164 (gSelectRect.Top > gSelectRect.Bottom || \
165 (gSelectRect.Top == gSelectRect.Bottom && \
166 gSelectRect.Left >= gSelectRect.Right)) \
169 BOOL selectionGetArea(SMALL_RECT& sr)
178 void selectionClear(HWND hWnd)
182 gSelectRect.Left = gSelectRect.Right = \
183 gSelectRect.Top = gSelectRect.Bottom = 0;
184 InvalidateRect(hWnd, NULL, FALSE);
188 wchar_t* selectionGetString()
195 if(gSelectRect.Top == gSelectRect.Bottom) {
196 nb = gSelectRect.Right - gSelectRect.Left;
199 nb = gCSI->srWindow.Right - gSelectRect.Left+1;
200 for(y = gSelectRect.Top+1 ; y <= gSelectRect.Bottom-1 ; y++)
201 nb += CSI_WndCols(gCSI);
202 nb += gSelectRect.Right - gCSI->srWindow.Left;
205 COORD size = { CSI_WndCols(gCSI), 1 };
206 CHAR_INFO* work = new CHAR_INFO[ size.X ];
207 wchar_t* buffer = new wchar_t[ nb +32 ];
208 wchar_t* wp = buffer;
210 SMALL_RECT sr = { gCSI->srWindow.Left, 0, gCSI->srWindow.Right, 0 };
214 if(gSelectRect.Top == gSelectRect.Bottom) {
215 sr.Top = sr.Bottom = gSelectRect.Top;
216 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
217 copy_char(wp, work, gSelectRect.Left, gSelectRect.Right-1, false);
220 sr.Top = sr.Bottom = gSelectRect.Top;
221 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
222 copy_char(wp, work, gSelectRect.Left, gCSI->srWindow.Right);
223 for(y = gSelectRect.Top+1 ; y <= gSelectRect.Bottom-1 ; y++) {
224 sr.Top = sr.Bottom = y;
225 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
226 copy_char(wp, work, gCSI->srWindow.Left, gCSI->srWindow.Right);
228 sr.Top = sr.Bottom = gSelectRect.Bottom;
229 ReadConsoleOutput_Unicode(gStdOut, work, size, pos, &sr);
230 copy_char(wp, work, gCSI->srWindow.Left, gSelectRect.Right-1, false);
238 void onLBtnDown(HWND hWnd, int x, int y)
240 static DWORD prev_time = 0;
241 static int prevX = -100;
242 static int prevY = -100;
245 /* calc click count */
246 DWORD now_time = GetTickCount();
248 if(prev_time > now_time)
249 stime = now_time + ~prev_time+1;
251 stime = now_time - prev_time;
252 if(stime <= GetDoubleClickTime()) {
253 int sx = (prevX > x) ? prevX-x : x-prevX;
254 int sy = (prevY > y) ? prevY-y : y-prevY;
255 if(sx <= GetSystemMetrics(SM_CXDOUBLECLK) &&
256 sy <= GetSystemMetrics(SM_CYDOUBLECLK)) {
257 if(++gSelectMode > 2)
267 prev_time = now_time;
272 if(!gScreen || !gCSI)
274 window_to_charpos(x, y);
279 gSelectRect.Left = gSelectRect.Right = x;
280 gSelectRect.Top = gSelectRect.Bottom = y;
283 InvalidateRect(hWnd, NULL, FALSE);
287 void onLBtnUp(HWND hWnd, int x, int y)
289 if(hWnd != GetCapture())
292 if(!gScreen || !gCSI)
294 //window_to_charpos(x, y);
296 wchar_t* str = selectionGetString();
299 size_t length = wcslen(str) +1;
304 hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(wchar_t) * length);
305 if(!hMem) result = false;
307 if(result && !(ptr = (wchar_t*) GlobalLock(hMem))) {
311 memcpy(ptr, str, sizeof(wchar_t) * length);
314 if(result && !OpenClipboard(hWnd)) {
316 if(!OpenClipboard(hWnd))
320 if(!EmptyClipboard() ||
321 !SetClipboardData(CF_UNICODETEXT, hMem))
325 if(!result && hMem) {
332 void onMouseMove(HWND hWnd, int x, int y)
334 if(hWnd != GetCapture())
336 if(!gScreen || !gCSI)
338 window_to_charpos(x, y);
340 SMALL_RECT bak = gSelectRect;
342 if(y < gSelectPos.Y || (y == gSelectPos.Y && x < gSelectPos.X)) {
343 gSelectRect.Left = x;
345 gSelectRect.Right = gSelectPos.X;
346 gSelectRect.Bottom = gSelectPos.Y;
349 gSelectRect.Left = gSelectPos.X;
350 gSelectRect.Top = gSelectPos.Y;
351 gSelectRect.Right = x;
352 gSelectRect.Bottom = y;
356 if(memcmp(&bak, &gSelectRect, sizeof(bak))) {
357 InvalidateRect(hWnd, NULL, FALSE);