大家有没有遇到过只在某特定系统上独有,但好用的软件或系统内置功能
讨论范围
- 主要是桌面端与桌面端、移动端与移动端对比
- 不仅限于独占,比如 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 脚本也挺好,用大佬写的也不用折腾
windows有ahk,linux無
https://alternativeto.net/software/autohotkey/?platform=linux
对。就是这个 AltSnap,我装上了之后根本没有效果。我的操作系统是 Windows Server 2008 r2,不知道是不是服务器操作系统的原因。
Ubuntu 可以在任务栏(或者说应该叫 Dock)上滚动鼠标滚轮来切换工作区
Windows 上好像没找到在任务栏区域检测鼠标行为来切换虚拟桌面的软件
右键改大小确实很方便
GNOME只能Alt+F7