Могу ли я включить прокрутку с помощью перетаскивания средней кнопкой в ​​OS X?

16

У меня есть мышь с тремя кнопками, но без колеса.

В OS X есть ли способ (возможно, с дополнительным программным обеспечением), который позволил бы мне использовать третью кнопку для прокрутки, удерживая ее и перемещая мышь?

КДТ
источник

Ответы:

10

Smart Scroll делает то, что вы ищете, с помощью функции «Grab Scroll». Присвойте его «Кнопке 3 (по центру)», и перетаскивание по обеим осям будет работать в таких приложениях, как браузеры (Chrome), Terminal, Adobe Photoshop и Finder - ни одно приложение, которое я пробовал, не работало с ним (с использованием 4.0 беты вверх и вверх). Это бесплатная пробная версия.

введите описание изображения здесь

Ishan
источник
3

Я сделал это с помощью Hammerspoon с помощью следующего скрипта настройки, вдохновленного этой веткой : https://github.com/tekezo/Karabiner/issues/814#issuecomment-337643019

шаги:

  • Установить молоток
  • Нажмите на значок своего меню и выберите Open Config
  • Вставьте следующий luaскрипт в конфигурацию:

    -- HANDLE SCROLLING WITH MOUSE BUTTON PRESSED
    local scrollMouseButton = 2
    local deferred = false
    
    overrideOtherMouseDown = hs.eventtap.new({ hs.eventtap.event.types.otherMouseDown }, function(e)
        -- print("down")
        local pressedMouseButton = e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber'])
        if scrollMouseButton == pressedMouseButton 
            then 
                deferred = true
                return true
            end
    end)
    
    overrideOtherMouseUp = hs.eventtap.new({ hs.eventtap.event.types.otherMouseUp }, function(e)
        -- print("up")
        local pressedMouseButton = e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber'])
        if scrollMouseButton == pressedMouseButton 
            then 
                if (deferred) then
                    overrideOtherMouseDown:stop()
                    overrideOtherMouseUp:stop()
                    hs.eventtap.otherClick(e:location(), pressedMouseButton)
                    overrideOtherMouseDown:start()
                    overrideOtherMouseUp:start()
                    return true
                end
                return false
            end
            return false
    end)
    
    local oldmousepos = {}
    local scrollmult = -4   -- negative multiplier makes mouse work like traditional scrollwheel
    
    dragOtherToScroll = hs.eventtap.new({ hs.eventtap.event.types.otherMouseDragged }, function(e)
        local pressedMouseButton = e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber'])
        -- print ("pressed mouse " .. pressedMouseButton)
        if scrollMouseButton == pressedMouseButton 
            then 
                -- print("scroll");
                deferred = false
                oldmousepos = hs.mouse.getAbsolutePosition()    
                local dx = e:getProperty(hs.eventtap.event.properties['mouseEventDeltaX'])
                local dy = e:getProperty(hs.eventtap.event.properties['mouseEventDeltaY'])
                local scroll = hs.eventtap.event.newScrollEvent({-dx * scrollmult, dy * scrollmult},{},'pixel')
                -- put the mouse back
                hs.mouse.setAbsolutePosition(oldmousepos)
                return true, {scroll}
            else 
                return false, {}
            end 
    end)
    
    overrideOtherMouseDown:start()
    overrideOtherMouseUp:start()
    dragOtherToScroll:start()
    
Алекс Бурдусел
источник
только что попробовал, и это прекрасно работает.
im_chc
так как я предпочитаю делать Y-прокрутку наоборот, я немного изменил код lua: измените «dy» в строке «local scroll = hs.eventtap.event.newScrollEvent ({- dx * scrollmult, dy * scrollmult}, {}, 'pixel') "в минус (так что это будет" -dy * scrollmult ")
im_chc
2

Smooze делает это, между прочим. (Я разработчик)

Что отличает его от других предложений, так это возможность использовать его в каждом приложении Mac, в то же время идентифицируя ссылки, например. (в случае, если вы используете перетаскивание средней кнопкой, чтобы захватить и бросить, но все же хотите, чтобы нажатие средней кнопки действовало как средняя кнопка)

С Smooze больше похоже на захват-перетаскивание, чем захват-перетаскивание. Релиз влияет на импульс и анимацию прокрутки, аналогично прокрутке iPhone.

введите описание изображения здесь

Segev
источник
2

Есть очень хорошее приложение с открытым исходным кодом под названием Karabiner, которое сделает это и многое другое (переназначение клавиатуры и мыши и т. Д.). Посмотрите этот вопрос для некоторых примеров. Также для определенных производителей они поставляют специализированное программное обеспечение для управления, которое может предоставлять улучшенные / модифицированные функции (например, Logitech Control Center).

Как упомянуто в комментариях ниже, хотя новая версия «Karabiner Elements» была выпущена для MacOS Sierra (10.12) и выше, на данный момент она предусматривает только переназначение на основе клавиатуры - поэтому в настоящее время переназначение мыши невозможно с ним.

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

Чтобы проверить, какие типы событий и mouseEventButtonNumbers генерируются вашим устройством, вы можете запустить это (просто скопируйте / вставьте 4 строки в консоль) в консоли Hammerspoon (используйте, reload configчтобы остановить его):

hs.eventtap.new({"all"},function(e)
print(e,"mouseEventButtonNumber:",
e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber']))
end):start()

Примечание. Если вы установили инструменты Logitech Control Center (LCC) - он получает события непосредственно с устройств Logitech, используя установленный модуль ядра, поэтому Hammerspoon их не видит. Вам нужно будет удалить LCC, если вы хотите переназначить кнопки мыши с помощью Hammerspoon.

Пирз
источник
1
К сожалению, Karabiner больше не работает с современным OSX. Теперь есть «Элементы Карабинера», которые имеют половину функциональности оригинала, и это одна из вещей, которые он не может сделать.
Натан Хорнби
1
Да, в настоящее время оно ограничено, поэтому я обновил свой ответ, чтобы добавить другое решение.
Пирз
Hammerspoon - это решение, которое я получил вчера, так что хорошее предложение! :) По какой-то причине я не смог привязать его к одной из кнопок мыши, но отображение его на ctrl + cmd, похоже, работало нормально.
Натан Хорнби,
1
Я добавил еще одно редактирование, так как у меня была эта проблема, когда у меня была установлена ​​LCC, но удаление ее исправило (как только я поработал, какие кнопки генерировали, какую mouseEventButtonNumber - на левой левой кнопке Marble Mouse - 3, а правой - 4) ,
Пирз
Я подозревал, что это может быть проблемой! Спасибо за подтверждение, я разберусь, когда получу шанс.
Натан Хорнби
1

Это зависит от программного обеспечения - например, Firefox поддерживает его, а Google Chrome - нет.

В настоящее время, к сожалению, в OS X нет программного обеспечения, позволяющего использовать такую ​​функцию в масштабе всей системы.


источник
Может быть, он не был совместим с Chrome еще в 2011 году, но, безусловно, в 2014 году, после многих сомнений, Smart Scroll 'Grab Scroll' без проблем работает с Chrome и Opera, я могу подтвердить. Я думаю, что это также для всей ОС, так как работает в Finder, Adobe Photoshop и даже в Terminal. Поэтому я думаю, что ваши данные устарели! :)
1

Я использовал Better Touch Tool, чтобы назначить Ctrl + средний щелчок для PgUp, а Option + Middle-click для PgDown. Это бесплатное, отличное программное обеспечение и работает хорошо.

ezrock
источник
1

+1 за Hammerspoon и скрипт, нормальная мышь / трекбол сводит меня с ума на Mac.

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

Щелчок по-прежнему работает как обычный щелчок с мертвой зоной в 5 пикселей, поэтому вам не нужно держать мышь неподвижно между нажатием и отпусканием колеса.

------------------------------------------------------------------------------------------
-- AUTOSCROLL WITH MOUSE WHEEL BUTTON
-- timginter @ GitHub
------------------------------------------------------------------------------------------

-- id of mouse wheel button
local mouseScrollButtonId = 2

-- scroll speed and direction config
local scrollSpeedMultiplier = 0.1
local scrollSpeedSquareAcceleration = true
local reverseVerticalScrollDirection = false
local mouseScrollTimerDelay = 0.01

-- circle config
local mouseScrollCircleRad = 10
local mouseScrollCircleDeadZone = 5

------------------------------------------------------------------------------------------

local mouseScrollCircle = nil
local mouseScrollTimer = nil
local mouseScrollStartPos = 0
local mouseScrollDragPosX = nil
local mouseScrollDragPosY = nil

overrideScrollMouseDown = hs.eventtap.new({ hs.eventtap.event.types.otherMouseDown }, function(e)
    -- uncomment line below to see the ID of pressed button
    --print(e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber']))

    if e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber']) == mouseScrollButtonId then
        -- remove circle if exists
        if mouseScrollCircle then
            mouseScrollCircle:delete()
            mouseScrollCircle = nil
        end

        -- stop timer if running
        if mouseScrollTimer then
            mouseScrollTimer:stop()
            mouseScrollTimer = nil
        end

        -- save mouse coordinates
        mouseScrollStartPos = hs.mouse.getAbsolutePosition()
        mouseScrollDragPosX = mouseScrollStartPos.x
        mouseScrollDragPosY = mouseScrollStartPos.y

        -- start scroll timer
        mouseScrollTimer = hs.timer.doAfter(mouseScrollTimerDelay, mouseScrollTimerFunction)

        -- don't send scroll button down event
        return true
    end
end)

overrideScrollMouseUp = hs.eventtap.new({ hs.eventtap.event.types.otherMouseUp }, function(e)
    if e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber']) == mouseScrollButtonId then
        -- send original button up event if released within 'mouseScrollCircleDeadZone' pixels of original position and scroll circle doesn't exist
        mouseScrollPos = hs.mouse.getAbsolutePosition()
        xDiff = math.abs(mouseScrollPos.x - mouseScrollStartPos.x)
        yDiff = math.abs(mouseScrollPos.y - mouseScrollStartPos.y)
        if (xDiff < mouseScrollCircleDeadZone and yDiff < mouseScrollCircleDeadZone) and not mouseScrollCircle then
            -- disable scroll mouse override
            overrideScrollMouseDown:stop()
            overrideScrollMouseUp:stop()

            -- send scroll mouse click
            hs.eventtap.otherClick(e:location(), mouseScrollButtonId)

            -- re-enable scroll mouse override
            overrideScrollMouseDown:start()
            overrideScrollMouseUp:start()
        end

        -- remove circle if exists
        if mouseScrollCircle then
            mouseScrollCircle:delete()
            mouseScrollCircle = nil
        end

        -- stop timer if running
        if mouseScrollTimer then
            mouseScrollTimer:stop()
            mouseScrollTimer = nil
        end

        -- don't send scroll button up event
        return true
    end
end)

overrideScrollMouseDrag = hs.eventtap.new({ hs.eventtap.event.types.otherMouseDragged }, function(e)
    -- sanity check
    if mouseScrollDragPosX == nil or mouseScrollDragPosY == nil then
        return true
    end

    -- update mouse coordinates
    mouseScrollDragPosX = mouseScrollDragPosX + e:getProperty(hs.eventtap.event.properties['mouseEventDeltaX'])
    mouseScrollDragPosY = mouseScrollDragPosY + e:getProperty(hs.eventtap.event.properties['mouseEventDeltaY'])

    -- don't send scroll button drag event
    return true
end)

function mouseScrollTimerFunction()
    -- sanity check
    if mouseScrollDragPosX ~= nil and mouseScrollDragPosY ~= nil then
        -- get cursor position difference from original click
        xDiff = math.abs(mouseScrollDragPosX - mouseScrollStartPos.x)
        yDiff = math.abs(mouseScrollDragPosY - mouseScrollStartPos.y)

        -- draw circle if not yet drawn and cursor moved more than 'mouseScrollCircleDeadZone' pixels
        if mouseScrollCircle == nil and (xDiff > mouseScrollCircleDeadZone or yDiff > mouseScrollCircleDeadZone) then
            mouseScrollCircle = hs.drawing.circle(hs.geometry.rect(mouseScrollStartPos.x - mouseScrollCircleRad, mouseScrollStartPos.y - mouseScrollCircleRad, mouseScrollCircleRad * 2, mouseScrollCircleRad * 2))
            mouseScrollCircle:setStrokeColor({["red"]=0.3, ["green"]=0.3, ["blue"]=0.3, ["alpha"]=1})
            mouseScrollCircle:setFill(false)
            mouseScrollCircle:setStrokeWidth(1)
            mouseScrollCircle:show()
        end

        -- send scroll event if cursor moved more than circle's radius
        if xDiff > mouseScrollCircleRad or yDiff > mouseScrollCircleRad then
            -- get real xDiff and yDiff
            deltaX = mouseScrollDragPosX - mouseScrollStartPos.x
            deltaY = mouseScrollDragPosY - mouseScrollStartPos.y

            -- use 'scrollSpeedMultiplier'
            deltaX = deltaX * scrollSpeedMultiplier
            deltaY = deltaY * scrollSpeedMultiplier

            -- square for better scroll acceleration
            if scrollSpeedSquareAcceleration then
                -- mod to keep negative values
                deltaXDirMod = 1
                deltaYDirMod = 1

                if deltaX < 0 then
                    deltaXDirMod = -1
                end
                if deltaY < 0 then
                    deltaYDirMod = -1
                end

                deltaX = deltaX * deltaX * deltaXDirMod
                deltaY = deltaY * deltaY * deltaYDirMod
            end

            -- math.floor - scroll event accepts only integers
            deltaX = math.floor(deltaX)
            deltaY = math.floor(deltaY)

            -- reverse Y scroll if 'reverseVerticalScrollDirection' set to true
            if reverseVerticalScrollDirection then
                deltaY = deltaY * -1
            end

            -- send scroll event
            hs.eventtap.event.newScrollEvent({-deltaX, deltaY}, {}, 'pixel'):post()
        end
    end

    -- restart timer
    mouseScrollTimer = hs.timer.doAfter(mouseScrollTimerDelay, mouseScrollTimerFunction)
end

-- start override functions
overrideScrollMouseDown:start()
overrideScrollMouseUp:start()
overrideScrollMouseDrag:start()

------------------------------------------------------------------------------------------
-- END OF AUTOSCROLL WITH MOUSE WHEEL BUTTON
------------------------------------------------------------------------------------------
ТИМ
источник
Особенность убийцы! Большое спасибо, именно то, что я искал. Одна ошибка, однако, deltaX = deltaY * -1должна быть, deltaY = deltaY * -1и я прокомментировал, deltaX = deltaX * -1потому что я не хотел инвертировать ось X.
Тайлер
Спасибо, что обнаружили опечатку. Я переписал это немного и изменил опцию, чтобы изменить только вертикальную прокрутку
TIM