unit main;
interface
uses
type
TForm1 = class(TForm)
Image1: TImage;
IdTCPClient1: TIdTCPClient;
Timer1: TTimer;
procedure connectClick(Sender: TObject);
procedure GetScreen;
procedure Timer1Timer(Sender: TObject);
procedure mouse_move;
procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
private
{ Private declarations }
public
{ Public declarations }
procedure connect_to_server;
end;
var
Form1: TForm1;
Stream: TMemoryStream;
implementation
{$R *.dfm}
///+++++++++++++++++++++++++++++PROCEDURE++++++++++++++++++++++++++++++++++++++
procedure TForm1.connect_to_server;
begin
//тут все работает
end;
procedure TForm1.GetScreen;
var
Bitmap: TBitmap;
begin
//тут все работает
end;
// на компоненте ИМЕДЖ1 нужна обработка событий левой-правой кнопки, нажать-отжать
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button=mbLeft then
begin
IdTCPClient1.IOHandler.WriteLn('mouse_left_dw ');
end;
if Button=mbRight then
begin
IdTCPClient1.IOHandler.WriteLn('mouse_right_dw ');
end;
end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button=mbLeft then
begin
IdTCPClient1.IOHandler.WriteLn('mouse_left_up ');
end;
if Button=mbRight then
begin
IdTCPClient1.IOHandler.WriteLn('mouse_right_up ');
end;
end;
procedure TForm1.mouse_move;
var
Kursor:TPoint;
begin
//тут все работает
end;
///+++++++++++++++++++++++++++++PROCEDURE++++++++++++++++++++++++++++++++++++++
///+++++++++++++++++PROG++++++++++++++++++++++++++++++++++++++++++++++++++
procedure TForm1.connectClick(Sender: TObject);
begin
// тут все работает, просто запуск тамер1
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
connect_to_server; //тут все работает
mouse_move; //тут все работает
Image1MouseUp; // тут ИДЕ пишет - недостаточно актуальных параметров????????
Image1MouseDown; // тут тоже самое
GetScreen; //тут все работает
IdTCPClient1.Disconnect;
end;
end.
Сервер-клиент РДП. обработка событий кнопки мыши
Предыдущая версия работает( передача скрина сервера на клиент и передача координат курсора мыши клиента на сервер), но возникла непонятная проблема в клиенте с передачей нажатия кнопок мыши
Код клиента (усеченная версия)
Код:
ВОПРОС: какие такие параметры, это ведь вызов процедуры, описанной выше, там и параметры указаны
можно конечно в отдельном цикле подключения все передать, как было сделано в предыдущей версии, но хотелось бы все в одном сеансе подключения к серверу
Цитата:
Код:
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
Shift: TShiftState; X, Y: Integer);
Цитата:
Код:
Image1MouseUp;
Сравните прототип процедуры с тем, как вы ее вызываете.
"прототип" - то что написано в секции TYPE - создала ИДЕ, врочем если все это (параметры) прописать в строке вызова процедуры просто выскочит куча ошибок
Во-первых, прямой вызов обработчиков - не лучший стиль программирования. Во-вторых, какую задачу вы хотите решить этими двумя строками? Какой смысл по таймеру дергать мышку?
как какой смысл? передать нажатие кнопок мыши с клиента на сервер. это прототип РАДМИН
В чем смысл вызывать обработчик _по таймеру_?? Я понимаю, когда вы экран передаете по таймеру (тоже вопрос, стОит ли так делать, но допускаю такой вариант), но, извините меня, зачем дергать мышку по таймеру, когда уже есть обработчик??
-клиент посылает на сервер координаты мыши
- клиент передает инфор о нажатых кнопках мыши
- клиент передает инфор о нажатых клавишах клавиатуры(до этого еще дойдем)
- клиент получает скрин экрана сервера со всеми выше перечисленными манипуляциями
полученная картинка идет на OCR и далее.....
что конкретно нужно прописать в параметрах вызова процедуры?
Ничего не нужно прописывать. Уберите эти строки оттуда В ПРИНЦИПЕ. Информация о событиях мышки должна передаваться только тогда, когда они реально происходят, а это как раз обеспечивают обработчики, понимаете?
когда просто Image1MouseUp; - тогда компиллятор не компилирует
а если убрать параметры в
type
procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); - вот это все
тогда выскакивает ошибки далее, в коде процедур Image1MouseUp
Код:
Image1MouseUp;
Image1MouseDown;
Image1MouseDown;
И ВСЕ.
если вставить подключение к серверу в процедуры
Image1MouseUp;
Image1MouseDown;
тогда это будет предыдущая версия клиент-сервера, когда все процессы коннект-реконнект разных частей программы клиента происходили асинхронно
именно надо, чтобы по таймеру все происходило
Image1MouseUp;
Image1MouseDown;
тогда прийдется вводить в них код подключение серверу
это было в предыдущей версии клиента-сервера, когда все части программы клиента работают асинхронно (кстати все работает)
но нужно все процессы запускать по таймеру, синхронно и последовательно
Цитата: Pcrepair
так ведь подключение к серверу идет по таймеру
Этого я недоглядел, но это все равно неправильно. Подключение должно происходить один раз (например, по факту успешной авторизации) и сохраняться до конца сессии. А дальше вы работаете с открытым подключением и передаете экран по таймеру, а события мышки / клавиатуры - по факту их возникновения. Соответственно, при завершении сессии подключение закрывается.
клиент-сервер РДП (то о чем сейчас речь идет) - маленький кусочек большой, в удаленной перспективе, программы
и надо, именно по таймеру, производить весь набор операций: передача состояния мыши, клавиатуры и получение скрина экрана, для последующей обработки в автоматическом режиме полученной информации
итого, как же сделать чтоб все работало?
Если все-таки делать по таймеру, то я бы, наверное, делал какие-нибудь буфера, в которые бы писал все события, а потом передавал буфер по таймеру. Приведу пример (на C++, он мне ближе):
Код:
// создаем структуры для описания различных событий
typedef enum {
LeftButton,
RightButton,
MiddleButton
} TMouseButton;
typedef enum {
MouseDown,
MouseUp
} TMouseEventType;
typedef enum {
KeyDown,
KeyUp
} TKeyboardEventType;
struct MouseEvent {
TMouseEventType type;
int X;
int Y;
TMouseButton mouseButton;
};
struct KeyboardEvent {
TKeyboardEventType type;
char c;
unsigned int modifiers; // MOD_ALT, MOD_CONTROL etc.
};
// создаем очереди для событий мыши и клавиатуры
queue<MouseEvent> mouseEvents();
queue<KeyboardEvent> keyboardEvents();
// когда происходят какие-то события мыши или клавиатуры, не отправляем сразу, а добавляем их в очередь:
// эта функция - обработчик события
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
MouseEvent mouseEvent;
mouseEvent.type = MouseDown;
mouseEvent.c = (char)nChar;
mouseEvent.modifiers = 0;
if (::GetAsyncKeyState(MOD_ALT))
mouseEvent.modifiers |= MOD_ALT;
if (::GetAsyncKeyState(MOD_CONTROL))
mouseEvent.modifiers |= MOD_CONTROL;
if (::GetAsyncKeyState(MOD_SHIFT))
mouseEvent.modifiers |= MOD_SHIFT;
mouseEvents.push(mouseEvent);
}
// аналогично поступаете с остальными событиями
bla-bla-bla OnTimer(...) {
SendScreen;
// посылаете все накопленные события мыши
while (!mouseEvents.empty()) {
SendMouseEvent(mouseEvents.front());
mouseEvents.pop();
}
// посылаете все накопленные события клавиатуры
while (!keyboardEvents.empty()) {
SendKeyboardEvent(keyboardEvents.front());
keyboardEvents.pop();
}
}
typedef enum {
LeftButton,
RightButton,
MiddleButton
} TMouseButton;
typedef enum {
MouseDown,
MouseUp
} TMouseEventType;
typedef enum {
KeyDown,
KeyUp
} TKeyboardEventType;
struct MouseEvent {
TMouseEventType type;
int X;
int Y;
TMouseButton mouseButton;
};
struct KeyboardEvent {
TKeyboardEventType type;
char c;
unsigned int modifiers; // MOD_ALT, MOD_CONTROL etc.
};
// создаем очереди для событий мыши и клавиатуры
queue<MouseEvent> mouseEvents();
queue<KeyboardEvent> keyboardEvents();
// когда происходят какие-то события мыши или клавиатуры, не отправляем сразу, а добавляем их в очередь:
// эта функция - обработчик события
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {
MouseEvent mouseEvent;
mouseEvent.type = MouseDown;
mouseEvent.c = (char)nChar;
mouseEvent.modifiers = 0;
if (::GetAsyncKeyState(MOD_ALT))
mouseEvent.modifiers |= MOD_ALT;
if (::GetAsyncKeyState(MOD_CONTROL))
mouseEvent.modifiers |= MOD_CONTROL;
if (::GetAsyncKeyState(MOD_SHIFT))
mouseEvent.modifiers |= MOD_SHIFT;
mouseEvents.push(mouseEvent);
}
// аналогично поступаете с остальными событиями
bla-bla-bla OnTimer(...) {
SendScreen;
// посылаете все накопленные события мыши
while (!mouseEvents.empty()) {
SendMouseEvent(mouseEvents.front());
mouseEvents.pop();
}
// посылаете все накопленные события клавиатуры
while (!keyboardEvents.empty()) {
SendKeyboardEvent(keyboardEvents.front());
keyboardEvents.pop();
}
}
Да, и замечание о том, что подключение должно быть перманентным, остается в силе.
режим таймера - просто контрольный режим (проверка функционирования работы модуля клиент-сервер)
в рабочем режиме получение скрина экрана удаленного хоста будет идти по запросу модуля программы
программа подключается к удаленному хосту в сети
- передает в хост параметры мыши и клавиатуры
- получает результат в виде скрина экрана удаленного хоста (на скрине отображены все последствия передачи параметров мыши и клавы - виртуальных параметров, реальные мышь и клава в этот момент блокированы)
- обрабатывает скрин (OCR и далее)
это нужно по работе - рабочий инструмент
PS: Alexander92 в вашем примере отсутствует всякая синхронизация, что непременно напомнит о себе в прочем как и вечные циклы.
Ramon, я могу за человека _весь_ код написать, но не бесплатно же... :) А если серьезно, я просто каркас набросал, чтоб понятно было, о чем я говорю.
модуль сжатия-декомпрессии уже есть, работает нормально нагрузка на ПРОЦ и на сеть небольшие
постояннного соединения не нужно - программа подключается к хосту проводит необходимые действия и отключается
весь код писать не надо, мне просто нужно понять что не так, там уже напишем-перепишем-откомпиллируем