답변:
Smart Scroll 은 'Grab Scroll'기능을 사용하여 원하는 것을 수행합니다. '버튼 3 (중간)'에 할당하고 브라우저 (Chrome), 터미널, Adobe Photoshop 및 Finder와 같은 앱에서 두 축을 드래그하면 작동합니다-시도한 앱이 작동하지 않습니다 (4.0 사용) 베타). 무료 평가판이 있습니다.
이 스레드에서 영감을 얻은 다음 구성 스크립트 로 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()
Karabiner 라는 멋진 오픈 소스 앱 이 있습니다.이 기능은 훨씬 더 많은 기능을 제공합니다 (키보드 및 마우스 리 맵핑 등). 몇 가지 예는 이 질문 을 참조하십시오 . 또한 특정 제조업체의 경우 개선 / 수정 기능 (예 : Logitech Control Center)을 허용 할 수있는 사용자 지정 제어 소프트웨어를 제공합니다.
아래 의견에서 언급했듯이 MacOS Sierra (10.12) 이후에는 새로운 버전의 'Karabiner Elements'가 출시되었지만 지금까지는 키보드 기반 리 맵핑 만 제공하므로 현재 마우스 리 맵핑을 수행 할 수 없습니다.
그러나 Hammerspoon 은 다른 무료 오픈 소스 도구로, 마우스 및 / 또는 키보드의 키를 다른 기능에 다시 매핑하는 데 사용할 수 있습니다. 도구를 설치하고 적절한 구성을 제공해야합니다 . 마우스 다시 매핑에 대한 예는 여기 를 참조하십시오 .
장치에서 어떤 이벤트 유형과 mouseEventButtonNumbers가 생성되는지 확인하려면 Hammerspoon 콘솔에서이를 실행하십시오 (4 줄을 콘솔에 복사 / 붙여 넣기 만하면 됨 reload config
).
hs.eventtap.new({"all"},function(e)
print(e,"mouseEventButtonNumber:",
e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber']))
end):start()
참고 : LCC (Logitech Control Center) 도구를 설치 한 경우 설치된 커널 모듈을 사용하여 Logitech 장치에서 직접 이벤트를 가져와 Hammerspoon에서이를 볼 수 없습니다. Hammerspoon을 사용하여 마우스 버튼을 다시 매핑하려면 LCC를 제거해야합니다.
소프트웨어에 따라 다릅니다 (예 : Firefox는 소프트웨어를 지원하지만 Chrome은 지원하지 않습니다).
현재 슬프게도 OS X에서 이러한 기능을 시스템 전체에서 활성화하는 소프트웨어는 없습니다.
Better Touch Tool 을 사용 하여 Ctrl + 중간 클릭을 PgUp에, Option + 중간 클릭을 PgDown에 할당했습니다. 무료이며 우수한 소프트웨어이며 잘 작동합니다.
Hammerspoon과 스크립트의 경우 +1, 일반 마우스 / 트랙볼은 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
있어야하며 X 축이 반전되는 것을 원하지 않기 때문에 deltaY = deltaY * -1
주석을 달았습니다 deltaX = deltaX * -1
.