Основы событий мыши
В этой главе мы более детально рассмотрим события мыши и их свойства.
Сразу заметим: эти события бывают не только из-за мыши, но и эмулируются на других устройствах, в частности, на мобильных, для совместимости.
Типы событий мыши
Мы уже видели некоторые из этих событий:
mousedown/mouseup Кнопка мыши нажата/отпущена над элементом. mouseover/mouseout Курсор мыши появляется над элементом и уходит с него. mousemove Каждое движение мыши над элементом генерирует это событие. click Вызывается при mousedown , а затем mouseup над одним и тем же элементом, если использовалась левая кнопка мыши. dblclick Вызывается двойным кликом на элементе. contextmenu Вызывается при попытке открытия контекстного меню, как правило, нажатием правой кнопки мыши. Но, заметим, это не совсем событие мыши, оно может вызываться и специальной клавишей клавиатуры.
…Есть также несколько иных типов событий, которые мы рассмотрим позже.
Порядок событий
Как вы можете видеть из приведённого выше списка, действие пользователя может вызвать несколько событий.
Например, клик мышью вначале вызывает mousedown , когда кнопка нажата, затем mouseup и click , когда она отпущена.
В случае, когда одно действие инициирует несколько событий, порядок их выполнения фиксирован. То есть обработчики событий вызываются в следующем порядке: mousedown → mouseup → click .
Кликните на кнопку ниже, и вы увидите события. Также попробуйте двойной клик.
В окне теста ниже все события мыши записываются, и если задержка между ними более 1 секунды, то они разделяются горизонтальной чертой.
Кроме того, мы можем видеть свойство button , которое позволяет нам определять кнопку мыши; это объясняется ниже.
Кнопки мыши
События, связанные с кликом, всегда имеют свойство button , которое позволяет получить конкретную кнопку мыши.
Обычно мы не используем его для событий click и contextmenu , потому что первое происходит только при щелчке левой кнопкой мыши, а второе – только при щелчке правой кнопкой мыши.
С другой стороны, обработчикам mousedown и mouseup может потребоваться event.button , потому что эти события срабатывают на любую кнопку, таким образом button позволяет различать «нажатие правой кнопки» и «нажатие левой кнопки».
Возможными значениями event.button являются:
| Состояние кнопки | event.button |
|---|---|
| Левая кнопка (основная) | 0 |
| Средняя кнопка (вспомогательная) | 1 |
| Правая кнопка (вторичная) | 2 |
| Кнопка X1 (назад) | 3 |
| Кнопка X2 (вперёд) | 4 |
Большинство мышек имеют только левую и правую кнопку, поэтому возможные значения это 0 или 2. Сенсорные устройства также генерируют аналогичные события, когда кто-то нажимает на них.
Также есть свойство event.buttons , в котором все нажатые в данный момент кнопки представлены в виде целого числа, по одному биту на кнопку. На практике это свойство используется очень редко, вы можете найти подробную информацию по адресу MDN, если вам это когда-нибудь понадобится.
В старом коде вы можете встретить event.which свойство – это старый нестандартный способ получения кнопки с возможными значениями:
- event.which == 1 – левая кнопка,
- event.which == 2 – средняя кнопка,
- event.which == 3 – правая кнопка.
На данный момент event.which устарел, нам не следует его использовать.
Средняя кнопка сейчас – скорее экзотика, и используется очень редко.
Модификаторы: shift, alt, ctrl и meta
Все события мыши включают в себя информацию о нажатых клавишах-модификаторах.
- shiftKey : Shift
- altKey : Alt (или Opt для Mac)
- ctrlKey : Ctrl
- metaKey : Cmd для Mac
Они равны true , если во время события была нажата соответствующая клавиша.
Например, кнопка внизу работает только при комбинации Alt + Shift +клик:
В Windows и Linux клавишами-модификаторами являются Alt , Shift и Ctrl . На Mac есть ещё одна: Cmd , которой соответствует свойство metaKey .
В большинстве приложений, когда в Windows/Linux используется Ctrl , на Mac используется Cmd .
То есть, когда пользователь Windows нажимает Ctrl + Enter и Ctrl + A , пользователь Mac нажимает Cmd + Enter или Cmd + A , и так далее.
Поэтому, если мы хотим поддерживать такие комбинации, как Ctrl +клик, то для Mac имеет смысл использовать Cmd +клик. Это удобней для пользователей Mac.
Даже если мы и хотели бы заставить людей на Mac использовать именно Ctrl +клик, это довольно сложно. Проблема в том, что левый клик в сочетании с Ctrl интерпретируется как правый клик на MacOS и генерирует событие contextmenu , а не click как на Windows/Linux.
Поэтому, если мы хотим, чтобы пользователям всех операционных систем было удобно, то вместе с ctrlKey нам нужно проверять metaKey .
Для JS-кода это означает, что мы должны проверить if (event.ctrlKey || event.metaKey) .
Комбинации клавиш хороши в качестве дополнения к рабочему процессу. Так что, если посетитель использует клавиатуру – они работают.
Но если на их устройстве его нет – тогда должен быть способ жить без клавиш-модификаторов.
Координаты: clientX/Y, pageX/Y
Все события мыши имеют координаты двух видов:
- Относительно окна: clientX и clientY .
- Относительно документа: pageX и pageY .
Мы уже рассмотрели разницу между ними в главе Координаты.
Если в кратце, то относительные координаты документа pageX/Y отсчитываются от левого верхнего угла документа и не меняются при прокрутке страницы, в то время как clientX/Y отсчитываются от левого верхнего угла текущего окна. Когда страница прокручивается, они меняются.
Например, если у нас есть окно размером 500×500, и курсор мыши находится в левом верхнем углу, то значения clientX и clientY равны 0 , независимо от того, как прокручивается страница.
А если мышь находится в центре окна, то значения clientX и clientY равны 250 независимо от того, в каком месте документа она находится и до какого места документ прокручен. В этом они похожи на position:fixed .
Наведите курсор мыши на поле ввода, чтобы увидеть clientX/clientY (пример находится в iframe , поэтому координаты определяются относительно этого iframe ):
Координаты относительно документа pageX , pageY отсчитываются не от окна, а от левого верхнего угла документа. Подробнее о координатах вы можете узнать в главе Координаты.
Отключаем выделение
Двойной клик мыши имеет побочный эффект, который может быть неудобен в некоторых интерфейсах: он выделяет текст.
Например, двойной клик на текст ниже выделяет его в дополнение к нашему обработчику:
Если зажать левую кнопку мыши и, не отпуская кнопку, провести мышью, то также будет выделение, которое в интерфейсах может быть «не кстати».
Есть несколько способов запретить выделение, о которых вы можете прочитать в главе Selection и Range.
В данном случае самым разумным будет отменить действие браузера по умолчанию при событии mousedown , это отменит оба этих выделения:
Теперь выделенный жирным элемент не выделяется при двойном клике, а также на нём нельзя начать выделение, зажав кнопку мыши.
Заметим, что текст внутри него по-прежнему можно выделить, если начать выделение не на самом тексте, а до него или после. Обычно это нормально воспринимается пользователями.
Если мы хотим отключить выделение для защиты содержимого страницы от копирования, то мы можем использовать другое событие: oncopy .
Если вы попытаетесь скопировать текст в <div> , у вас это не получится, потому что срабатывание события oncopy по умолчанию запрещено.
Конечно, пользователь имеет доступ к HTML-коду страницы и может взять текст оттуда, но не все знают, как это сделать.
Итого
События мыши имеют следующие свойства:
Клавиши-модификаторы ( true если нажаты): altKey , ctrlKey , shiftKey и metaKey (Mac).
- Если вы планируете обработать Ctrl , то не забудьте, что пользователи Mac обычно используют Cmd , поэтому лучше проверить if (e.metaKey || e.ctrlKey) .
Координаты относительно окна: clientX/clientY .
Координаты относительно документа: pageX/pageY .
Действие по умолчанию события mousedown – начало выделения, если в интерфейсе оно скорее мешает, его можно отменить.
В следующей главе мы поговорим о событиях, которые возникают при передвижении мыши, и об отслеживании смены элементов под указателем.
Задачи
Выделяемый список
Создайте список, в котором элементы могут быть выделены, как в файловых менеджерах.
MouseEvent
Интерфейс MouseEvent представляет собой событие, которое происходит в результате взаимодействия пользователя с манипулятором ( например, мышью). Наиболее частые из таких событий: click (en-US) , dblclick (en-US) , mouseup (en-US) , mousedown (en-US) .
MouseEvent выводится из метода UIEvent (en-US), который в свою очередь происходит из метода Event . Метод MouseEvent.initMouseEvent() (en-US) допустимо использовать для лучшей совместимости с предыдущими версиями, однако, для создания MouseEvent рекомендуется использовать конструктор метода MouseEvent() (en-US).
Несколько более конкретные события, производные от события mouseevent: WheelEvent (en-US) and DragEvent (en-US).
Конструктор
Создаёт объект MouseEvent .
Свойства
Данный интерфейс наследует свойства от родителей UIEvent (en-US) и Event .
Возвращает значение true, если клавиша
была нажата во время движения мыши.
Представляет код клавиши, нажатой в то время, когда произошло событие мыши.
Отображает, какие клавиши были нажаты во время движения мыши.
Отображение X координат курсора мыши в локальной системе координат (DOM контент).
Отображение Y координат курсора мыши в локальной системе координат (DOM контент).
Возвращает значение true, если клавиша
была нажата во время движения мыши.
Возвращает значение true, если клавиша
была нажата во время движения мыши.
Отображает X координат указателя мыши относительно позиции последнего mousemove (en-US) события.
Отображает Y координат указателя мыши относительно позиции последнего mousemove (en-US) события.
Отображает X координат указателя мыши относительно позиции границы отступа целевого узла.
Отображает Y координат указателя мыши относительно позиции границы отступа целевого узла.
Отображает X координат указателя мыши относительно всего документа.
Отображает Y координат указателя мыши относительно всего документа.
Возвращает id затронутого событием региона. Если ни какой регион затронут не был, возвращает null.
Второстепенная цель события, если таковая есть.
Отображает X координат указателя мыши в пространстве экрана.
Отображает Y координат указателя мыши в пространстве экрана.
Возвращает true если клавиша
была нажата, когда произошло событие мыши.
Возвращает код последней нажатой клавиши, когда произошло событие мыши.
Отображает давление которое было осуществлено при нажатии. Значение будет между 0.0 (минимальное давление) и 1.0 (максимальное давление).
The type of device that generated the event (one of the MOZ_SOURCE_* constants listed below). This lets you, for example, determine whether a mouse event was generated by an actual mouse or by a touch event (which might affect the degree of accuracy with which you interpret the coordinates associated with the event).
Отображает количество приложенного давления при клике.
Константы
Минимальная необходимая сила для обычного клика
Минимальная необходимая сила для усиленного клика
Методы
Данный интерфейс наследует свойства от родителей, UIEvent (en-US) and Event .
Returns the current state of the specified modifier key. See the KeyboardEvent.getModifierState (en-US)() for details.
Initializes the value of a MouseEvent created. If the event has already being dispatched, this method does nothing.
Пример
Данный пример демонстрирует симуляцию нажатия левой клавиши мыши (событие мыши генерируется программно) по чекбоксу используя методы DOM.
Mouse events
In this chapter we’ll get into more details about mouse events and their properties.
Please note: such events may come not only from “mouse devices”, but are also from other devices, such as phones and tablets, where they are emulated for compatibility.
Mouse event types
We’ve already seen some of these events:
mousedown/mouseup Mouse button is clicked/released over an element. mouseover/mouseout Mouse pointer comes over/out from an element. mousemove Every mouse move over an element triggers that event. click Triggers after mousedown and then mouseup over the same element if the left mouse button was used. dblclick Triggers after two clicks on the same element within a short timeframe. Rarely used nowadays. contextmenu Triggers when the right mouse button is pressed. There are other ways to open a context menu, e.g. using a special keyboard key, it triggers in that case also, so it’s not exactly the mouse event.
…There are several other events too, we’ll cover them later.
Events order
As you can see from the list above, a user action may trigger multiple events.
For instance, a left-button click first triggers mousedown , when the button is pressed, then mouseup and click when it’s released.
In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order mousedown → mouseup → click .
Click the button below and you’ll see the events. Try double-click too.
On the teststand below, all mouse events are logged, and if there is more than a 1 second delay between them, they are separated by a horizontal rule.
Also, we can see the button property that allows us to detect the mouse button; it’s explained below.
Mouse button
Click-related events always have the button property, which allows to get the exact mouse button.
We usually don’t use it for click and contextmenu events, because the former happens only on left-click, and the latter – only on right-click.
On the other hand, mousedown and mouseup handlers may need event.button , because these events trigger on any button, so button allows to distinguish between “right-mousedown” and “left-mousedown”.
The possible values of event.button are:
| Button state | event.button |
|---|---|
| Left button (primary) | 0 |
| Middle button (auxiliary) | 1 |
| Right button (secondary) | 2 |
| X1 button (back) | 3 |
| X2 button (forward) | 4 |
Most mouse devices only have the left and right buttons, so possible values are 0 or 2 . Touch devices also generate similar events when one taps on them.
Also there’s event.buttons property that has all currently pressed buttons as an integer, one bit per button. In practice this property is very rarely used, you can find details at MDN if you ever need it.
Old code may use event.which property that’s an old non-standard way of getting a button, with possible values:
- event.which == 1 – left button,
- event.which == 2 – middle button,
- event.which == 3 – right button.
As of now, event.which is deprecated, we shouldn’t use it.
Modifiers: shift, alt, ctrl and meta
All mouse events include the information about pressed modifier keys.
- shiftKey : Shift
- altKey : Alt (or Opt for Mac)
- ctrlKey : Ctrl
- metaKey : Cmd for Mac
They are true if the corresponding key was pressed during the event.
For instance, the button below only works on Alt + Shift +click:
On Windows and Linux there are modifier keys Alt , Shift and Ctrl . On Mac there’s one more: Cmd , corresponding to the property metaKey .
In most applications, when Windows/Linux uses Ctrl , on Mac Cmd is used.
That is: where a Windows user presses Ctrl + Enter or Ctrl + A , a Mac user would press Cmd + Enter or Cmd + A , and so on.
So if we want to support combinations like Ctrl +click, then for Mac it makes sense to use Cmd +click. That’s more comfortable for Mac users.
Even if we’d like to force Mac users to Ctrl +click – that’s kind of difficult. The problem is: a left-click with Ctrl is interpreted as a right-click on MacOS, and it generates the contextmenu event, not click like Windows/Linux.
So if we want users of all operating systems to feel comfortable, then together with ctrlKey we should check metaKey .
For JS-code it means that we should check if (event.ctrlKey || event.metaKey) .
Keyboard combinations are good as an addition to the workflow. So that if the visitor uses a keyboard – they work.
But if their device doesn’t have it – then there should be a way to live without modifier keys.
Coordinates: clientX/Y, pageX/Y
All mouse events provide coordinates in two flavours:
- Window-relative: clientX and clientY .
- Document-relative: pageX and pageY .
We already covered the difference between them in the chapter Coordinates.
In short, document-relative coordinates pageX/Y are counted from the left-upper corner of the document, and do not change when the page is scrolled, while clientX/Y are counted from the current window left-upper corner. When the page is scrolled, they change.
For instance, if we have a window of the size 500×500, and the mouse is in the left-upper corner, then clientX and clientY are 0 , no matter how the page is scrolled.
And if the mouse is in the center, then clientX and clientY are 250 , no matter what place in the document it is. They are similar to position:fixed in that aspect.
Move the mouse over the input field to see clientX/clientY (the example is in the iframe , so coordinates are relative to that iframe ):
Preventing selection on mousedown
Double mouse click has a side effect that may be disturbing in some interfaces: it selects text.
For instance, double-clicking on the text below selects it in addition to our handler:
If one presses the left mouse button and, without releasing it, moves the mouse, that also makes the selection, often unwanted.
There are multiple ways to prevent the selection, that you can read in the chapter Selection and Range.
In this particular case the most reasonable way is to prevent the browser action on mousedown . It prevents both these selections:
Now the bold element is not selected on double clicks, and pressing the left button on it won’t start the selection.
Please note: the text inside it is still selectable. However, the selection should start not on the text itself, but before or after it. Usually that’s fine for users.
If we want to disable selection to protect our page content from copy-pasting, then we can use another event: oncopy .
If you try to copy a piece of text in the <div> , that won’t work, because the default action oncopy is prevented.
Surely the user has access to HTML-source of the page, and can take the content from there, but not everyone knows how to do it.
Summary
Mouse events have the following properties:
Modifier keys ( true if pressed): altKey , ctrlKey , shiftKey and metaKey (Mac).
- If you want to handle Ctrl , then don’t forget Mac users, they usually use Cmd , so it’s better to check if (e.metaKey || e.ctrlKey) .
Window-relative coordinates: clientX/clientY .
Document-relative coordinates: pageX/pageY .
The default browser action of mousedown is text selection, if it’s not good for the interface, then it should be prevented.
In the next chapter we’ll see more details about events that follow pointer movement and how to track element changes under it.
Mice event что это
Функция _TrackMouseEvent посылает сообщения тогда, когда указатель мыши оставляет окно или нависает над окном на указанное время. Эта функция вызывает TrackMouseEvent если таковая существует, или же она имитирует её.
Функция DragDetect захватывает мышь и отслеживает ее перемещение до тех пор, пока пользователь не отпустит левую кнопку, нажмет клавишу ESC или переместит мышь за пределы перетаскиваемого прямоугольника около указанной точки. Ширина и высота перетаскиваемого прямоугольника определяются значениями SM_CXDRAG и SM_CYDRAG , возвращенными функцией GetSystemMetrics .
Функция GetCapture извлекает дескриптор окна (если он есть), которое захватило мышь. Одновременно только одно окно может захватить мышь; это окно получает ввод данных от мыши, в любом случае, есть или нет курсора внутри его границ.
Функция GetDoubleClickTime извлекает текущее время двойного щелчка мыши. Двойной щелчок — это серия двух щелчков кнопки мыши, когда второй происходит в пределах заданного времени после первого. Время двойного щелчка — это максимальное число миллисекунд, которые могут пройти между первым и вторым щелчком в двойном щелчке.
Функция GetMouseMovePointsEx извлекает архив данных до 64 предыдущих координат мыши или пера.
Функция ReleaseCapture освобождает мышь от захвата окном в текущем потоке и восстанавливает обычную обработку ввода данных от мыши. Окно, которое захватило мышь, получает весь ввод данных от мыши, независимо от позиции курсора, кроме тех случаев, когда кнопкой мыши щелкают в то время, когда острие курсора находится в окне другого потока.
Функция SetDoubleClickTime устанавливает время двойного щелчка для мыши. Двойной щелчок — серия из двух щелчков кнопки мыши, в которой второй происходит в пределах заданного времени после первого. Время двойного щелчка — это максимальное число миллисекунд, которые могут пройти между первым и вторым щелчками двойного щелчка.
Функция SwapMouseButton изменяет на противоположное (инвертирует) или восстанавливает предназначение левых и правых кнопок мыши.
Функция TrackMouseEvent посылает сообщения, когда указатель мыши оставляет окно или нависает над окном на определенное количество времени.