Posso ativar a rolagem com o botão do meio arrastado no OS X?


16

Eu tenho um mouse com três botões, mas sem roda.

No OS X, existe alguma maneira (talvez com software adicional) que me permita usar meu terceiro botão para rolar, segurando-o e movendo o mouse?

Respostas:


10

O Smart Scroll faz o que você está procurando, com o recurso 'Grab Scroll'. Atribua-o ao 'Botão 3 (Médio)' e arrastar os dois eixos funcionará em aplicativos como navegadores (Chrome), Terminal, Adobe Photoshop e Finder - nenhum aplicativo que tentei não funcionou com ele (usando o 4.0 betas para cima e para cima). Tem um teste gratuito.

insira a descrição da imagem aqui


3

Eu fiz isso com o Hammerspoon com o seguinte script de configuração inspirado neste tópico: https://github.com/tekezo/Karabiner/issues/814#issuecomment-337643019

Passos:

  • Instalar Hammerspoon
  • Clique no ícone do menu e selecione Open Config
  • Cole o seguinte luascript na configuração:

    -- 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()
    

apenas tentei e funciona lindamente.
im_chc 11/05/19

como prefiro fazer o scroll Y ao contrário, alterei um pouco o código lua: altere "dy" na linha "local scroll = hs.eventtap.event.newScrollEvent ({- dx * scrollmult, dy * scrollmult}, {}, 'pixel') "para negativo (então seria" -dy * scrollmult ")
im_chc

2

Smooze faz isso, entre outras coisas. (Eu sou o desenvolvedor)

O que o diferencia de outras sugestões é a capacidade de usá-lo em todos os aplicativos para Mac enquanto ainda identifica links, por exemplo. (caso você use o botão do meio do mouse para agarrar e jogar, mas ainda assim queira que um clique no botão do meio atue como um botão do meio)

Com o Smooze, é mais como agarrar e arrastar do que agarrar e arrastar. O lançamento afeta o momento e a animação do pergaminho, semelhante ao pergaminho do iPhone.

insira a descrição da imagem aqui


2

Há um muito bom aplicativo de código aberto chamado Karabiner que fará isso e muito mais (remapeamento de teclado e mouse etc.). Veja esta pergunta para alguns exemplos. Também para alguns fabricantes, eles fornecem software de controle personalizado que pode permitir funcionalidade aprimorada / modificada (por exemplo, Logitech Control Center).

Como mencionado nos comentários abaixo, embora uma nova versão do 'Karabiner Elements' tenha sido lançada para o MacOS Sierra (10.12), ela fornece apenas remapeamento baseado em teclado até agora - portanto, atualmente, o remapeamento do mouse não pode ser feito com ele.

Contudo Hammerspoon é outra ferramenta gratuita de código aberto que pode ser usada, entre muitas outras coisas, para remapear as teclas do mouse (e / ou teclado) para diferentes funções. Você precisará instalar a ferramenta e fornecer algumas configurações apropriadas - veja exemplos aqui para o remapeamento do mouse.

Para verificar quais tipos de eventos e mouseEventButtonNumbers estão sendo gerados pelo seu dispositivo, você pode executar isso (basta copiar / colar as 4 linhas no console) no console Hammerspoon (Use reload config para pará-lo):

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

Nota: Se você instalou as ferramentas do Logitech Control Center (LCC) - ele captura os eventos diretamente dos dispositivos Logitech usando o módulo do kernel instalado para que Hammerspoon não possa vê-los. Você precisará desinstalar o LCC se desejar remapear os botões do mouse usando o Hammerspoon.


1
Infelizmente, o Karabiner não funciona mais com o OSX moderno. Agora existe um 'Karabiner Elements', mas ele tem metade da funcionalidade do original, e essa é uma das coisas que ele não pode fazer.
Nathan Hornby

1
Sim, atualmente é limitado, por isso atualizei minha resposta para adicionar outra solução.
Pierz 30/10

Hammerspoon é a solução em que eu cheguei ontem, boa sugestão! :) Por alguma razão, não consegui vinculá-lo a um dos botões do mouse, mas o mapeamento para ctrl + cmd parecia funcionar bem.
Nathan Hornby

1
Adicionei outra edição porque tive esse problema quando o LCC foi instalado, mas a desinstalação foi corrigida (depois que trabalhei quais botões geravam qual mouseEventButtonNumber - no mini-botão esquerdo do Marble Mouse é 3 e o certo é 4) .
Pierz

Eu suspeitava que esse poderia ser o problema! Obrigado pela confirmação, eu resolvo isso quando tiver a chance.
Nathan Hornby

1

Depende do software - por exemplo, o Firefox suporta, enquanto o Google Chrome não.

Atualmente, não há software para ativar esse recurso em todo o sistema no OS X, infelizmente.


Talvez não fosse compatível com o Chrome em 2011, mas certamente em 2014, depois de algumas revisões, o 'Grab Scroll' do Smart Scroll funciona sem problemas com o Chrome e o Opera, posso confirmar. Eu acho que também abrange todo o sistema operacional, pois funciona no Finder, Adobe Photoshop e até no Terminal. Acho que seus dados estão desatualizados! :)

1

Usei a Better Touch Tool para atribuir Ctrl + clique do meio no PgUp e Option + clique no PgDown. É um software excelente e gratuito e funciona bem.


1

+1 para Hammerspoon e um script, um mouse / trackball normal me deixa louco em um Mac.

Escrevi uma para rolar enquanto o botão do meio do mouse é pressionado - quanto mais você move o mouse, mais rápido ele irá rolar.

O clique ainda funciona como um clique normal, com uma zona morta de 5 pixels, para que você não precise manter o mouse perfeitamente imóvel entre pressionar e soltar a roda.

------------------------------------------------------------------------------------------
-- 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
------------------------------------------------------------------------------------------

Recurso assassino! Muito obrigado, exatamente o que eu estava procurando. No entanto, um erro deltaX = deltaY * -1deveria ser deltaY = deltaY * -1e comentei deltaX = deltaX * -1porque não queria que o eixo X fosse invertido.
Tyler #

Obrigado por detectar o erro de digitação. Eu reescrevi-lo um pouco e mudou a opção para reverter a rolagem vertical única
TIM
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.