mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 13:13:00 +00:00
Sync with trunk r63637.
svn path=/branches/shell-experiments/; revision=63640
This commit is contained in:
commit
73d72624b0
410 changed files with 4745 additions and 12328 deletions
|
@ -63,8 +63,8 @@ extern const FLOATOBJ gef16;
|
|||
#define FLOATOBJ_16 {0x40000000, 0x00000006}
|
||||
#define FLOATOBJ_1_16 {0x40000000, 0xfffffffe}
|
||||
|
||||
#define FLOATOBJ_Set0(fo) (fo)->ul1 = 0; (fo)->ul2 = 0;
|
||||
#define FLOATOBJ_Set1(fo) (fo)->ul1 = 0x40000000; (fo)->ul2 = 2;
|
||||
#define FLOATOBJ_Set0(fo) do { (fo)->ul1 = 0; (fo)->ul2 = 0; } while (0)
|
||||
#define FLOATOBJ_Set1(fo) do { (fo)->ul1 = 0x40000000; (fo)->ul2 = 2; } while (0)
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -382,7 +382,7 @@ EngLoadImageEx(
|
|||
if (pldev->pGdiDriverInfo)
|
||||
{
|
||||
/* Check for match (case insensative) */
|
||||
if (RtlEqualUnicodeString(&pldev->pGdiDriverInfo->DriverName, &strDriverName, 1))
|
||||
if (RtlEqualUnicodeString(&pldev->pGdiDriverInfo->DriverName, &strDriverName, TRUE))
|
||||
{
|
||||
/* Image found in LDEV list */
|
||||
break;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <ftoutln.h>
|
||||
#include <ftwinfnt.h>
|
||||
|
||||
#include <gdi/eng/floatobj.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
|
@ -3228,6 +3230,7 @@ GreExtTextOutW(
|
|||
USHORT DxShift;
|
||||
PMATRIX pmxWorldToDevice;
|
||||
LONG fixAscender, fixDescender;
|
||||
FLOATOBJ Scale;
|
||||
|
||||
// TODO: Write test-cases to exactly match real Windows in different
|
||||
// bad parameters (e.g. does Windows check the DC or the RECT first?).
|
||||
|
@ -3671,8 +3674,13 @@ GreExtTextOutW(
|
|||
}
|
||||
else
|
||||
{
|
||||
TextLeft += Dx[i<<DxShift] << 6;
|
||||
DPRINT("New TextLeft2: %I64d\n", TextLeft);
|
||||
Scale = pdcattr->mxWorldToDevice.efM11;
|
||||
if (_FLOATOBJ_Equal0(&Scale))
|
||||
FLOATOBJ_Set1(&Scale);
|
||||
|
||||
FLOATOBJ_MulLong(&Scale, Dx[i<<DxShift] << 6); // do the shift before multiplying to preserve precision
|
||||
TextLeft += FLOATOBJ_GetLong(&Scale);
|
||||
DPRINT("New TextLeft2: %I64d\n", TextLeft);
|
||||
}
|
||||
|
||||
if (DxShift)
|
||||
|
|
|
@ -70,7 +70,6 @@ typedef enum _USERTHREADINFOCLASS
|
|||
UserThreadWOWInformation,
|
||||
UserThreadHungStatus,
|
||||
UserThreadInitiateShutdown,
|
||||
|
||||
UserThreadEndShutdown,
|
||||
UserThreadUseActiveDesktop,
|
||||
UserThreadUseDesktop,
|
||||
|
@ -3385,7 +3384,6 @@ typedef struct tagKMDDELPARAM
|
|||
#define MSQ_STATE_MENUOWNER 0x4
|
||||
#define MSQ_STATE_MOVESIZE 0x5
|
||||
#define MSQ_STATE_CARET 0x6
|
||||
#define TWOPARAM_ROUTINE_SETCARETPOS 0xfffd0060
|
||||
#define TWOPARAM_ROUTINE_ROS_UPDATEUISTATE 0x1004
|
||||
#define HWNDPARAM_ROUTINE_ROS_NOTIFYWINEVENT 0x1005
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ IntDesktopObjectParse(IN PVOID ParseObject,
|
|||
/* Compare the name */
|
||||
if (RtlEqualUnicodeString(RemainingName,
|
||||
&DesktopName,
|
||||
(Attributes & OBJ_CASE_INSENSITIVE)))
|
||||
(Attributes & OBJ_CASE_INSENSITIVE) != 0))
|
||||
{
|
||||
/* We found a match. Did this come from a create? */
|
||||
if (Context)
|
||||
|
|
|
@ -101,11 +101,13 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
|
|||
HANDLE OldTID, NewTID;
|
||||
PTHREADINFO pti, ptiOld, ptiNew;
|
||||
BOOL InAAPM = FALSE;
|
||||
|
||||
//ERR("SendActivateMessages\n");
|
||||
|
||||
pti = PsGetCurrentThreadWin32Thread();
|
||||
|
||||
if (Window)
|
||||
{
|
||||
|
||||
UserRefObjectCo(Window, &Ref);
|
||||
|
||||
if (WindowPrev) UserRefObjectCo(WindowPrev, &RefPrev);
|
||||
|
@ -163,8 +165,62 @@ co_IntSendActivateMessages(PWND WindowPrev, PWND Window, BOOL MouseActivate, BOO
|
|||
ExFreePool(phwndTopLevel);
|
||||
}
|
||||
}
|
||||
////
|
||||
}
|
||||
////
|
||||
OldTID = WindowPrev ? IntGetWndThreadId(WindowPrev) : NULL;
|
||||
NewTID = Window ? IntGetWndThreadId(Window) : NULL;
|
||||
ptiOld = WindowPrev ? WindowPrev->head.pti : NULL;
|
||||
ptiNew = Window ? Window->head.pti : NULL;
|
||||
|
||||
//ERR("SendActivateMessage Old -> %x, New -> %x\n", OldTID, NewTID);
|
||||
|
||||
if (!(pti->TIF_flags & TIF_INACTIVATEAPPMSG) &&
|
||||
(!WindowPrev || OldTID != NewTID) )
|
||||
{
|
||||
PWND cWindow;
|
||||
HWND *List, *phWnd;
|
||||
|
||||
List = IntWinListChildren(UserGetDesktopWindow());
|
||||
if ( List )
|
||||
{
|
||||
if ( OldTID )
|
||||
{
|
||||
ptiOld->TIF_flags |= TIF_INACTIVATEAPPMSG;
|
||||
// Note: Do not set pci flags, this does crash!
|
||||
for (phWnd = List; *phWnd; ++phWnd)
|
||||
{
|
||||
cWindow = ValidateHwndNoErr(*phWnd);
|
||||
if (cWindow && cWindow->head.pti == ptiOld)
|
||||
{ // FALSE if the window is being deactivated,
|
||||
// ThreadId that owns the window being activated.
|
||||
//ERR("SendActivateMessage Old\n");
|
||||
co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, FALSE, (LPARAM)NewTID);
|
||||
}
|
||||
}
|
||||
ptiOld->TIF_flags &= ~TIF_INACTIVATEAPPMSG;
|
||||
}
|
||||
if ( NewTID )
|
||||
{ //// Prevents a resource crash due to reentrance!
|
||||
InAAPM = TRUE;
|
||||
pti->TIF_flags |= TIF_INACTIVATEAPPMSG;
|
||||
////
|
||||
for (phWnd = List; *phWnd; ++phWnd)
|
||||
{
|
||||
cWindow = ValidateHwndNoErr(*phWnd);
|
||||
if (cWindow && cWindow->head.pti == ptiNew)
|
||||
{ // TRUE if the window is being activated,
|
||||
// ThreadId that owns the window being deactivated.
|
||||
//ERR("SendActivateMessage New\n");
|
||||
co_IntSendMessageNoWait(*phWnd, WM_ACTIVATEAPP, TRUE, (LPARAM)OldTID);
|
||||
}
|
||||
}
|
||||
}
|
||||
ExFreePoolWithTag(List, USERTAG_WINDOWLIST);
|
||||
}
|
||||
}
|
||||
|
||||
if (Window)
|
||||
{
|
||||
if (WindowPrev)
|
||||
UserDerefObjectCo(WindowPrev); // Now allow the previous window to die.
|
||||
|
||||
|
@ -542,7 +598,7 @@ IntFindChildWindowToOwner(PWND Root, PWND Owner)
|
|||
|
||||
for(Child = Root->spwndChild; Child; Child = Child->spwndNext)
|
||||
{
|
||||
OwnerWnd = Child->spwndOwner;
|
||||
OwnerWnd = Child->spwndOwner;
|
||||
if(!OwnerWnd)
|
||||
continue;
|
||||
|
||||
|
|
|
@ -1369,7 +1369,7 @@ BOOL co_IntProcessMouseMessage(MSG* msg, BOOL* RemoveMessages, UINT first, UINT
|
|||
}
|
||||
else
|
||||
{
|
||||
pwndMsg = co_WinPosWindowFromPoint(NULL, &msg->pt, &hittest, TRUE);
|
||||
pwndMsg = co_WinPosWindowFromPoint(NULL, &msg->pt, &hittest, FALSE);//TRUE);
|
||||
}
|
||||
|
||||
TRACE("Got mouse message for %p, hittest: 0x%x\n", msg->hwnd, hittest);
|
||||
|
|
|
@ -2141,7 +2141,13 @@ NtUserInvalidateRect(
|
|||
CONST RECT *lpUnsafeRect,
|
||||
BOOL bErase)
|
||||
{
|
||||
return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
|
||||
UINT flags = RDW_INVALIDATE | (bErase ? RDW_ERASE : 0);
|
||||
if (!hWnd)
|
||||
{
|
||||
flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW;
|
||||
lpUnsafeRect = NULL;
|
||||
}
|
||||
return NtUserRedrawWindow(hWnd, lpUnsafeRect, NULL, flags);
|
||||
}
|
||||
|
||||
BOOL
|
||||
|
@ -2151,6 +2157,11 @@ NtUserInvalidateRgn(
|
|||
HRGN hRgn,
|
||||
BOOL bErase)
|
||||
{
|
||||
if (!hWnd)
|
||||
{
|
||||
EngSetLastError( ERROR_INVALID_WINDOW_HANDLE );
|
||||
return FALSE;
|
||||
}
|
||||
return NtUserRedrawWindow(hWnd, NULL, hRgn, RDW_INVALIDATE | (bErase? RDW_ERASE : 0));
|
||||
}
|
||||
|
||||
|
@ -2197,11 +2208,13 @@ NtUserValidateRect(
|
|||
HWND hWnd,
|
||||
const RECT *lpRect)
|
||||
{
|
||||
if (hWnd)
|
||||
UINT flags = RDW_VALIDATE;
|
||||
if (!hWnd)
|
||||
{
|
||||
return NtUserRedrawWindow(hWnd, lpRect, NULL, RDW_VALIDATE );
|
||||
flags = RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ERASENOW;
|
||||
lpRect = NULL;
|
||||
}
|
||||
return NtUserRedrawWindow(hWnd, lpRect, NULL, RDW_INVALIDATE|RDW_ERASE|RDW_ERASENOW|RDW_ALLCHILDREN);
|
||||
return NtUserRedrawWindow(hWnd, lpRect, NULL, flags);
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -451,7 +451,6 @@ NtUserCreateWindowStation(
|
|||
/* Initialize the window station */
|
||||
RtlZeroMemory(WindowStationObject, sizeof(WINSTATION_OBJECT));
|
||||
|
||||
KeInitializeSpinLock(&WindowStationObject->Lock);
|
||||
InitializeListHead(&WindowStationObject->DesktopListHead);
|
||||
Status = RtlCreateAtomTable(37, &WindowStationObject->AtomTable);
|
||||
WindowStationObject->Name = WindowStationName;
|
||||
|
@ -1203,7 +1202,6 @@ BuildDesktopNameList(
|
|||
{
|
||||
NTSTATUS Status;
|
||||
PWINSTATION_OBJECT WindowStation;
|
||||
KIRQL OldLevel;
|
||||
PLIST_ENTRY DesktopEntry;
|
||||
PDESKTOP DesktopObject;
|
||||
DWORD EntryCount;
|
||||
|
@ -1220,8 +1218,6 @@ BuildDesktopNameList(
|
|||
return Status;
|
||||
}
|
||||
|
||||
KeAcquireSpinLock(&WindowStation->Lock, &OldLevel);
|
||||
|
||||
/*
|
||||
* Count the required size of buffer.
|
||||
*/
|
||||
|
@ -1242,7 +1238,6 @@ BuildDesktopNameList(
|
|||
Status = MmCopyToCaller(pRequiredSize, &ReturnLength, sizeof(ULONG));
|
||||
if (! NT_SUCCESS(Status))
|
||||
{
|
||||
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
|
||||
ObDereferenceObject(WindowStation);
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
@ -1253,7 +1248,6 @@ BuildDesktopNameList(
|
|||
*/
|
||||
if (dwSize < ReturnLength)
|
||||
{
|
||||
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
|
||||
ObDereferenceObject(WindowStation);
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
@ -1264,7 +1258,6 @@ BuildDesktopNameList(
|
|||
Status = MmCopyToCaller(lpBuffer, &EntryCount, sizeof(DWORD));
|
||||
if (! NT_SUCCESS(Status))
|
||||
{
|
||||
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
|
||||
ObDereferenceObject(WindowStation);
|
||||
return Status;
|
||||
}
|
||||
|
@ -1280,7 +1273,6 @@ BuildDesktopNameList(
|
|||
Status = MmCopyToCaller(lpBuffer, DesktopName.Buffer, DesktopName.Length);
|
||||
if (! NT_SUCCESS(Status))
|
||||
{
|
||||
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
|
||||
ObDereferenceObject(WindowStation);
|
||||
return Status;
|
||||
}
|
||||
|
@ -1288,7 +1280,6 @@ BuildDesktopNameList(
|
|||
Status = MmCopyToCaller(lpBuffer, &NullWchar, sizeof(WCHAR));
|
||||
if (! NT_SUCCESS(Status))
|
||||
{
|
||||
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
|
||||
ObDereferenceObject(WindowStation);
|
||||
return Status;
|
||||
}
|
||||
|
@ -1296,11 +1287,9 @@ BuildDesktopNameList(
|
|||
}
|
||||
|
||||
/*
|
||||
* Clean up
|
||||
* Clean up and return
|
||||
*/
|
||||
KeReleaseSpinLock(&WindowStation->Lock, OldLevel);
|
||||
ObDereferenceObject(WindowStation);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ typedef struct _WINSTATION_OBJECT
|
|||
{
|
||||
DWORD dwSessionId;
|
||||
|
||||
KSPIN_LOCK Lock;
|
||||
UNICODE_STRING Name;
|
||||
LIST_ENTRY DesktopListHead;
|
||||
PRTL_ATOM_TABLE AtomTable;
|
||||
|
|
|
@ -17,7 +17,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(user32);
|
|||
#define MAX_WINDOWS 120
|
||||
|
||||
// Global variables
|
||||
HWND switchdialog;
|
||||
HWND switchdialog = NULL;
|
||||
HFONT dialogFont;
|
||||
int selectedWindow = 0;
|
||||
BOOL isOpen = FALSE;
|
||||
|
@ -334,19 +334,26 @@ void ProcessHotKey()
|
|||
|
||||
LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
HWND hwnd;
|
||||
HWND hwnd, hwndActive;
|
||||
MSG msg;
|
||||
BOOL Esc = FALSE;
|
||||
INT Count = 0;
|
||||
WCHAR Text[1024];
|
||||
|
||||
switchdialog = NULL;
|
||||
// Already in the loop.
|
||||
if (switchdialog) return 0;
|
||||
|
||||
hwndActive = GetActiveWindow();
|
||||
// Nothing is active so exit.
|
||||
if (!hwndActive) return 0;
|
||||
// Capture current active window.
|
||||
SetCapture( hwndActive );
|
||||
|
||||
switch (lParam)
|
||||
{
|
||||
case VK_TAB:
|
||||
if( !CreateSwitcherWindow(User32Instance) ) return 0;
|
||||
if( !GetDialogFont() ) return 0;
|
||||
if( !CreateSwitcherWindow(User32Instance) ) goto Exit;
|
||||
if( !GetDialogFont() ) goto Exit;
|
||||
ProcessHotKey();
|
||||
break;
|
||||
|
||||
|
@ -354,7 +361,7 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
|
|||
windowCount = 0;
|
||||
Count = 0;
|
||||
EnumWindowsZOrder(EnumerateCallback, 0);
|
||||
if (windowCount < 2) return 0;
|
||||
if (windowCount < 2) goto Exit;
|
||||
if (wParam == SC_NEXTWINDOW)
|
||||
Count = 1;
|
||||
else
|
||||
|
@ -373,7 +380,7 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
|
|||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
goto Exit;
|
||||
}
|
||||
// Main message loop:
|
||||
while (1)
|
||||
|
@ -471,6 +478,7 @@ LRESULT WINAPI DoAppSwitch( WPARAM wParam, LPARAM lParam )
|
|||
}
|
||||
}
|
||||
Exit:
|
||||
ReleaseCapture();
|
||||
if (switchdialog) DestroyWindow(switchdialog);
|
||||
switchdialog = NULL;
|
||||
selectedWindow = 0;
|
||||
|
|
|
@ -636,8 +636,9 @@ static void TEXT_WordBreak (HDC hdc, WCHAR *str, unsigned int max_str,
|
|||
DT_EDITCONTROL)
|
||||
{
|
||||
/* break the word after the last character that fits (there must be
|
||||
* at least one; none is caught earlier).
|
||||
*/
|
||||
* at least one). */
|
||||
if (!chars_fit)
|
||||
++chars_fit;
|
||||
*len_str = chars_fit;
|
||||
*chars_used = chars_fit;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <consrv.h>
|
||||
|
||||
#include <intrin.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#define NDEBUG
|
||||
|
@ -250,7 +250,8 @@ AppendMenuItems(HMENU hMenu,
|
|||
} while (!(Items[i].uID == 0 && Items[i].SubMenu == NULL && Items[i].wCmdID == 0));
|
||||
}
|
||||
|
||||
static VOID
|
||||
//static
|
||||
VOID
|
||||
CreateSysMenu(HWND hWnd)
|
||||
{
|
||||
MENUITEMINFOW mii;
|
||||
|
@ -301,7 +302,9 @@ Copy(PGUI_CONSOLE_DATA GuiData);
|
|||
static VOID
|
||||
Paste(PGUI_CONSOLE_DATA GuiData);
|
||||
static VOID
|
||||
UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord);
|
||||
UpdateSelection(PGUI_CONSOLE_DATA GuiData,
|
||||
PCOORD SelectionAnchor OPTIONAL,
|
||||
PCOORD coord);
|
||||
|
||||
static VOID
|
||||
Mark(PGUI_CONSOLE_DATA GuiData)
|
||||
|
@ -309,30 +312,28 @@ Mark(PGUI_CONSOLE_DATA GuiData)
|
|||
PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
|
||||
|
||||
/* Clear the old selection */
|
||||
// UpdateSelection(GuiData, NULL);
|
||||
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
|
||||
|
||||
/* Restart a new selection */
|
||||
GuiData->dwSelectionCursor.X = ActiveBuffer->ViewOrigin.X;
|
||||
GuiData->dwSelectionCursor.Y = ActiveBuffer->ViewOrigin.Y;
|
||||
GuiData->Selection.dwSelectionAnchor = GuiData->dwSelectionCursor;
|
||||
UpdateSelection(GuiData, &GuiData->Selection.dwSelectionAnchor);
|
||||
GuiData->dwSelectionCursor = ActiveBuffer->ViewOrigin;
|
||||
UpdateSelection(GuiData,
|
||||
&GuiData->dwSelectionCursor,
|
||||
&GuiData->dwSelectionCursor);
|
||||
}
|
||||
|
||||
static VOID
|
||||
SelectAll(PGUI_CONSOLE_DATA GuiData)
|
||||
{
|
||||
PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
|
||||
COORD SelectionAnchor;
|
||||
|
||||
/* Clear the old selection */
|
||||
// UpdateSelection(GuiData, NULL);
|
||||
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
|
||||
|
||||
/*
|
||||
* The selection area extends to the whole screen buffer's width.
|
||||
*/
|
||||
GuiData->Selection.dwSelectionAnchor.X = 0;
|
||||
GuiData->Selection.dwSelectionAnchor.Y = 0;
|
||||
SelectionAnchor.X = SelectionAnchor.Y = 0;
|
||||
GuiData->dwSelectionCursor.X = ActiveBuffer->ScreenBufferSize.X - 1;
|
||||
|
||||
/*
|
||||
|
@ -358,7 +359,7 @@ SelectAll(PGUI_CONSOLE_DATA GuiData)
|
|||
|
||||
/* Restart a new selection */
|
||||
GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION;
|
||||
UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
|
||||
UpdateSelection(GuiData, &SelectionAnchor, &GuiData->dwSelectionCursor);
|
||||
}
|
||||
|
||||
static LRESULT
|
||||
|
@ -587,7 +588,8 @@ OnNcCreate(HWND hWnd, LPCREATESTRUCTW Create)
|
|||
SetWindowLongPtrW(GuiData->hWindow, GWLP_USERDATA, (DWORD_PTR)GuiData);
|
||||
|
||||
SetTimer(GuiData->hWindow, CONGUI_UPDATE_TIMER, CONGUI_UPDATE_TIME, NULL);
|
||||
CreateSysMenu(GuiData->hWindow);
|
||||
// FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
|
||||
//CreateSysMenu(GuiData->hWindow);
|
||||
|
||||
DPRINT("OnNcCreate - setting start event\n");
|
||||
SetEvent(GuiData->hGuiInitEvent);
|
||||
|
@ -678,18 +680,162 @@ SmallRectToRect(PGUI_CONSOLE_DATA GuiData, PRECT Rect, PSMALL_RECT SmallRect)
|
|||
Rect->bottom = (SmallRect->Bottom + 1 - Buffer->ViewOrigin.Y) * HeightUnit;
|
||||
}
|
||||
|
||||
VOID
|
||||
GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
|
||||
PCOORD SelectionAnchor,
|
||||
PSMALL_RECT SmallRect)
|
||||
{
|
||||
if (Begin == NULL || End == NULL) return;
|
||||
|
||||
*Begin = *SelectionAnchor;
|
||||
End->X = (SelectionAnchor->X == SmallRect->Left) ? SmallRect->Right
|
||||
/* Case X != Left, must be == Right */ : SmallRect->Left;
|
||||
End->Y = (SelectionAnchor->Y == SmallRect->Top ) ? SmallRect->Bottom
|
||||
/* Case Y != Top, must be == Bottom */ : SmallRect->Top;
|
||||
|
||||
/* Exchange Begin / End if Begin > End lexicographically */
|
||||
if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X))
|
||||
{
|
||||
End->X = _InterlockedExchange16(&Begin->X, End->X);
|
||||
End->Y = _InterlockedExchange16(&Begin->Y, End->Y);
|
||||
}
|
||||
}
|
||||
|
||||
static HRGN
|
||||
CreateSelectionRgn(PGUI_CONSOLE_DATA GuiData,
|
||||
BOOL LineSelection,
|
||||
PCOORD SelectionAnchor,
|
||||
PSMALL_RECT SmallRect)
|
||||
{
|
||||
if (!LineSelection)
|
||||
{
|
||||
RECT rect;
|
||||
SmallRectToRect(GuiData, &rect, SmallRect);
|
||||
return CreateRectRgnIndirect(&rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
HRGN SelRgn;
|
||||
COORD Begin, End;
|
||||
|
||||
GetSelectionBeginEnd(&Begin, &End, SelectionAnchor, SmallRect);
|
||||
|
||||
if (Begin.Y == End.Y)
|
||||
{
|
||||
SMALL_RECT sr;
|
||||
RECT r ;
|
||||
|
||||
sr.Left = Begin.X;
|
||||
sr.Top = Begin.Y;
|
||||
sr.Right = End.X;
|
||||
sr.Bottom = End.Y;
|
||||
|
||||
// Debug thingie to see whether I can put this corner case
|
||||
// together with the previous one.
|
||||
if (SmallRect->Left != sr.Left ||
|
||||
SmallRect->Top != sr.Top ||
|
||||
SmallRect->Right != sr.Right ||
|
||||
SmallRect->Bottom != sr.Bottom)
|
||||
{
|
||||
DPRINT1("\n"
|
||||
"SmallRect = (%d, %d, %d, %d)\n"
|
||||
"sr = (%d, %d, %d, %d)\n"
|
||||
"\n",
|
||||
SmallRect->Left, SmallRect->Top, SmallRect->Right, SmallRect->Bottom,
|
||||
sr.Left, sr.Top, sr.Right, sr.Bottom);
|
||||
}
|
||||
|
||||
SmallRectToRect(GuiData, &r, &sr);
|
||||
SelRgn = CreateRectRgnIndirect(&r);
|
||||
}
|
||||
else
|
||||
{
|
||||
PCONSOLE_SCREEN_BUFFER ActiveBuffer = GuiData->ActiveBuffer;
|
||||
|
||||
HRGN rg1, rg2, rg3;
|
||||
SMALL_RECT sr1, sr2, sr3;
|
||||
RECT r1 , r2 , r3 ;
|
||||
|
||||
sr1.Left = Begin.X;
|
||||
sr1.Top = Begin.Y;
|
||||
sr1.Right = ActiveBuffer->ScreenBufferSize.X - 1;
|
||||
sr1.Bottom = Begin.Y;
|
||||
|
||||
sr2.Left = 0;
|
||||
sr2.Top = Begin.Y + 1;
|
||||
sr2.Right = ActiveBuffer->ScreenBufferSize.X - 1;
|
||||
sr2.Bottom = End.Y - 1;
|
||||
|
||||
sr3.Left = 0;
|
||||
sr3.Top = End.Y;
|
||||
sr3.Right = End.X;
|
||||
sr3.Bottom = End.Y;
|
||||
|
||||
SmallRectToRect(GuiData, &r1, &sr1);
|
||||
SmallRectToRect(GuiData, &r2, &sr2);
|
||||
SmallRectToRect(GuiData, &r3, &sr3);
|
||||
|
||||
rg1 = CreateRectRgnIndirect(&r1);
|
||||
rg2 = CreateRectRgnIndirect(&r2);
|
||||
rg3 = CreateRectRgnIndirect(&r3);
|
||||
|
||||
CombineRgn(rg1, rg1, rg2, RGN_XOR);
|
||||
CombineRgn(rg1, rg1, rg3, RGN_XOR);
|
||||
DeleteObject(rg3);
|
||||
DeleteObject(rg2);
|
||||
|
||||
SelRgn = rg1;
|
||||
}
|
||||
|
||||
return SelRgn;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID
|
||||
UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
|
||||
PaintSelectionRect(PGUI_CONSOLE_DATA GuiData, PPAINTSTRUCT pps)
|
||||
{
|
||||
HRGN rgnPaint = CreateRectRgnIndirect(&pps->rcPaint);
|
||||
HRGN rgnSel = CreateSelectionRgn(GuiData, GuiData->LineSelection,
|
||||
&GuiData->Selection.dwSelectionAnchor,
|
||||
&GuiData->Selection.srSelection);
|
||||
|
||||
/* Invert the selection */
|
||||
|
||||
int ErrorCode = CombineRgn(rgnPaint, rgnPaint, rgnSel, RGN_AND);
|
||||
if (ErrorCode != ERROR && ErrorCode != NULLREGION)
|
||||
{
|
||||
InvertRgn(pps->hdc, rgnPaint);
|
||||
}
|
||||
|
||||
DeleteObject(rgnSel);
|
||||
DeleteObject(rgnPaint);
|
||||
}
|
||||
|
||||
static VOID
|
||||
UpdateSelection(PGUI_CONSOLE_DATA GuiData,
|
||||
PCOORD SelectionAnchor OPTIONAL,
|
||||
PCOORD coord)
|
||||
{
|
||||
PCONSOLE Console = GuiData->Console;
|
||||
RECT oldRect;
|
||||
HRGN oldRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
|
||||
&GuiData->Selection.dwSelectionAnchor,
|
||||
&GuiData->Selection.srSelection);
|
||||
|
||||
SmallRectToRect(GuiData, &oldRect, &GuiData->Selection.srSelection);
|
||||
/* Update the anchor if needed (use the old one if NULL) */
|
||||
if (SelectionAnchor)
|
||||
GuiData->Selection.dwSelectionAnchor = *SelectionAnchor;
|
||||
|
||||
if (coord != NULL)
|
||||
{
|
||||
RECT newRect;
|
||||
SMALL_RECT rc;
|
||||
HRGN newRgn;
|
||||
|
||||
/*
|
||||
* Pressing the Control key while selecting text, allows us to enter
|
||||
* into line-selection mode, the selection mode of *nix terminals.
|
||||
*/
|
||||
BOOL OldLineSel = GuiData->LineSelection;
|
||||
GuiData->LineSelection = !!(GetKeyState(VK_CONTROL) & 0x8000);
|
||||
|
||||
/* Exchange left/top with right/bottom if required */
|
||||
rc.Left = min(GuiData->Selection.dwSelectionAnchor.X, coord->X);
|
||||
|
@ -697,64 +843,72 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
|
|||
rc.Right = max(GuiData->Selection.dwSelectionAnchor.X, coord->X);
|
||||
rc.Bottom = max(GuiData->Selection.dwSelectionAnchor.Y, coord->Y);
|
||||
|
||||
SmallRectToRect(GuiData, &newRect, &rc);
|
||||
newRgn = CreateSelectionRgn(GuiData, GuiData->LineSelection,
|
||||
&GuiData->Selection.dwSelectionAnchor,
|
||||
&rc);
|
||||
|
||||
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
|
||||
{
|
||||
if (memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
|
||||
if (OldLineSel != GuiData->LineSelection ||
|
||||
memcmp(&rc, &GuiData->Selection.srSelection, sizeof(SMALL_RECT)) != 0)
|
||||
{
|
||||
HRGN rgn1, rgn2;
|
||||
|
||||
/* Calculate the region that needs to be updated */
|
||||
if ((rgn1 = CreateRectRgnIndirect(&oldRect)))
|
||||
if (oldRgn && newRgn && CombineRgn(newRgn, newRgn, oldRgn, RGN_XOR) != ERROR)
|
||||
{
|
||||
if ((rgn2 = CreateRectRgnIndirect(&newRect)))
|
||||
{
|
||||
if (CombineRgn(rgn1, rgn2, rgn1, RGN_XOR) != ERROR)
|
||||
{
|
||||
InvalidateRgn(GuiData->hWindow, rgn1, FALSE);
|
||||
}
|
||||
DeleteObject(rgn2);
|
||||
}
|
||||
DeleteObject(rgn1);
|
||||
InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidateRect(GuiData->hWindow, &newRect, FALSE);
|
||||
InvalidateRgn(GuiData->hWindow, newRgn, FALSE);
|
||||
}
|
||||
|
||||
DeleteObject(newRgn);
|
||||
|
||||
GuiData->Selection.dwFlags |= CONSOLE_SELECTION_NOT_EMPTY;
|
||||
GuiData->Selection.srSelection = rc;
|
||||
GuiData->dwSelectionCursor = *coord;
|
||||
|
||||
if ((GuiData->Selection.dwFlags & CONSOLE_SELECTION_IN_PROGRESS) == 0)
|
||||
{
|
||||
LPWSTR SelectionType, WindowTitle = NULL;
|
||||
SIZE_T Length = 0;
|
||||
LPWSTR SelTypeStr = NULL , WindowTitle = NULL;
|
||||
SIZE_T SelTypeStrLength = 0, Length = 0;
|
||||
|
||||
/* Clear the old selection */
|
||||
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
|
||||
{
|
||||
InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
|
||||
InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
|
||||
}
|
||||
|
||||
if (GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
|
||||
{
|
||||
SelectionType = L"Selection - ";
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectionType = L"Mark - ";
|
||||
}
|
||||
/*
|
||||
* When passing a zero-length buffer size, LoadString(...) returns
|
||||
* a read-only pointer buffer to the program's resource string.
|
||||
*/
|
||||
SelTypeStrLength =
|
||||
LoadStringW(ConSrvDllInstance,
|
||||
(GuiData->Selection.dwFlags & CONSOLE_MOUSE_SELECTION)
|
||||
? IDS_SELECT_TITLE : IDS_MARK_TITLE,
|
||||
(LPWSTR)&SelTypeStr, 0);
|
||||
|
||||
Length = Console->Title.Length + wcslen(SelectionType) + 1;
|
||||
WindowTitle = ConsoleAllocHeap(0, Length * sizeof(WCHAR));
|
||||
wcscpy(WindowTitle, SelectionType);
|
||||
wcscat(WindowTitle, Console->Title.Buffer);
|
||||
SetWindowText(GuiData->hWindow, WindowTitle);
|
||||
ConsoleFreeHeap(WindowTitle);
|
||||
/*
|
||||
* Prepend the selection type string to the current console title
|
||||
* if we succeeded in retrieving a valid localized string.
|
||||
*/
|
||||
if (SelTypeStr)
|
||||
{
|
||||
// 3 for " - " and 1 for NULL
|
||||
Length = Console->Title.Length + (SelTypeStrLength + 3 + 1) * sizeof(WCHAR);
|
||||
WindowTitle = ConsoleAllocHeap(0, Length);
|
||||
|
||||
wcsncpy(WindowTitle, SelTypeStr, SelTypeStrLength);
|
||||
WindowTitle[SelTypeStrLength] = L'\0';
|
||||
wcscat(WindowTitle, L" - ");
|
||||
wcscat(WindowTitle, Console->Title.Buffer);
|
||||
|
||||
SetWindowText(GuiData->hWindow, WindowTitle);
|
||||
ConsoleFreeHeap(WindowTitle);
|
||||
}
|
||||
|
||||
GuiData->Selection.dwFlags |= CONSOLE_SELECTION_IN_PROGRESS;
|
||||
ConioPause(Console, PAUSED_FROM_SELECTION);
|
||||
|
@ -765,14 +919,17 @@ UpdateSelection(PGUI_CONSOLE_DATA GuiData, PCOORD coord)
|
|||
/* Clear the selection */
|
||||
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
|
||||
{
|
||||
InvalidateRect(GuiData->hWindow, &oldRect, FALSE);
|
||||
InvalidateRgn(GuiData->hWindow, oldRgn, FALSE);
|
||||
}
|
||||
|
||||
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
|
||||
ConioUnpause(Console, PAUSED_FROM_SELECTION);
|
||||
|
||||
/* Restore the console title */
|
||||
SetWindowText(GuiData->hWindow, Console->Title.Buffer);
|
||||
}
|
||||
|
||||
DeleteObject(oldRgn);
|
||||
}
|
||||
|
||||
|
||||
|
@ -826,15 +983,10 @@ OnPaint(PGUI_CONSOLE_DATA GuiData)
|
|||
rcPaint.top,
|
||||
SRCCOPY);
|
||||
|
||||
/* Draw the selection region if needed */
|
||||
if (GuiData->Selection.dwFlags & CONSOLE_SELECTION_NOT_EMPTY)
|
||||
{
|
||||
SmallRectToRect(GuiData, &rcPaint, &GuiData->Selection.srSelection);
|
||||
|
||||
/* Invert the selection */
|
||||
if (IntersectRect(&rcPaint, &ps.rcPaint, &rcPaint))
|
||||
{
|
||||
InvertRect(ps.hdc, &rcPaint);
|
||||
}
|
||||
PaintSelectionRect(GuiData, &ps);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&GuiData->Lock);
|
||||
|
@ -911,10 +1063,10 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
goto Quit;
|
||||
}
|
||||
else if ( VirtualKeyCode == VK_ESCAPE ||
|
||||
(VirtualKeyCode == 'C' && GetKeyState(VK_CONTROL) & 0x8000) )
|
||||
(VirtualKeyCode == 'C' && (GetKeyState(VK_CONTROL) & 0x8000)) )
|
||||
{
|
||||
/* Cancel selection if ESC or Ctrl-C are pressed */
|
||||
UpdateSelection(GuiData, NULL);
|
||||
UpdateSelection(GuiData, NULL, NULL);
|
||||
goto Quit;
|
||||
}
|
||||
|
||||
|
@ -922,7 +1074,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
{
|
||||
/* Keyboard selection mode */
|
||||
BOOL Interpreted = FALSE;
|
||||
BOOL MajPressed = (GetKeyState(VK_SHIFT) & 0x8000);
|
||||
BOOL MajPressed = !!(GetKeyState(VK_SHIFT) & 0x8000);
|
||||
|
||||
switch (VirtualKeyCode)
|
||||
{
|
||||
|
@ -1003,10 +1155,9 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
if (Interpreted)
|
||||
{
|
||||
if (!MajPressed)
|
||||
GuiData->Selection.dwSelectionAnchor = GuiData->dwSelectionCursor;
|
||||
|
||||
UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
|
||||
UpdateSelection(GuiData,
|
||||
!MajPressed ? &GuiData->dwSelectionCursor : NULL,
|
||||
&GuiData->dwSelectionCursor);
|
||||
}
|
||||
else if (!IsSystemKey(VirtualKeyCode))
|
||||
{
|
||||
|
@ -1023,7 +1174,7 @@ OnKey(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
if (!IsSystemKey(VirtualKeyCode))
|
||||
{
|
||||
/* Clear the selection and send the key into the input buffer */
|
||||
UpdateSelection(GuiData, NULL);
|
||||
UpdateSelection(GuiData, NULL, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1273,27 +1424,26 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
case WM_LBUTTONDOWN:
|
||||
{
|
||||
/* Clear the old selection */
|
||||
// UpdateSelection(GuiData, NULL);
|
||||
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
|
||||
|
||||
/* Restart a new selection */
|
||||
GuiData->Selection.dwSelectionAnchor = PointToCoord(GuiData, lParam);
|
||||
GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
|
||||
SetCapture(GuiData->hWindow);
|
||||
GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
|
||||
UpdateSelection(GuiData, &GuiData->Selection.dwSelectionAnchor);
|
||||
UpdateSelection(GuiData,
|
||||
&GuiData->dwSelectionCursor,
|
||||
&GuiData->dwSelectionCursor);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
// COORD c;
|
||||
|
||||
if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
|
||||
|
||||
// c = PointToCoord(GuiData, lParam);
|
||||
// GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
|
||||
GuiData->Selection.dwFlags &= ~CONSOLE_MOUSE_DOWN;
|
||||
// UpdateSelection(GuiData, &c);
|
||||
// UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
|
||||
ReleaseCapture();
|
||||
|
||||
break;
|
||||
|
@ -1305,10 +1455,7 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
if (GetType(Buffer) == TEXTMODE_BUFFER)
|
||||
{
|
||||
#ifdef IS_WHITESPACE
|
||||
#undef IS_WHITESPACE
|
||||
#endif
|
||||
#define IS_WHITESPACE(c) \
|
||||
#define IS_WORD_SEP(c) \
|
||||
((c) == L'\0' || (c) == L' ' || (c) == L'\t' || (c) == L'\r' || (c) == L'\n')
|
||||
|
||||
PTEXTMODE_SCREEN_BUFFER TextBuffer = (PTEXTMODE_SCREEN_BUFFER)Buffer;
|
||||
|
@ -1320,15 +1467,15 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
ptrL = ptrR = ConioCoordToPointer(TextBuffer, cL.X, cL.Y);
|
||||
|
||||
/* Enlarge the selection by checking for whitespace */
|
||||
while ((0 < cL.X) && !IS_WHITESPACE(ptrL->Char.UnicodeChar)
|
||||
&& !IS_WHITESPACE((ptrL-1)->Char.UnicodeChar))
|
||||
while ((0 < cL.X) && !IS_WORD_SEP(ptrL->Char.UnicodeChar)
|
||||
&& !IS_WORD_SEP((ptrL-1)->Char.UnicodeChar))
|
||||
{
|
||||
--cL.X;
|
||||
--ptrL;
|
||||
}
|
||||
while ((cR.X < TextBuffer->ScreenBufferSize.X - 1) &&
|
||||
!IS_WHITESPACE(ptrR->Char.UnicodeChar) &&
|
||||
!IS_WHITESPACE((ptrR+1)->Char.UnicodeChar))
|
||||
!IS_WORD_SEP(ptrR->Char.UnicodeChar) &&
|
||||
!IS_WORD_SEP((ptrR+1)->Char.UnicodeChar))
|
||||
{
|
||||
++cR.X;
|
||||
++ptrR;
|
||||
|
@ -1338,11 +1485,8 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
* Update the selection started with the single
|
||||
* left-click that preceded this double-click.
|
||||
*/
|
||||
GuiData->Selection.dwSelectionAnchor = cL;
|
||||
GuiData->dwSelectionCursor = cR;
|
||||
|
||||
GuiData->Selection.dwFlags |= CONSOLE_MOUSE_SELECTION | CONSOLE_MOUSE_DOWN;
|
||||
UpdateSelection(GuiData, &GuiData->dwSelectionCursor);
|
||||
UpdateSelection(GuiData, &cL, &cR);
|
||||
|
||||
/* Ignore the next mouse move signal */
|
||||
GuiData->IgnoreNextMouseSignal = TRUE;
|
||||
|
@ -1370,13 +1514,12 @@ OnMouse(PGUI_CONSOLE_DATA GuiData, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
COORD c;
|
||||
|
||||
if (!(wParam & MK_LBUTTON)) break;
|
||||
if (!(GuiData->Selection.dwFlags & CONSOLE_MOUSE_DOWN)) break;
|
||||
|
||||
c = PointToCoord(GuiData, lParam); /* TODO: Scroll buffer to bring c into view */
|
||||
UpdateSelection(GuiData, &c);
|
||||
// TODO: Scroll buffer to bring SelectionCursor into view
|
||||
GuiData->dwSelectionCursor = PointToCoord(GuiData, lParam);
|
||||
UpdateSelection(GuiData, NULL, &GuiData->dwSelectionCursor);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1546,7 +1689,7 @@ Copy(PGUI_CONSOLE_DATA GuiData)
|
|||
}
|
||||
|
||||
/* Clear the selection */
|
||||
UpdateSelection(GuiData, NULL);
|
||||
UpdateSelection(GuiData, NULL, NULL);
|
||||
}
|
||||
|
||||
VOID
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct _GUI_CONSOLE_DATA
|
|||
PCONSOLE_SCREEN_BUFFER ActiveBuffer; /* Pointer to the active screen buffer (then maybe the previous Console member is redundant?? Or not...) */
|
||||
CONSOLE_SELECTION_INFO Selection; /* Contains information about the selection */
|
||||
COORD dwSelectionCursor; /* Selection cursor position, most of the time different from Selection.dwSelectionAnchor */
|
||||
BOOL LineSelection; /* TRUE if line-oriented selection (a la *nix terminals), FALSE if block-oriented selection (default on Windows) */
|
||||
|
||||
GUI_CONSOLE_INFO GuiInfo; /* GUI terminal settings */
|
||||
} GUI_CONSOLE_DATA, *PGUI_CONSOLE_DATA;
|
||||
|
|
|
@ -34,7 +34,7 @@ GuiCopyFromGraphicsBuffer(PGRAPHICS_SCREEN_BUFFER Buffer,
|
|||
|
||||
selWidth = GuiData->Selection.srSelection.Right - GuiData->Selection.srSelection.Left + 1;
|
||||
selHeight = GuiData->Selection.srSelection.Bottom - GuiData->Selection.srSelection.Top + 1;
|
||||
DPRINT1("Selection is (%d|%d) to (%d|%d)\n",
|
||||
DPRINT("Selection is (%d|%d) to (%d|%d)\n",
|
||||
GuiData->Selection.srSelection.Left,
|
||||
GuiData->Selection.srSelection.Top,
|
||||
GuiData->Selection.srSelection.Right,
|
||||
|
|
|
@ -140,7 +140,8 @@ InvalidateCell(PGUI_CONSOLE_DATA GuiData,
|
|||
|
||||
VOID
|
||||
SwitchFullScreen(PGUI_CONSOLE_DATA GuiData, BOOL FullScreen);
|
||||
|
||||
VOID
|
||||
CreateSysMenu(HWND hWnd);
|
||||
static LRESULT CALLBACK
|
||||
GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
|
@ -199,6 +200,9 @@ GuiConsoleNotifyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|||
GuiConsoleMoveWindow(GuiData); // FIXME: This MUST be done via the CreateWindowExW call.
|
||||
SendMessageW(GuiData->hWindow, PM_RESIZE_TERMINAL, 0, 0);
|
||||
|
||||
// FIXME: HACK: Potential HACK for CORE-8129; see revision 63595.
|
||||
CreateSysMenu(GuiData->hWindow);
|
||||
|
||||
/* Switch to full-screen mode if necessary */
|
||||
// FIXME: Move elsewhere, it cause misdrawings of the window.
|
||||
if (GuiData->GuiInfo.FullScreen) SwitchFullScreen(GuiData, TRUE);
|
||||
|
@ -533,8 +537,11 @@ GuiInitFrontEnd(IN OUT PFRONTEND This,
|
|||
GuiData->CmdIdLow = GuiData->CmdIdHigh = 0;
|
||||
|
||||
/* Initialize the selection */
|
||||
RtlZeroMemory(&GuiData->Selection, sizeof(CONSOLE_SELECTION_INFO));
|
||||
RtlZeroMemory(&GuiData->Selection, sizeof(GuiData->Selection));
|
||||
GuiData->Selection.dwFlags = CONSOLE_NO_SELECTION;
|
||||
RtlZeroMemory(&GuiData->dwSelectionCursor, sizeof(GuiData->dwSelectionCursor));
|
||||
GuiData->LineSelection = FALSE; // Default to block selection
|
||||
// TODO: Retrieve the selection mode via the registry.
|
||||
|
||||
/*
|
||||
* We need to wait until the GUI has been fully initialized
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Eingabeaufforderung"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Marquage"
|
||||
IDS_SELECT_TITLE "Sélection"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* https://sourceforge.net/projects/reactospl
|
||||
* Translation update by Olaf Siejka (Caemyr), Apr 2011
|
||||
* UTF-8 conversion by Caemyr (May, 2011)
|
||||
* Update by wojo664 (June 2014)
|
||||
*/
|
||||
|
||||
LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
|
||||
|
@ -30,3 +31,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "Konsola ReactOS"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Zaznacz"
|
||||
IDS_SELECT_TITLE "Wybierz"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "Consola ReactOS"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -27,3 +27,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -24,3 +24,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -22,3 +22,9 @@ BEGIN
|
|||
*/
|
||||
IDS_TERMINAL_TITLE "ReactOS Console"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_MARK_TITLE "Mark"
|
||||
IDS_SELECT_TITLE "Select"
|
||||
END
|
||||
|
|
|
@ -18,17 +18,18 @@
|
|||
#define ID_SYSTEM_DEFAULTS 0xFFF6
|
||||
#define ID_SYSTEM_PROPERTIES 0xFFF7
|
||||
|
||||
#define NCPOPUP_MENU 103
|
||||
#define IDS_EDIT 204
|
||||
#define IDS_MARK 205
|
||||
#define IDS_COPY 206
|
||||
#define IDS_PASTE 207
|
||||
#define IDS_SELECTALL 208
|
||||
#define IDS_SCROLL 209
|
||||
#define IDS_FIND 210
|
||||
#define IDS_DEFAULTS 211
|
||||
#define IDS_PROPERTIES 212
|
||||
|
||||
#define IDS_EDIT 204
|
||||
#define IDS_MARK 205
|
||||
#define IDS_COPY 206
|
||||
#define IDS_PASTE 207
|
||||
#define IDS_SELECTALL 208
|
||||
#define IDS_SCROLL 209
|
||||
#define IDS_FIND 210
|
||||
#define IDS_DEFAULTS 211
|
||||
#define IDS_PROPERTIES 212
|
||||
#define IDS_MARK_TITLE 220
|
||||
#define IDS_SELECT_TITLE 221
|
||||
|
||||
// Scrollbar resource ids. Unused.
|
||||
/*
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
|
||||
#include "guiterm.h"
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define IS_WHITESPACE(c) ((c) == L'\0' || (c) == L' ' || (c) == L'\t')
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
COLORREF PaletteRGBFromAttrib(PCONSOLE Console, WORD Attribute)
|
||||
|
@ -31,38 +35,33 @@ COLORREF PaletteRGBFromAttrib(PCONSOLE Console, WORD Attribute)
|
|||
return PALETTERGB(pe.peRed, pe.peGreen, pe.peBlue);
|
||||
}
|
||||
|
||||
VOID
|
||||
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
||||
PGUI_CONSOLE_DATA GuiData)
|
||||
static VOID
|
||||
CopyBlock(PTEXTMODE_SCREEN_BUFFER Buffer,
|
||||
PSMALL_RECT Selection)
|
||||
{
|
||||
/*
|
||||
* This function supposes that the system clipboard was opened.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pressing the Shift key while copying text, allows us to copy
|
||||
* text without newline characters (inline-text copy mode).
|
||||
*/
|
||||
BOOL InlineCopyMode = (GetKeyState(VK_SHIFT) & 0x8000);
|
||||
BOOL InlineCopyMode = !!(GetKeyState(VK_SHIFT) & 0x8000);
|
||||
|
||||
HANDLE hData;
|
||||
PCHAR_INFO ptr;
|
||||
LPWSTR data, dstPos;
|
||||
ULONG selWidth, selHeight;
|
||||
ULONG xPos, yPos, size;
|
||||
ULONG xPos, yPos;
|
||||
ULONG size;
|
||||
|
||||
selWidth = GuiData->Selection.srSelection.Right - GuiData->Selection.srSelection.Left + 1;
|
||||
selHeight = GuiData->Selection.srSelection.Bottom - GuiData->Selection.srSelection.Top + 1;
|
||||
DPRINT("Selection is (%d|%d) to (%d|%d)\n",
|
||||
GuiData->Selection.srSelection.Left,
|
||||
GuiData->Selection.srSelection.Top,
|
||||
GuiData->Selection.srSelection.Right,
|
||||
GuiData->Selection.srSelection.Bottom);
|
||||
DPRINT("CopyBlock(%u, %u, %u, %u)\n",
|
||||
Selection->Left, Selection->Top, Selection->Right, Selection->Bottom);
|
||||
|
||||
#ifdef IS_WHITESPACE
|
||||
#undef IS_WHITESPACE
|
||||
#endif
|
||||
#define IS_WHITESPACE(c) ((c) == L'\0' || (c) == L' ' || (c) == L'\t')
|
||||
/* Prevent against empty blocks */
|
||||
if (Selection == NULL) return;
|
||||
if (Selection->Left > Selection->Right || Selection->Top > Selection->Bottom)
|
||||
return;
|
||||
|
||||
selWidth = Selection->Right - Selection->Left + 1;
|
||||
selHeight = Selection->Bottom - Selection->Top + 1;
|
||||
|
||||
/* Basic size for one line... */
|
||||
size = selWidth;
|
||||
|
@ -75,6 +74,11 @@ GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
|||
*/
|
||||
size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("This case must never happen, because selHeight is at least == 1\n");
|
||||
}
|
||||
|
||||
size += 1; /* Null-termination */
|
||||
size *= sizeof(WCHAR);
|
||||
|
||||
|
@ -97,8 +101,8 @@ GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
|||
ULONG length = selWidth;
|
||||
|
||||
ptr = ConioCoordToPointer(Buffer,
|
||||
GuiData->Selection.srSelection.Left,
|
||||
GuiData->Selection.srSelection.Top + yPos);
|
||||
Selection->Left,
|
||||
Selection->Top + yPos);
|
||||
|
||||
/* Trim whitespace from the right */
|
||||
while (length > 0)
|
||||
|
@ -116,16 +120,15 @@ GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
|||
* Sometimes, applications can put NULL chars into the screen-buffer
|
||||
* (this behaviour is allowed). Detect this and replace by a space.
|
||||
*/
|
||||
dstPos[xPos] = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
|
||||
*dstPos++ = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
|
||||
}
|
||||
dstPos += length;
|
||||
|
||||
/* Add newline characters if we are not in inline-text copy mode */
|
||||
if (!InlineCopyMode)
|
||||
{
|
||||
if (yPos != (selHeight - 1))
|
||||
{
|
||||
wcscat(data, L"\r\n");
|
||||
wcscat(dstPos, L"\r\n");
|
||||
dstPos += 2;
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +141,127 @@ GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
|||
SetClipboardData(CF_UNICODETEXT, hData);
|
||||
}
|
||||
|
||||
static VOID
|
||||
CopyLines(PTEXTMODE_SCREEN_BUFFER Buffer,
|
||||
PCOORD Begin,
|
||||
PCOORD End)
|
||||
{
|
||||
HANDLE hData;
|
||||
PCHAR_INFO ptr;
|
||||
LPWSTR data, dstPos;
|
||||
ULONG NumChars, size;
|
||||
ULONG xPos, yPos, xBeg, xEnd;
|
||||
|
||||
DPRINT("CopyLines((%u, %u) ; (%u, %u))\n",
|
||||
Begin->X, Begin->Y, End->X, End->Y);
|
||||
|
||||
/* Prevent against empty blocks... */
|
||||
if (Begin == NULL || End == NULL) return;
|
||||
/* ... or malformed blocks */
|
||||
if (Begin->Y > End->Y || (Begin->Y == End->Y && Begin->X > End->X)) return;
|
||||
|
||||
/* Compute the number of characters to copy */
|
||||
if (End->Y == Begin->Y) // top == bottom
|
||||
{
|
||||
NumChars = End->X - Begin->X + 1;
|
||||
}
|
||||
else // if (End->Y > Begin->Y)
|
||||
{
|
||||
NumChars = Buffer->ScreenBufferSize.X - Begin->X;
|
||||
|
||||
if (End->Y >= Begin->Y + 2)
|
||||
{
|
||||
NumChars += (End->Y - Begin->Y - 1) * Buffer->ScreenBufferSize.X;
|
||||
}
|
||||
|
||||
NumChars += End->X + 1;
|
||||
}
|
||||
|
||||
size = (NumChars + 1) * sizeof(WCHAR); /* Null-terminated */
|
||||
|
||||
/* Allocate some memory area to be given to the clipboard, so it will not be freed here */
|
||||
hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
|
||||
if (hData == NULL) return;
|
||||
|
||||
data = GlobalLock(hData);
|
||||
if (data == NULL)
|
||||
{
|
||||
GlobalFree(hData);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINT("Copying %d characters\n", NumChars);
|
||||
dstPos = data;
|
||||
|
||||
/*
|
||||
* We need to walk per-lines, and not just looping in the big screen-buffer
|
||||
* array, because of the way things are stored inside it. The downside is
|
||||
* that it makes the code more complicated.
|
||||
*/
|
||||
for (yPos = Begin->Y; (yPos <= End->Y) && (NumChars > 0); yPos++)
|
||||
{
|
||||
xBeg = (yPos == Begin->Y ? Begin->X : 0);
|
||||
xEnd = (yPos == End->Y ? End->X : Buffer->ScreenBufferSize.X - 1);
|
||||
|
||||
ptr = ConioCoordToPointer(Buffer, 0, yPos);
|
||||
|
||||
/* Copy only the characters, leave attributes alone */
|
||||
for (xPos = xBeg; (xPos <= xEnd) && (NumChars-- > 0); xPos++)
|
||||
{
|
||||
/*
|
||||
* Sometimes, applications can put NULL chars into the screen-buffer
|
||||
* (this behaviour is allowed). Detect this and replace by a space.
|
||||
*/
|
||||
*dstPos++ = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("Setting data <%S> to clipboard\n", data);
|
||||
GlobalUnlock(hData);
|
||||
|
||||
EmptyClipboard();
|
||||
SetClipboardData(CF_UNICODETEXT, hData);
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
GetSelectionBeginEnd(PCOORD Begin, PCOORD End,
|
||||
PCOORD SelectionAnchor,
|
||||
PSMALL_RECT SmallRect);
|
||||
|
||||
VOID
|
||||
GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
||||
PGUI_CONSOLE_DATA GuiData)
|
||||
{
|
||||
/*
|
||||
* This function supposes that the system clipboard was opened.
|
||||
*/
|
||||
|
||||
BOOL LineSelection = GuiData->LineSelection;
|
||||
|
||||
DPRINT("Selection is (%d|%d) to (%d|%d) in %s mode\n",
|
||||
GuiData->Selection.srSelection.Left,
|
||||
GuiData->Selection.srSelection.Top,
|
||||
GuiData->Selection.srSelection.Right,
|
||||
GuiData->Selection.srSelection.Bottom,
|
||||
(LineSelection ? "line" : "block"));
|
||||
|
||||
if (!LineSelection)
|
||||
{
|
||||
CopyBlock(Buffer, &GuiData->Selection.srSelection);
|
||||
}
|
||||
else
|
||||
{
|
||||
COORD Begin, End;
|
||||
|
||||
GetSelectionBeginEnd(&Begin, &End,
|
||||
&GuiData->Selection.dwSelectionAnchor,
|
||||
&GuiData->Selection.srSelection);
|
||||
|
||||
CopyLines(Buffer, &Begin, &End);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
|
||||
PGUI_CONSOLE_DATA GuiData)
|
||||
|
|
|
@ -32,6 +32,7 @@ KeyboardHookProc(int nCode,
|
|||
WPARAM wParam,
|
||||
LPARAM lParam)
|
||||
{
|
||||
DPRINT1("KeyboardHookProc Processing!\n");
|
||||
return CallNextHookEx(hhk, nCode, wParam, lParam);
|
||||
}
|
||||
/*** END - HACK from win32csr... ***/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue