I'm currently working on project which will have two RichEdit controls one close to the other: let's say RichEdit1 is on left and RichEdit2 is on the right.
The user scenario I want to enable in the project is:
User mouse LButton down at somewhere in RichEdit1, e.g. before the 3rd char, in total 7 chars.
User drag the mouse to RichEdit2, e.g. after the 6th char, in total 11 chars.
User mouse LButton up.
I want to see both RichEdit1 3rd char to end and RichEdit2 begin to 6th char are selected.
Currently I notice that once mouse LButton down on RichEdit1, after I move the mouse to RichEdit2, the RichEdit2 could not receive mouse event before I release mouse.
Any suggestion will be appreciated. Thank you!
When the mouse button is pressed down on RichEdit1, it captures the mouse, thus subsequent mouse messages are sent to RichEdit1 until the mouse button is released. That is why RichEdit2 does not receive any mouse events while dragging over RichEdit2.
You will have to process the mouse move messages in RichEdit1 and check if their coordinates are outside of RichEdit1's client area. If so, convert them into coordinates relative to RichEdit2's client's area and then send EM_SETSEL/EM_EXSETSEL messages to RichEdit2 as needed. For example:
int RichEdit2StartIndex = -1;
...
// in RichEdit1's message handler...
case WM_MOUSEMOVE:
{
if ((wParam & MK_LBUTTON) == 0)
break;
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
RECT r;
GetClientRect(hwndRichEdit1, &r);
if (xPos < (r.right - r.left))
{
if (RichEdit2StartIndex != -1)
{
SendMessage(hwndRichEdit2, EM_SETSEL, -1, 0);
RichEdit2StartIndex = -1;
}
}
else
{
POINT pt;
pt.x = xPos;
pt.y = yPos;
MapWindowPoints(hwndRichEdit1, hwndRichEdit2, &pt, 1);
POINTL pl;
Pl.x := pt.x;
Pl.y := pt.y;
int idx = SendMessage(hwndRichEdit2, EM_CHARFROMPOS, 0, (LPARAM)&Pl);
if (idx != -1)
{
if (RichEdit2StartIndex == -1)
RichEdit2StartIndex = idx;
SendMessage(hwndRichEdit2, EM_SETSEL, RichEdit2StartIndex, idx);
}
}
break;
}
Vice versa when dragging a selection from RichEdit2 to RichEdit1.
And make sure that both RichEdit controls have the ES_NOHIDESEL style applied so you can see the selection in both controls at the same time.
Related
I'll try to be as clear as I can here. I have this C++ code here that lets me move a shape (circle or square) around a window by clicking (selecting) once on the shape, and then tapping or holding the arrow keys, and it let's me re-size the shape by clicking (selecting) once on the shape and tappping or holding the '+' or '-' keys.
//For extra credit, modify the project so that moving the mouse with the
//left button and the shift key down will change the size of the selected
// object.
afx_msg void CLab09Win::OnKeyDown (UINT achar, UINT repeat, UINT flags) {
CRect modified;
switch(achar) {
case 'B': // 'b'
design.SetColor ('B');
break;
case 38: //up arrow to move shape
modified = design.MoveShape(0, -1);
InvalidateRect(modified);
break;
case 40: //down arrow to move shape
modified = design.MoveShape(0, 1);
InvalidateRect(modified);
break;
case 107: // '+' (numeric pad) to grow shape
modified = design.ResizeShape(2);
InvalidateRect(modified);
break;
case 109: // '-' [numeric pad] to shrink shape
modified = design.ResizeShape(-2);
InvalidateRect(modified);
break;
};
}
I want to simultaneous hold two keys to resize the shape, i.e hold 'X' and 'W', as in x + w or like how we copy something ( Ctrl + C ).
I tried the following code but it didn't work.
case 'X':
if (achar == 'W') {
modified = design.ResizeShape(2);
InvalidateRect(modified);
break;
}
I've had a hard time finding solutions to this online because most solutions use something called VK (virtual keys), and in this assignment we don't use VK.
Ultimately, I actually want to have it so that after selecting a shape, and holding down the SHIFT key while holding the left mouse button and moving the cursor the shape will be re-sized, similar to how you re-size a window by clicking on its edge and dragging the cursor.
My code for handling mouse movement and left-button events is the following:
afx_msg void CLab09Win::OnLButtonDown(UINT flags, CPoint point) {
CRect selected = design.SelectShape(point.x, point.y);
current = point;
InvalidateRect(selected);
}
afx_msg void CLab09Win::OnMouseMove(UINT flags, CPoint point) {
if (flags == MK_LBUTTON) {
int deltax = point.x - current.x;
int deltay = point.y - current.y;
CRect modified = design.MoveShape(deltax, deltay);
current = point;
InvalidateRect(modified);
}
}
So to recap, I would like advice on how to use two keyboard keys [ x + w ] , and how to use a keyboard key along with the mouse's left-button [ SHIFT + LButton ] and the movement of the cursor to resize a shape (circle or square).
Thank you all.
I'm adapting some skeleton code to learn how OpenGL works and have in SphericalCameraManipulator.cpp which allows me to pan and tilt the camera while I hold down right mouse:
void SphericalCameraManipulator::handleMouseMotion(int x, int y)
{
//Motion
float xMotion = (float)x - previousMousePosition[0];
float yMotion = (float)y - previousMousePosition[1];
if(reset)
{
xMotion = yMotion = 0.0;
reset = false;
}
this->previousMousePosition[0] = (float)x;
this->previousMousePosition[1] = (float)y;
//Right Button Action
if(this->currentButton == GLUT_RIGHT_BUTTON && this->currentState == GLUT_DOWN)
{
this->pan -= xMotion*this->panTiltMouseStep ;
this->tilt += yMotion*this->panTiltMouseStep ;
}
//Enforce Ranges
this->enforceRanges();
}
I deleted the left mouse action as I don't want it to control the camera, and it now actions a command in the main code body.
//Left Button Action
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
... //game action
}
My problem is that when I click the left mouse, the press of the right mouse is cancelled, and I must release and repress the right mouse to continue controlling the camera.
Is there a way to prevent this from happening? It interrupts the flow of the game. I'm using GLUT
Rabbid76's comment saying there is no mouse hold event set me on the right path.
I wrote a small function that simply recorded the last state of mouse button 2 (the 'camera look around' button):
void SphericalCameraManipulator::handleMouse(int button, int state)
{
this->currentButton = button;
this->currentState = state;
//to enable mouse look around
if (this->currentButton == 2) //right mouse
this->lastLookState = this->currentState;
if(this->currentState == GLUT_UP)
{
reset = true;
}
}
This mean even when the current state was regarding the left mouse button (game action) it was still possiblew to look around since a 'mouse two button up' event had not occured:
this->currentButton = 2;
this->currentState = 1;
I am writing a program that scans if the Left Mouse Button is held down, then sends a left mouse button up and continues after that. The problem is, since I am sending a left mouse button up, the program will not continue because the left mouse button is not being held down anymore.
Here is some pseudo:
if(GetKeyState(VK_LBUTTON) < 0){
Sleep(10);
mouse_event(MOUSEEVENTF_LEFTUP, p.x, p.y, 0, 0);
//Rest of code
}
How can I detect the left mouse button being down after this? Would I have to use a driver?
Just use a flag:
bool lButtonWasDown=flase;
if(GetKeyState(VK_LBUTTON) < 0){
Sleep(10);
lButtonWasDown = true;
mouse_event(MOUSEEVENTF_LEFTUP, p.x, p.y, 0, 0);
}
if (lButtonWasDown)
{
// rest of the code for lButtonWasDown = true
}
From reading your description of the program only here is my implementation.
Using the Windows API:
while (true) {
//check if left mouse button is down
if (GetKeyState(VK_LBUTTON) & 0x8000) {
//send left mouse button up
//You might want to place a delay in here
//to simulate the natural speed of a mouse click
//Sleep(140);
INPUT Input = { 0 };
::ZeroMemory(&Input, sizeof(INPUT));
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
::SendInput(1, &Input, sizeof(INPUT));
}
}
You can place this code into a function that you call in a thread if you want to do other things while you forcibly stop people from clicking and dragging.
void noHoldingAllowed() {
//insert code here used above...
}
int main(void) {
std::thread t1(noHoldingAllowed);
//other stuff...
return 0;
{
I haven't tested this code, but it should work
while(programIsRunning)
{
if(GetKeyState(VK_LBUTTON) < 0){
Sleep(10);
mouse_event(MOUSEEVENTF_LEFTUP, p.x, p.y, 0, 0);
// rest of the code
}
It should work since if you have the Lmouse button held while the loop reruns if will trigger the if statement which will then trigger a mouseup event.
note:
You might be able to do while(GetKeyState(VK_LBUTTON) < 0){//code here}
Is there anyway when mouse moving find the control mouse is over on it? I mean if you have a dialog with some labels and text boxes, and the mouse move to label, notify me that label name, after that if move it to text box notify the text box name.
If you handle WM_MOUSEMOVE within your dialog, you can grab the mouse position, convert it to dialog coordinates, and determine what control lies underneath the cursor point.
After some research, I came to this code which let me know if the mouse cursor is over my control in a dialog box.
//Handling mouse move in mfc dialog
void CDialogRoll::OnMouseMove(UINT nFlags, CPoint point)
{
CRect rect1;
m_FrameArea.GetClientRect(&rect1); //control rectangle
m_FrameArea.ClientToScreen(&rect1)
ScreenToClient(&rect1); //dialog coordinates`
if (point.x >= rect1.left && point.x <= rect1.right && point.y >= rect1.top &&
point.y <= rect1.bottom) {
char str[100];
sprintf(str, "%d-%d", point.x - rect1.left, point.y - rect1.top);
}
CDialogEx::OnMouseMove(nFlags, point);
}
I'm designing a custom window border, and i put a bitmap on the top as a drag bar. This works, however when i try to drag the window, it places itself in two different areas and flickers between the two. Here's a video:
http://dl.dropbox.com/u/85700751/capture-1.avi
When the window is flashing, i'm trying to drag it (it doesn't show my cursor for some reason). Here's my dragging code:
case WM_LBUTTONDOWN: {
int posX = LOWORD(lParam);
int posY = HIWORD(lParam);
if((isDragging==false)&&(posX>4)&&(posX<470)&&(posY>4)&&(posY<24))
{
isDragging = true;
ClipCursor(rect);
oldCursorX = posX;
oldCursorY = posY;
}
}
break;
case WM_LBUTTONUP: {
isDragging = false;
ClipCursor(NULL);
}
break;
case WM_MOUSEMOVE: {
if(isDragging) {
SetWindowPos(hWnd, NULL, LOWORD(lParam)-oldCursorX, HIWORD(lParam)-oldCursorY, 500, 500, NULL);
}
}
break;
It's generally easiest to simply resond to WM_NCHITTEST. For that message, the LPARAM will have the mouse hit X and Y coordinates (same as WM_LBUTTONDOWN). If they're within your draggable area just return HTCAPTION. The system will then automatically handle all the drag logic for you.
The cursor coordinates passed to WM_MOUSEMOVE are relative to the window position. But you keep changing the window position with every WM_MOUSEMOVE recieved.
Convert the coordinates to Screen coordinates using ::ClientToScreen().