Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Сервер-клиент РДП. обработка событий кнопки мыши

36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
Добрый день! Продолжается разработка клиент-серверного приложения типа РАДМИН (D2010 + INDY10)
Предыдущая версия работает( передача скрина сервера на клиент и передача координат курсора мыши клиента на сервер), но возникла непонятная проблема в клиенте с передачей нажатия кнопок мыши
Код клиента (усеченная версия)
Код:
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.

ВОПРОС: какие такие параметры, это ведь вызов процедуры, описанной выше, там и параметры указаны
можно конечно в отдельном цикле подключения все передать, как было сделано в предыдущей версии, но хотелось бы все в одном сеансе подключения к серверу
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
Эх... Сложно быть кэпом, но попробую. :)

Цитата:

 
Код:
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);


Цитата:

 
Код:
Image1MouseUp;



Сравните прототип процедуры с тем, как вы ее вызываете.

36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
"прототип" - то что написано в секции TYPE - создала ИДЕ, врочем если все это (параметры) прописать в строке вызова процедуры просто выскочит куча ошибок
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
Естественно, выскочит, если просто прописать! Кто ж спорит?
Во-первых, прямой вызов обработчиков - не лучший стиль программирования. Во-вторых, какую задачу вы хотите решить этими двумя строками? Какой смысл по таймеру дергать мышку?
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
как какой смысл? передать нажатие кнопок мыши с клиента на сервер. это прототип РАДМИН
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
В чем смысл вызывать обработчик _по таймеру_?? Я понимаю, когда вы экран передаете по таймеру (тоже вопрос, стОит ли так делать, но допускаю такой вариант), но, извините меня, зачем дергать мышку по таймеру, когда уже есть обработчик??
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
так было задумано:
-клиент посылает на сервер координаты мыши
- клиент передает инфор о нажатых кнопках мыши
- клиент передает инфор о нажатых клавишах клавиатуры(до этого еще дойдем)
- клиент получает скрин экрана сервера со всеми выше перечисленными манипуляциями
полученная картинка идет на OCR и далее.....

что конкретно нужно прописать в параметрах вызова процедуры?
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
Ничего не нужно прописывать. Уберите эти строки оттуда В ПРИНЦИПЕ. Информация о событиях мышки должна передаваться только тогда, когда они реально происходят, а это как раз обеспечивают обработчики, понимаете?
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
не, не понимаю
когда просто 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
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
:facepalm: Просто уберите из процедуры таймера строки
 
Код:
Image1MouseUp;
Image1MouseDown;

И ВСЕ.
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
так ведь подключение к серверу идет по таймеру
если вставить подключение к серверу в процедуры
Image1MouseUp;
Image1MouseDown;
тогда это будет предыдущая версия клиент-сервера, когда все процессы коннект-реконнект разных частей программы клиента происходили асинхронно
именно надо, чтобы по таймеру все происходило
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
если убрать из таймера вызов процедур
Image1MouseUp;
Image1MouseDown;
тогда прийдется вводить в них код подключение серверу
это было в предыдущей версии клиента-сервера, когда все части программы клиента работают асинхронно (кстати все работает)
но нужно все процессы запускать по таймеру, синхронно и последовательно
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
Цитата: Pcrepair
так ведь подключение к серверу идет по таймеру



Этого я недоглядел, но это все равно неправильно. Подключение должно происходить один раз (например, по факту успешной авторизации) и сохраняться до конца сессии. А дальше вы работаете с открытым подключением и передаете экран по таймеру, а события мышки / клавиатуры - по факту их возникновения. Соответственно, при завершении сессии подключение закрывается.

36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
все немножко сложнее
клиент-сервер РДП (то о чем сейчас речь идет) - маленький кусочек большой, в удаленной перспективе, программы
и надо, именно по таймеру, производить весь набор операций: передача состояния мыши, клавиатуры и получение скрина экрана, для последующей обработки в автоматическом режиме полученной информации
итого, как же сделать чтоб все работало?
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
А можно узнать, с чем связано такое жесткое ограничение передачи информации именно по таймеру? Просто такое решение обычно порождает довольно много лишнего трафика. Если вы подробно читали про RAdmin, на который вы ориентируетесь, наверняка знаете, что именно эта проблема заставила Famatech с 3-й версии сделать зеркальный видеодрайвер, чтобы не гонять лишний раз полный экран по сети.

Если все-таки делать по таймеру, то я бы, наверное, делал какие-нибудь буфера, в которые бы писал все события, а потом передавал буфер по таймеру. Приведу пример (на 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();
  }

}


Да, и замечание о том, что подключение должно быть перманентным, остается в силе.
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
да РАДМИН здесь только для примера, как программа имеющая похожий функционал, не более того
режим таймера - просто контрольный режим (проверка функционирования работы модуля клиент-сервер)
в рабочем режиме получение скрина экрана удаленного хоста будет идти по запросу модуля программы
программа подключается к удаленному хосту в сети
- передает в хост параметры мыши и клавиатуры
- получает результат в виде скрина экрана удаленного хоста (на скрине отображены все последствия передачи параметров мыши и клавы - виртуальных параметров, реальные мышь и клава в этот момент блокированы)
- обрабатывает скрин (OCR и далее)
это нужно по работе - рабочий инструмент
260
23 июля 2011 года
Ramon
1.1K / / 16.08.2003
Не будем же лишать человека всех детских грабелек по которым ему предстоит пройти с трафиком, неоправданной нагрузкой на клиента и на сервер, а так же радости многократного соединения незащищенного к тому же небось, будет вещать некий десктоп на весь антернет.

PS: Alexander92 в вашем примере отсутствует всякая синхронизация, что непременно напомнит о себе в прочем как и вечные циклы.
278
23 июля 2011 года
Alexander92
1.1K / / 04.08.2008
Ramon, я могу за человека _весь_ код написать, но не бесплатно же... :) А если серьезно, я просто каркас набросал, чтоб понятно было, о чем я говорю.
36K
23 июля 2011 года
Pcrepair
64 / / 16.01.2011
нет, это прибамбас чисто для ЛВС, на "антернет" вещать не будем
модуль сжатия-декомпрессии уже есть, работает нормально нагрузка на ПРОЦ и на сеть небольшие
постояннного соединения не нужно - программа подключается к хосту проводит необходимые действия и отключается

весь код писать не надо, мне просто нужно понять что не так, там уже напишем-перепишем-откомпиллируем
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог