Jawaban:
Smart Scroll melakukan apa yang Anda cari, dengan fitur 'Grab Scroll'. Tetapkan ke 'Tombol 3 (Tengah)' dan menyeret pada kedua sumbu akan bekerja di aplikasi seperti browser (Chrome), Terminal, Adobe Photoshop, dan Finder - tidak ada aplikasi yang saya coba belum bekerja dengan itu (menggunakan 4.0 betas ke atas). Ini memiliki uji coba gratis.
Saya melakukannya dengan Hammerspoon dengan skrip konfigurasi berikut yang terinspirasi oleh utas ini: https://github.com/tekezo/Karabiner/issues/814#issuecomment-337643019
Langkah:
Open Config
Rekatkan lua
skrip berikut ke dalam konfigurasi:
-- 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()
Smooze melakukan itu, antara lain. (Saya pengembang)
Apa yang membedakannya dari saran lain adalah kemampuan untuk menggunakannya di setiap aplikasi mac sambil mengidentifikasi tautan, misalnya. (jika Anda menggunakan seret tombol tengah untuk meraih dan melempar, tetapi tetap ingin bahwa klik tombol tengah akan bertindak sebagai tombol tengah)
Dengan Smooze lebih mirip grab-drag-throw daripada grab-drag. Rilis ini mempengaruhi momentum dan animasi dari gulir, mirip dengan gulir iPhone.
Ada aplikasi open source yang sangat bagus bernama Karabiner yang akan melakukan ini dan banyak lagi (Keyboard dan mouse remapping dll). Lihat pertanyaan ini untuk beberapa contoh. Juga untuk produsen tertentu mereka menyediakan perangkat lunak kontrol kustom yang memungkinkan untuk fungsionalitas yang ditingkatkan / dimodifikasi (misalnya Pusat Kontrol Logitech).
Seperti disebutkan dalam komentar di bawah ini bahwa sementara versi baru 'Karabiner Elements' telah dirilis untuk MacOS Sierra (10.12) dan seterusnya, hanya menyediakan remapping berbasis keyboard sejauh ini - jadi saat ini remapping mouse tidak dapat dilakukan dengan itu.
Namun Hammerspoon adalah alat open source gratis lain yang dapat digunakan, di antara banyak hal lain, untuk memetakan kembali tombol pada mouse (dan / atau keyboard) ke berbagai fungsi. Anda harus menginstal alat dan menyediakannya dengan beberapa konfigurasi yang sesuai - lihat contoh di sini untuk memetakan ulang mouse.
Untuk memeriksa jenis acara dan mouseEventButtonNumber yang sedang dibuat oleh perangkat Anda, Anda dapat menjalankan ini (cukup salin / tempel 4 baris ke konsol) di konsol Hammerspoon (Gunakan reload config
untuk menghentikannya):
hs.eventtap.new({"all"},function(e)
print(e,"mouseEventButtonNumber:",
e:getProperty(hs.eventtap.event.properties['mouseEventButtonNumber']))
end):start()
Catatan: Jika Anda telah menginstal alat Logitech Control Center (LCC) - itu mengambil peristiwa langsung dari perangkat Logitech menggunakan modul kernel yang terpasang sehingga Hammerspoon tidak dapat melihatnya. Anda harus menghapus LCC jika Anda ingin memetakan kembali tombol mouse menggunakan Hammerspoon.
Tergantung pada perangkat lunak - misalnya, Firefox mendukungnya, sedangkan Google Chrome tidak.
Sayangnya, saat ini tidak ada perangkat lunak untuk mengaktifkan fitur sistem seperti itu di OS X.
Saya menggunakan Better Touch Tool untuk menetapkan Ctrl + klik tengah ke PgUp, dan Option + klik tengah ke PgDown. Ini gratis, perangkat lunak luar biasa, dan berfungsi dengan baik.
+1 untuk Hammerspoon dan skrip, mouse / trackball yang normal membuat saya marah pada Mac.
Saya menulis satu untuk menggulir sementara tombol tengah mouse ditekan ke bawah - semakin jauh Anda menggerakkan mouse semakin cepat akan bergulir.
Klik masih berfungsi seperti klik normal dengan zona mati 5 piksel sehingga Anda tidak perlu menjaga mouse tetap diam antara menekan dan melepaskan 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
------------------------------------------------------------------------------------------
deltaX = deltaY * -1
seharusnya deltaY = deltaY * -1
dan saya berkomentar deltaX = deltaX * -1
karena saya tidak ingin sumbu X terbalik.