大家有没有遇到过只在某特定系统上独有,但好用的软件或系统内置功能
讨论范围
- 主要是桌面端与桌面端、移动端与移动端对比
- 不仅限于独占,比如 Linux 和 Mac 有,但 Windows 没有也算
- 同系统不同版本也算,比如 Win7 有,但 Win11 没有
- 也许有但可能比较小众没有被发现也算
- 也许有"平替",但"平替"过于简陋或体验太差也算
- 交互操作也算
- 不考虑:游戏、杀毒、虚拟机
发帖目的
- 发掘好用的软件或功能
- 为体验新系统做准备
无意比较各系统的优劣,因为比较主观所以请大家友善讨论
大家有没有遇到过只在某特定系统上独有,但好用的软件或系统内置功能
讨论范围
发帖目的
无意比较各系统的优劣,因为比较主观所以请大家友善讨论
说说个人体验,一直用惯了 Windows,因为其他原因用过一段时间的 Mac,我个人主观觉得窗口管理功能这一块 Windows 真是做的比 Mac 好,Windows 各种软件窗口切换就很流畅,Mac 我觉得太乱了,随时找不到想要的窗口在哪,还有全屏化切来切去全屏一多就不好记要切到哪。Dock 栏两边空一截觉得难受特别是窗口放大之后(非全屏)整个屏幕下面留个 Dock 还空两边太扎眼了。好看归好看但用着不如 Windows 方便。
上面仅是我个人用过半年多 Mac 主观感受,无意引战,要是有人觉得我说的不对没掌握到 Mac 窗口管理的精髓可以留下评论,欢迎赐教。
赞同,补充一条,MacOS 的文件管理器访达难用无比,犹如行舟无桨,却没有人开发出可与 Windows 上 Directory Opus、Totalcmd 的一半并肩的文件管理增强工具
Windows的兼容性,真的是没比的。
特别是以前的微软。
作为开发者和使用者,是真的喜欢。
不仅Windows,以前的Windows Mobile(不是wp、w10m) 的兼容性同样也是如此。ppc2002上的app在wm6.5.3上照样完美运行。
后来随 .net framework的发布,wm端专用的 .Net
Compact framework 也同步发布。这样使用 .net cf开发的移动端app可以直接在电脑端运行,而不需要模拟器,是真的方便。
不过后来的wp直接不兼容wm,可以说是wp灭亡的祸根。
linux下没有everything
![]()
Linux 桌面各个窗口管理器一般有个功能是按住 alt 然后就可以按左键拖动窗口,右键修改窗口大小。
这个功能我太习惯了,以至于让我改用 Windows 非常难以适应。
不过这个功能好像 GNOME 没有。
这个autohotkey脚本适合你
#Persistent
#SingleInstance, Force
; Hotkeys
; 1. Alt + LButton = Move window
; 2. Alt + Shift + LButton = Move window along X axis only
; 3. Alt + Ctrl + LButton = Move window along Y axis only
; 4. Alt + RButton = Resize
; 5. Alt + Shift + RButton = Resize window width only
; 6. Alt + Ctrl + RButton = Resize window height only
; 7. Alt + MButton OR Alt + Win + C = Change text within window
; 8. Win + LButton = Enable/Disable Window
Menu, TRAY, NoStandard
Menu, TRAY, MainWindow ; For compiled scripts
Menu, TRAY, Add, &Reload, Reload
Menu, TRAY, Add, E&xit, Exit
CoordMode, Mouse
SetWinDelay, -1
g_iIntraMonitorThreashold := 350 ; pixels
return ; End auto-execute
Reload:
Reload
Exit:
ExitApp
#!c::
{
gosub ChangeWindowTitle
return
}
; Simple hotkeys like ~Alt & ~LButton cannot be used becuase this does not disable clicks inside of windows
Shift & ~Alt::
Ctrl & ~Alt::
~Alt::
{
Hotkey, *LButton, Alt_And_LButton, On
Hotkey, *RButton, Alt_And_RButton, On
Hotkey, *MButton, ChangeWindowTitle, On
KeyWait, Alt
Hotkey, *LButton, Off
Hotkey, *RButton, Off
Hotkey, *MButton, Off
if (A_ThisHotkey = "*LButton")
gosub Alt_And_LButton
else if (A_ThisHotkey = "*RButton")
gosub Alt_And_RButton
else if (A_ThisHotkey = "*MButton")
gosub ChangeWindowTitle
return
}
Alt_And_LButton:
{
iPrevMouseX := iPrevMouseY := A_Blank
MouseGetPos,,, hWnd
if (IsApprovedHwnd(hWnd))
{
g_bUseXThreshold := g_bUseYThreshold := true
g_iXDeltaAtLeftCorner := g_iXDeltaAtRightCorner := g_iYDeltaAtTopCorner := g_iYDeltaAtBottomCorner := 0
while (GetKeyState("Alt", "P") && GetKeyState("LButton", "P"))
{
bIgnoreX := GetKeyState("Ctrl", "P")
bIgnoreY := GetKeyState("Shift", "P")
MouseGetPos, iMouseX, iMouseY
iMouseX := iMouseX
iMouseY := iMouseY
WinGetPos, iX, iY, iWndW, iWndH, ahk_id %hWnd%
iXDelta := bIgnoreX ? 0 : iMouseX - (iPrevMouseX == A_Blank ? iMouseX : iPrevMouseX)
iYDelta := bIgnoreY ? 0 : iMouseY - (iPrevMouseY == A_Blank ? iMouseY : iPrevMouseY)
if (iXDelta == 0 && iYDelta == 0)
{
iPrevMouseX := iMouseX
iPrevMouseY := iMouseY
continue
}
iX := iX + iXDelta
iY := iY + iYDelta
bMoveX := bMoveY := true
rectMonMouseIsOn := GetMonitorRectAt(iMouseX, iMouseY)
; if we have passed a monitor corner over onto another monitor, or else we have shifted directions towards to opposite corner of the monitor, reset
if (abs(iMouseX) - abs(iMouseXPosAtCorner) < g_iIntraMonitorThreashold)
g_bUseXThreshold := true
if (abs(iMouseY) - abs(iMouseYPosAtCorner) < g_iIntraMonitorThreashold)
g_bUseYThreshold := true
if (g_bUseXThreshold)
{
if (!bIgnoreX)
{
if (iXDelta < 0 ; moving window to the left
&& iX - iXDelta >= rectMonMouseIsOn.left ; the left corner of the wnd is not already past the monitor's left corner
&& iX < rectMonMouseIsOn.left) ; we are trying to move the window past the left corner
{
g_iXDeltaAtLeftCorner += abs(iXDelta)
if (g_iXDeltaAtLeftCorner < g_iIntraMonitorThreashold)
{
bMoveX := false
g_bUseXThreshold := true
}
else
{
bMoveX := true
g_bUseXThreshold := false
iMouseXPosAtCorner := iMouseX
g_iXDeltaAtLeftCorner := 0
}
}
else if (iXDelta > 0 ; moving window to the right
&& iX - iXDelta + iWndW <= rectMonMouseIsOn.right ; the right corner of the wnd is not already past the monitor's right corner
&& (iX + iWndW) > rectMonMouseIsOn.right) ; we are trying to move the window past the right corner
{
g_iXDeltaAtRightCorner += abs(iXDelta)
if (g_iXDeltaAtRightCorner < g_iIntraMonitorThreashold)
{
bMoveX := false
g_bUseXThreshold := true
}
else
{
bMoveX := true
g_bUseXThreshold := false
iMouseXPosAtCorner := iMouseX
g_iXDeltaAtRightCorner := 0
}
}
}
}
if (g_bUseYThreshold)
{
if (!bIgnoreY)
{
if (iYDelta < 0 ; moving window to the bottom
&& iY - iYDelta >= rectMonMouseIsOn.top ; the top corner of the wnd is not already past the monitor's top corner
&& iY < rectMonMouseIsOn.top) ; we are trying to move the window past the top corner
{
g_iYDeltaAtBottomCorner += abs(iYDelta)
if (g_iYDeltaAtBottomCorner < g_iIntraMonitorThreashold)
{
bMoveY := false
g_bUseYThreshold := true
}
else
{
bMoveY := true
g_bUseYThreshold := false
iMouseYPosAtCorner := iMouseY
g_iYDeltaAtBottomCorner := 0
}
}
else if (iYDelta > 0 ; moving window to the right
&& iY - iYDelta + iWndH <= rectMonMouseIsOn.bottom ; the right corner of the wnd is not already past the monitor's bottom corner
&& (iY + iWndH) > rectMonMouseIsOn.bottom) ; we are trying to move the window past the bottom corner
{
g_iYDeltaAtTopCorner += abs(iYDelta)
if (g_iYDeltaAtTopCorner < g_iIntraMonitorThreashold)
{
bMoveY := false
g_bUseYThreshold := true
}
else
{
bMoveY := true
g_bUseYThreshold := false
iMouseYPosAtCorner := iMouseY
g_iYDeltaAtTopCorner := 0
}
}
}
}
WinMove, ahk_id %hWnd%,, % bMoveX ? iX : "", bMoveY ? iY : ""
iPrevMouseX := iMouseX
iPrevMouseY := iMouseY
}
}
return
}
Alt_And_RButton:
{
iPrevMouseX := iPrevMouseY := A_Blank
g_bUseWThreshold := g_bUseHThreshold := true
MouseGetPos,,, hWnd
if (IsApprovedHwnd(hWnd))
{
while (GetKeyState("Alt", "P") && GetKeyState("RButton", "P"))
{
bIgnoreW := GetKeyState("Ctrl", "P")
bIgnoreH := GetKeyState("Shift", "P")
MouseGetPos, iMouseX, iMouseY
iMouseX := iMouseX
iMouseY := iMouseY
WinGetPos, iX, iY, iWndW, iWndH, ahk_id %hWnd%
iXDelta := bIgnoreW ? 0 : iMouseX - (iPrevMouseX == A_Blank ? iMouseX : iPrevMouseX)
iYDelta := bIgnoreH ? 0 : iMouseY - (iPrevMouseY == A_Blank ? iMouseY : iPrevMouseY)
if (iXDelta == 0 && iYDelta == 0)
{
iPrevMouseX := iMouseX
iPrevMouseY := iMouseY
continue
}
iWndW := iWndW + iXDelta
iWndH := iWndH + iYDelta
bMoveW := bMoveH := true
rectMonMouseIsOn := GetMonitorRectAt(iMouseX, iMouseY)
; if we have passed a monitor corner over onto another monitor, or else we have shifted directions towards to opposite corner of the monitor, reset
if (abs(iMouseX) - abs(iMouseXPosAtCorner) < g_iIntraMonitorThreashold)
g_bUseWThreshold := true
if (abs(iMouseY) - abs(iMouseYPosAtCorner) < g_iIntraMonitorThreashold)
g_bUseHThreshold := true
if (g_bUseWThreshold)
{
if (!bIgnoreW)
{
if (iXDelta < 0 ; moving window to the left
&& iX - iXDelta >= rectMonMouseIsOn.left ; the left corner of the wnd is not already past the monitor's left corner
&& iX < rectMonMouseIsOn.left) ; we are trying to move the window past the left corner
{
g_iXDeltaAtLeftCorner += abs(iXDelta)
if (g_iXDeltaAtLeftCorner < g_iIntraMonitorThreashold)
{
bMoveW := false
g_bUseWThreshold := true
}
else
{
bMoveW := true
g_bUseWThreshold := false
iMouseXPosAtCorner := iMouseX
g_iXDeltaAtLeftCorner := 0
}
}
else if (iXDelta > 0 ; moving window to the right
&& iX - iXDelta + iWndW <= rectMonMouseIsOn.right ; the right corner of the wnd is not already past the monitor's right corner
&& (iX + iWndW) > rectMonMouseIsOn.right) ; we are trying to move the window past the right corner
{
g_iXDeltaAtRightCorner += abs(iXDelta)
if (g_iXDeltaAtRightCorner < g_iIntraMonitorThreashold)
{
bMoveW := false
g_bUseWThreshold := true
}
else
{
bMoveW := true
g_bUseWThreshold := false
iMouseXPosAtCorner := iMouseX
g_iXDeltaAtRightCorner := 0
}
}
}
}
if (g_bUseHThreshold)
{
if (!bIgnoreH)
{
if (iYDelta < 0 ; moving window to the bottom
&& iY - iYDelta >= rectMonMouseIsOn.top ; the top corner of the wnd is not already past the monitor's top corner
&& iY < rectMonMouseIsOn.top) ; we are trying to move the window past the top corner
{
g_iYDeltaAtBottomCorner += abs(iYDelta)
if (g_iYDeltaAtBottomCorner < g_iIntraMonitorThreashold)
{
bMoveH := false
g_bUseHThreshold := true
}
else
{
bMoveH := true
g_bUseHThreshold := false
iMouseYPosAtCorner := iMouseY
g_iYDeltaAtBottomCorner := 0
}
}
else if (iYDelta > 0 ; moving window to the right
&& iY - iYDelta + iWndH <= rectMonMouseIsOn.bottom ; the right corner of the wnd is not already past the monitor's bottom corner
&& (iY + iWndH) > rectMonMouseIsOn.bottom) ; we are trying to move the window past the bottom corner
{
g_iYDeltaAtTopCorner += abs(iYDelta)
if (g_iYDeltaAtTopCorner < g_iIntraMonitorThreashold)
{
bMoveH := false
g_bUseHThreshold := true
}
else
{
bMoveH := true
g_bUseHThreshold := false
iMouseYPosAtCorner := iMouseY
g_iYDeltaAtTopCorner := 0
}
}
}
}
WinMove, ahk_id %hWnd%,,,, % bMoveW ? iWndW : "", bMoveH ? iWndH : ""
iPrevMouseX := iMouseX
iPrevMouseY := iMouseY
}
}
return
}
ChangeWindowTitle:
{
; Turn off hotkeys so that the LButton is not responise
Hotkey, *LButton, Off
Hotkey, *RButton, Off
Hotkey, *MButton, Off
; This hotkey seems to be triggered twice every time it is activated, so g_iTimeAtThisExecution is used to prevent double-execution
g_iTimeAtThisExecution := SubStr(A_Now, StrLen(A_Now) - 3, 4)
if (A_ThisHotkey = "*MButton" && g_iTimeAtLastExecution != A_Blank && g_iTimeAtThisExecution - g_iTimeAtLastExecution < 1)
return
MouseGetPos,,, hWnd
if (IsApprovedHwnd(hWnd))
{
WinGetTitle, sExistingTitle, ahk_id %hWnd%
InputBox, sNewTitle, Set Window Title,,,,,,,,, %sExistingTitle%
g_iTimeAtLastExecution := SubStr(A_Now, StrLen(A_Now) - 3, 4)
if (ErrorLevel)
return
WinSetTitle, ahk_id %hWnd%,, %sNewTitle%
}
return
}
#LButton::
{
MouseGetPos,,, hWnd
if (IsApprovedHwnd(hWnd))
{
sEnable := (DllCall("IsWindowEnabled", uint, hWnd) ? "Disable" : "Enable")
WinSet, %sEnable%,, ahk_id %hWnd%
TT_Out("Window " sEnable "d!")
}
return
}
!+C::
{
MouseGetPos,,,, hCtrl, 2
ControlGetText, sCtrlTxt,, ahk_id %hCtrl%
ControlGetPos, iX, iY, iW, iH,, ahk_id %hCtrl%
if !((iX == A_Blank || iY == A_Blank || iW == A_Blank || iH == A_Blank))
clipboard := "Control:`t" sCtrlTxt "`nLeft:`t" iX "`nTop:`t" iY "`nRight:`t" iW "`nBottom:`t" iH
return
}
TT_Out(sOutput)
{
Tooltip, %sOutput%
SetTimer, TT_Out, 2500
return
}
TT_Out:
{
Tooltip
SetTimer, TT_Out, Off
return
}
IsApprovedHwnd(hWnd)
{
WinGetClass, sClass, ahk_id %hWnd%
return !(sClass== "WorkerW"
|| sClass == "Shell_TrayWnd"
|| sClass== "Progman"
|| sClass== "SideBar_HTMLHostWindow")
}
/*
===============================================================================
Function: wp_GetMonitorAt (Modified by Verdlin to return monitor rect)
Get the index of the monitor containing the specified x and y coordinates.
Parameters:
x,y - Coordinates
default - Default monitor
Returns:
array of monitor coordinates
Author(s):
Original - Lexikos - http://www.autohotkey.com/forum/topic21703.html
===============================================================================
*/
GetMonitorRectAt(x, y, default=1)
{
SysGet, m, MonitorCount
; Iterate through all monitors.
Loop, %m%
{ ; Check if the window is on this monitor.
SysGet, Mon%A_Index%, MonitorWorkArea, %A_Index%
if (x >= Mon%A_Index%Left && x <= Mon%A_Index%Right && y >= Mon%A_Index%Top && y <= Mon%A_Index%Bottom)
return {left: Mon%A_Index%Left, right: Mon%A_Index%Right, top: Mon%A_Index%Top, bottom: Mon%A_Index%Bottom}
}
return {left: Mon%default%Left, right: Mon%default%Right, top: Mon%default%Top, bottom: Mon%default%Bottom}
}
如果您平时用的桌面环境是 MATE、Xfce、Cinnamon、GNOME 等基于 GTK+ 的桌面环境,或者窗口管理器,可以试一试 FSearch:
GUI 使用 GTK3 编写,界面和 Everything 很像,搜索速度也很快。
我之前试过一个专门的 alt 软件。但是没满足我的功能。后来我就没再折腾了。
如果 win 能够自带的话或许会好一些。
另外一个 windows 经常缺少的功能是 sshfs,也可以通过安装第三方软件解决。但是不如 linux 底下的好用。各种 linux 桌面一般也是自带。
Totalcmd mac上一直没有找到合适的
那当然是windows的微信,就是不支持深色模式。。。。。
windows上DesktopOK有这个功能,默认不开启,可以在菜单-工具-Alt+Drag功能里面开启
包管理器吧。离开了 Windows 然后再也没回去,一部分也是因为喜欢 Linux 发行版的包管理器设计。
Windows 上的一些平替:
现在用的是 Arch 的 pacman 包管理器,目前来看 AUR 上这种「用户编写包 + 集中管理包」的方式是最有利于生态发展的。
AltSnap 不用折腾,装上就用,因为其操作行为是复制自 Linux 并进行了部分扩展。
AutoHotkey 脚本也挺好,用大佬写的也不用折腾 ![]()
对。就是这个 AltSnap,我装上了之后根本没有效果。我的操作系统是 Windows Server 2008 r2,不知道是不是服务器操作系统的原因。
Ubuntu 可以在任务栏(或者说应该叫 Dock)上滚动鼠标滚轮来切换工作区
Windows 上好像没找到在任务栏区域检测鼠标行为来切换虚拟桌面的软件
右键改大小确实很方便
GNOME只能Alt+F7