Что нового

Жесты мышкой, помогите настроить функцию

Suppir

Продвинутый
Сообщения
967
Репутация
62
Код:
#include <Misc.au3>

While   1
    Sleep (300)
    ToolTip("")
    If _IsPressed("04") Then
        $ori = MouseGetPos()
            SplashImageOn("","images.jpg","16","16", $ori[0]-8, $ori[1]-8, 1)
        Do
				Sleep(100)
			$cur = MouseGetPos()
			If $ori[0] - $cur[0] > 100 And  $ori[1] - $cur[1] > 100  Then
				ToolTip("функция 1")
			ElseIf $ori[0] - $cur[0] < -100 And  $ori[1] - $cur[1] > 100  Then
				ToolTip("функция 2")
			ElseIf $ori[0] - $cur[0] > 100 And  $ori[1] - $cur[1] < -100  Then
				ToolTip("функция 3")
			ElseIf $ori[0] - $cur[0] < -100 And  $ori[1] - $cur[1] < -100  Then
				ToolTip("функция 4")
			ElseIf $ori[0] - $cur[0] > 50 Then
				ToolTip("функция 5")
			ElseIf $ori[0] - $cur[0] < -50 Then
				ToolTip("функция 6")
			ElseIf $ori[1] - $cur[1] > 50 Then
				ToolTip("функция 7")
			ElseIf $ori[1] - $cur[1] < -50 Then
				ToolTip("функция 8")
			Else
				ToolTip("")
			EndIf
        Until Not(_IsPressed("04"))
        $cur = MouseGetPos()
        If $ori[0] - $cur[0] > 100 And  $ori[1] - $cur[1] > 100  Then
;~             func1()
        ElseIf $ori[0] - $cur[0] < -100 And  $ori[1] - $cur[1] > 100  Then
;~             func2()
        ElseIf $ori[0] - $cur[0] > 100 And  $ori[1] - $cur[1] < -100  Then
;~             func3()
        ElseIf $ori[0] - $cur[0] < -100 And  $ori[1] - $cur[1] < -100  Then
;~             func4()
        ElseIf $ori[0] - $cur[0] > 50 Then
;~             func5()
        ElseIf $ori[0] - $cur[0] < -50 Then
;~             func6()
        ElseIf $ori[1] - $cur[1] > 50 Then
;~             func7()
        ElseIf $ori[1] - $cur[1] < -50 Then
;~             func8()
        Else
			SplashOff()
            Sleep(500)
        EndIf
        SplashOff()
    EndIf
WEnd



Запускаем скрипт. Удерживаем среднюю кнопку мышки. Я хочу, чтобы пользователь мог выбрать по часовой стрелке одну из восьми функций (при отпускании мышки будет запускаться выбранная функция). Но сейчас почему-то функции 4, 3, 2 и 1 не срабатывают.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Ты собрался написать Crysis 3?

:smile:

Suppir, если ты оперируешь угловыми размерами, то и расчет производи в угловых координатах. Для этого тебе нужно определить удаление (радиус) текущего положения курсора от центра окружности и угол относительно 12 часов по часовой стрелке. Далее, условно делишь окружность на сектора и определяешь, в каком именно секторе в данный момент находится курсор...

Я маленько изменил твой код и добавил разных плюшек. Надеюсь, все будет понятно. Если нужны основы тригонометрии, то см. здесь.

Код:
#Include <GDIPlus.au3>
#Include <Misc.au3>
#Include <WinAPIEx.au3>
#Include <WindowsConstants.au3>

$hCursor = _WinAPI_CopyCursor(_WinAPI_LoadCursor(0, 32512))

_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Sectors.png')
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()

$hForm = GUICreate('', 300, 300, -1, -1, $WS_POPUPWINDOW, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST), GUICreate('', -1, -1, -1, -1, -1, $WS_EX_TOOLWINDOW))

$Index = 1

While 1
	Sleep(100)
	If _IsPressed('04') Then
		$XY = MouseGetPos()
		WinMove($hForm, '', $XY[0] - 150, $XY[1] - 150)
		GUISetState(@SW_SHOW, $hForm)
		For $i = 5 To 255 Step 5
			_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, $i)
			$Timer = TimerInit()
			While Not Floor(TimerDiff($Timer))
				; Задержка 1 мс
			WEnd
		Next
		_WinAPI_SetSystemCursor(_WinAPI_LoadCursor(0, 32649), 32512, 1)
		While _IsPressed('04')
			$Pos = MouseGetPos()
			$Ang = _Angle($Pos[0], $Pos[1], $XY[0], $XY[1]) ; Угол относительно 12 часов по часовой стрелке (в градусах)
			$R = Sqrt(($XY[0] - $Pos[0]) ^ 2 + ($XY[1] - $Pos[1]) ^ 2) ; Удаление (радиус) от центра
			If $R > 150 Then ; Если курсор выходит за пределы окружности, радиус = 150
				MouseMove($XY[0] + 150 * Sin($Ang * ATan(1) / 45), $XY[1] - 150 * Cos($Ang * ATan(1) / 45), 0)
			EndIf
			Select
				Case ($Ang >= 0  ) And ($Ang < 45 ) ;   0 - 45°
					ToolTip('Функция 1')
					$Index = 1
				Case ($Ang >= 45 ) And ($Ang < 90 ) ;  45 - 90°
					ToolTip('Функция 2')
					$Index = 2
				Case ($Ang >= 90 ) And ($Ang < 135) ;  90 - 135°
					ToolTip('Функция 3')
					$Index = 3
				Case ($Ang >= 135) And ($Ang < 180) ; 135 - 180°
					ToolTip('Функция 4')
					$Index = 4
				Case ($Ang >= 180) And ($Ang < 225) ; 180 - 225°
					ToolTip('Функция 5')
					$Index = 5
				Case ($Ang >= 225) And ($Ang < 270) ; 225 - 270°
					ToolTip('Функция 6')
					$Index = 6
				Case ($Ang >= 270) And ($Ang < 315) ; 270 - 315°
					ToolTip('Функция 7')
					$Index = 7
				Case Else ; 315 - 0°
					ToolTip('Функция 8')
					$Index = 8
			EndSelect
		WEnd
		_WinAPI_SetSystemCursor($hCursor, 32512, 1)
		ToolTip('')
		For $i = 250 To 0 Step -5
			_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, $i)
			$Timer = TimerInit()
			While Not Floor(TimerDiff($Timer))
				; Задержка 1 мс
			WEnd
		Next
		GUISetState(@SW_HIDE, $hForm)
		ConsoleWrite('Функция ' & $Index & '...' & @CR)
	EndIf
WEnd

Func _Angle($X, $Y, $XC, $YC)
	If ($X = $XC) And ($Y = $YC) Then
		Return 0
	Else
		Return Mod(360 + ($Y > $YC) * 180 - ATan(($XC - $X) / ($YC - $Y)) * 45 / ATan(1), 360)
	EndIf
EndFunc   ;==>_Angle


WinAPEX
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Офигеть! Спасибо огромное! :ok:

Только этот круг я поверну по часовой стрелке на 22,5 градусов. Чтобы получились как бы стороны света: север, юг, запад, восток, северо-восток, юго-восток, северо-запад, юго-запад.


Yashied [?]
Ты собрался написать Crysis 3?

Дело в том, что моя программа работает в трее, в то время как пользователь работает с двумя другими программами (редактором и базой данных). Моя программа выступает в роли коннектора между этими программами, а также выполняет ряд полезных действий, упрощая работу пользователям. В редакторе и БД используется огромное количество хоткеев - и для моей программы на клавиатуре не хватает места. Восемь функций кое-как получилось впихнуть, но некоторые комбинации не очень удобные (зажимается CTRL + ALT + далеко стоящая клавиша). Поэтому возникла идея подвязать функции к жестам мышкой :smile: Немного потестил - получается очень удобно, гораздо быстрее чем с хоткеями.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
Только этот круг я поверну по часовой стрелке на 22,5 градусов.

Тогда нужно немного изменить функцию _Angle():

Код:
Func _Angle($X, $Y, $XC, $YC)
	If ($X = $XC) And ($Y = $YC) Then
		Return 0
	Else
		Return Mod(360 + 22.5 + ($Y > $YC) * 180 - ATan(($XC - $X) / ($YC - $Y)) * 45 / ATan(1), 360)
	EndIf
EndFunc   ;==>_Angle


P.S

Афигеть => Офигеть

:whistle:
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Yashied
Yashied сказал(а):
Return Mod(360 + 22.5 + ($Y > $YC) * 180 - ATan(($XC - $X) / ($YC - $Y)) * 45 / ATan(1), 360)

А здесь что поменять? (сейчас мышка сдвигается по часовой стрелке)

Код:
If $R > 150 Then ; Если курсор выходит за пределы окружности, радиус = 150
     MouseMove($XY[0] + 150 * Sin($Ang * ATan(1) / 45), $XY[1] - 150 * Cos($Ang * ATan(1) / 45), 0)
EndIf
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
А здесь что поменять?

Ничего. Это условие нужно только для того, чтобы курсор не выползал за пределы окружности (радиус = 150, соответственно размер картинки 300x300 точек). Если курсор оказывается за пределами окружности, то MouseMove() возвращает его на место (на границу окружности). Если ты уменьшишь размера .png, то нужно будет поставить соответствующий радиус, т.е. половина изображения. Можешь также закомментировать эти строчки и посмотреть, как будет вести себя курсор.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
OffTopic:
p.s. некоторые функции в моей программе работают недостаточно быстро (потому что AutoIt не самый шустрый язык). С этим кругом я придумал такую вещь:

когда мышка преодолевает 30 пикселей в одну из сторон (треть пути до цели), начитать подготовительные работы по этой функции;
а когда мышка проходит 90 пикселей - исполнять эту функцию (уже подготовленную). Мне кажется, это ускорит работу программы.



Добавлено:
Сообщение автоматически объединено:

Мне кажется, что их этого зонтика можно сделать интересный UDF!
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Ты больше получишь с этим гемороя, чем реальной пользы. Мой тебе совет: забей! Лучше оптимизируй свои "медленные" функции.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Yashied
уже голову сломал над этим. Единственный выход - вынос расчетов в dll (на c#). Но для этого нужно освоить c# :(

могу легко написать на Perl, но у 90% пользователей он не установлен (так как в windows все работают).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
Мне кажется, что их этого зонтика можно сделать интересный UDF!

Все в твоих руках. Делай с этим, что хочешь. Я бы нарисовал более красивый круг и добавил бы подсветку секторов при наведении на нее курсора. Для этого нужно нарисовать 8 одинаковых кругов с подсветкой для каждого отдельного сектора. Ну, а дальше дело техники...

Suppir сказал(а):
...уже голову сломал над этим.

Мне просто интересно, что за функции такие медленные, что дают о себе знать. Чего они выполняют?
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Yashied [?]
Все в твоих руках. Делай с этим, что хочешь. Я бы нарисовал более красивый круг и добавил бы подсветку секторов при наведении на нее курсора. Для этого нужно 8 одинаковых кругов с подсветкой для каждого отдельного сектора. Ну, а далее дело техники...

Я думаю сделать прозрачный круг, а которого на максимальном радиусе секторов нарисованы ToolTips. Чтобы при наведении на ToolTip он подсвечивался. В общем, это уже дело вкуса. Спасибо, Yashied :smile:


Добавлено:
Сообщение автоматически объединено:

Yashied [?]
Мне просто интересно, что за функции такие медленные, что дают о себе знать. Чего они выполняют?

Например:

1. Считывается файл 10 Мб в двумерный массив и делается в нем поиск (ключ->значение). Если массив хранить в памяти постоянно, то он отнимает много оперативной памяти (гораздо больше, чем 10 мегабайт). В итоге функция работает 2 - 3 секунды, а пользователи хотят моментальный отклик.

2. Поиск-замена в выделенном тексте. Пользователь выделят текст в редакторе и нажимает хоткей. При этом текст копируется в буфер обмена, из буфера достаются RTF-данные, в которых делается огромная куча замен, потом RTF вставляется обратно в буфер, после чего вставляется обратно в редактор. На самом коротком тексте занимает 5 секунд, а на длинных - до минуты. Это самая медленная функция.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
Если массив хранить в памяти постоянно, то он отнимает много оперативной памяти (гораздо больше, чем 10 мегабайт).

Свопь память в файл подкачки после использования такого массива. Вот простой пример. Открой "Диспетчер задач" и запусти этот скрипт. Посмотри, как меняется объем занимаемой программой памяти при создании массива, свопа, чтения данных из массива и опять свопа.

Код:
#Include <WinAPIEx.au3>

Dim $Array[1000000]

MsgBox(0, '', 'Step 1')

For $i = 0 To UBound($Array) - 1
	$Array[$i] = 'AutoIt v3 is a freeware BASIC-like scripting language designed for automating the Windows GUI and general scripting. It uses a combination of simulated keystrokes, mouse movement and window/control manipulation in order to automate tasks in a way not possible or reliable with other languages (e.g. VBScript and SendKeys). AutoIt is also very small, self-contained and will run on all versions of Windows out-of-the-box with no annoying "runtimes" required!'
Next

MsgBox(0, '', 'Step 2')

_WinAPI_EmptyWorkingSet()

MsgBox(0, '', 'Step 3')

For $i = 0 To UBound($Array) - 1
	If $Array[$i] Then

	EndIf
Next

MsgBox(0, '', 'Step 4')

_WinAPI_EmptyWorkingSet()

MsgBox(0, '', ':-)')
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Step1 - 14 Мб
Step2 - 61 Мб
Step3 - 1,6 Мб
Step4 - 52 Мб

Т.е. эта функция освобождает память, переписывая ее на винчестер?

1) А сильно ли это влияет на быстродействие программы?
2) Если у пользователя отключено создания своп-файла?

Результат интересный, но нужно потестить, дело для меня новое :smile:
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Suppir сказал(а):
А сильно ли это влияет на быстродействие программы?

На мнооооого быстрее, чем чтение файл с диска.

Suppir сказал(а):
Если у пользователя отключено создания своп-файла?

Попробуй.

P.S

Если у пользователя отключен своп, то это очень и очень плохо. Никогда не нужно отключать своп, т.к. это чревато полным зависанием компьютера в самые неподходящие моменты (пример Adobe Photoshop), независимо от того, сколько установлено на нем памяти.
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Прикольно! Раньше при запуске моя программа "весила" 55 мегабайт, а теперь всего 2 Мб.
В понедельник потестю на работе ее быстродействие :smile:


Думаю, что при запуске можно проверять в реестре - включен ли своп. Если своп включен, то использовать эту функцию сброса.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Несмотря на то, что я отключил создание своп-файла, он все равно создается. При запуске windows занимает 250 Мб. А после запуска скрипта - 310 Мб. Сам скрипт, как уже говорил, занимает теперь 1,5 Мб в оперативной памяти. Думаю, что эта функция полезна для компьютеров с небольшим количеством памяти.


Добавлено:
Сообщение автоматически объединено:

Kaster [?]
своп - это и есть чтение из диска

Наверное, чтение из свопа происходит средствами Windows, что быстрее, чем чтение файла средствами Autoit?
Хотя AutoIt использует те же функции апишные.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Suppir
сомневаюсь. суть свопа - скинуть неактивную часть занятой ОЗУ на диск, чтобы освободить место. единственное, если обычное чтения из файлов происходит в виде непрерывной работы головки ЖД, то при свопе возможно при обращении к области памяти что засвоплена, она снова подргужается в память, то есть тормоза разовые. а дальше снова работа уже с ОЗУ. это хорошо заметно при запущенных но долго не работающих приложениях из пакет Office, Photoshop и др. ресурсоемких. если активировать их окно то происходит подгрузка всех библиотек снова в память сопровождающийся сильными тормозами. но дальше все как обычно.
 

Redline

AutoIT Гуру
Сообщения
506
Репутация
375
Yashied
Идея с зонтиком супер! Захотелось развить.
Переделал под 4 сектора, повернул на 45 град., добавил эффект прозрачности, сделал из круга тор :smile: чтобы можно было передумать и добавил sleep(1) чтобы не кушало процессор.
Код:
#Include <GDIPlus.au3>
#Include <Misc.au3>
#Include <WinAPIEx.au3>
#Include <WindowsConstants.au3>

$hCursor = _WinAPI_CopyCursor(_WinAPI_LoadCursor(0, 32512))

_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Sectors.png')
$hBitmap = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Sector1.png')
$hBitmap1 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Sector2.png')
$hBitmap2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Sector3.png')
$hBitmap3 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & '\Sector4.png')
$hBitmap4 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hImage)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()
$hForm = GUICreate('', 300, 300, -1, -1, $WS_POPUPWINDOW, BitOR($WS_EX_LAYERED, $WS_EX_TOPMOST), GUICreate('', -1, -1, -1, -1, -1, $WS_EX_TOOLWINDOW))

$Index = 1

While 1
    Sleep(100)
    If _IsPressed('04') Then
        $XY = MouseGetPos()
        WinMove($hForm, '', $XY[0] - 150, $XY[1] - 150)
        GUISetState(@SW_SHOW, $hForm)
        For $i = 5 To 125 Step 5
            _WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, $i)
            $Timer = TimerInit()
            While Not Floor(TimerDiff($Timer))
                ; Задержка 1 мс
            WEnd
        Next
        _WinAPI_SetSystemCursor(_WinAPI_LoadCursor(0, 32649), 32512, 1)
        While _IsPressed('04')
            $Pos = MouseGetPos()
            $Ang = _Angle($Pos[0], $Pos[1], $XY[0], $XY[1]) ; Угол относительно 10:30 (часов:минут) по часовой стрелке (в градусах)
            $R = Sqrt(($XY[0] - $Pos[0]) ^ 2 + ($XY[1] - $Pos[1]) ^ 2) ; Удаление (радиус) от центра
            If $R > 150 Then ; Если курсор выходит за пределы окружности, радиус = 150
                MouseMove($XY[0] + 150 * Sin($Ang * ATan(1) / 45), $XY[1] - 150 * Cos($Ang * ATan(1) / 45), 0)
            EndIf
			If $R > 25 Then
				Select
					Case ($Ang >= 45 ) And ($Ang < 135 ) ;  45 - 135°
						_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap2, 255)
						ToolTip('Функция 2')
						$Index = 2
					Case ($Ang >= 135 ) And ($Ang < 225) ;  135 - 225°
						_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap3, 255)
						ToolTip('Функция 3')
						$Index = 3
					Case ($Ang >= 225) And ($Ang < 315) ;  225 - 315°
						_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap4, 255)
						ToolTip('Функция 4')
						$Index = 4
					Case Else ;  315 - 45°
						_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap1, 255)
						ToolTip('Функция 1')
						$Index = 1
				EndSelect
			Else
				$Index = 0
				_WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, 125)
				ToolTip('')
			EndIf
			Sleep(1)
        WEnd
        _WinAPI_SetSystemCursor($hCursor, 32512, 1)
        ToolTip('')
        For $i = 125 To 0 Step -5
            _WinAPI_UpdateLayeredWindowEx($hForm, $hBitmap, $i)
            $Timer = TimerInit()
            While Not Floor(TimerDiff($Timer))
                ; Задержка 1 мс
            WEnd
        Next
        GUISetState(@SW_HIDE, $hForm)
        ConsoleWrite('Функция ' & $Index & '...' & @CR)
    EndIf
WEnd

Func _Angle($X, $Y, $XC, $YC)
    If ($X = $XC) And ($Y = $YC) Then
        Return 0
    Else
        Return Mod(360 + ($Y > $YC) * 180 - ATan(($XC - $X) / ($YC - $Y)) * 45 / ATan(1), 360)
    EndIf
EndFunc   ;==>_Angle
 
Автор
S

Suppir

Продвинутый
Сообщения
967
Репутация
62
Redline

Я вот думаю, а можно как-то сделать, чтобы вместо круга отображались короткие стрелочки в 8 сторон.

Здесь нужен человек с художественным вкусом :smile:

Что-то вроде этого, но нужно покрасивее :smile:




Добавлено:
Сообщение автоматически объединено:

p.s. размер в 300 пикселей мне кажется избыточным. Для точного позиционирования мышки вполне достаточно картинки в 100 пикселей.
 
Верх