คีย์บอร์ดอินพุตและเอาต์พุตข้อความทำงานอย่างไร


85

สมมติว่าฉันกดAปุ่มในตัวแก้ไขข้อความและสิ่งนี้แทรกตัวละครaในเอกสารและแสดงบนหน้าจอ ฉันรู้ว่าแอปพลิเคชันตัวแก้ไขไม่ได้สื่อสารโดยตรงกับฮาร์ดแวร์ (มีเคอร์เนลและสิ่งต่าง ๆ อยู่ระหว่างนั้น) ดังนั้นสิ่งที่เกิดขึ้นภายในคอมพิวเตอร์ของฉัน

คำตอบ:


100

มีหลายสถานการณ์ที่แตกต่างกัน ฉันจะอธิบายสิ่งที่พบบ่อยที่สุด เหตุการณ์ที่เกิดขึ้นอย่างต่อเนื่องคือ:

  1. อินพุต: เหตุการณ์การกดปุ่มถูกส่งจากฮาร์ดแวร์แป้นพิมพ์ไปยังแอปพลิเคชัน
  2. การประมวลผล: การประยุกต์ใช้ตัดสินใจว่าเพราะคีย์ถูกกดก็ต้องแสดงตัวอักษรAa
  3. เอาท์พุท: แอปพลิเคชั่นให้คำสั่งแสดงaบนหน้าจอ

แอปพลิเคชัน GUI

อินเทอร์เฟซผู้ใช้แบบกราฟิกมาตรฐานโดยพฤตินัยของระบบ unix คือX Window Systemซึ่งมักเรียกว่า X11 เนื่องจากมันเสถียรในโปรโตคอลหลักรุ่นที่ 11 ระหว่างแอพพลิเคชันและเซิร์ฟเวอร์การแสดงผล โปรแกรมที่เรียกว่าเซิร์ฟเวอร์ X ตั้งอยู่ระหว่างเคอร์เนลระบบปฏิบัติการและแอพพลิเคชัน มันให้บริการรวมถึงการแสดงหน้าต่างบนหน้าจอและกดปุ่มส่งสัญญาณไปยังหน้าต่างที่มีโฟกัส

อินพุต

+----------+              +-------------+         +-----+
| keyboard |------------->| motherboard |-------->| CPU |
+----------+              +-------------+         +-----+
             USB, PS/2, …                 PCI, …
             key down/up

ขั้นแรกข้อมูลเกี่ยวกับการกดปุ่มและการปล่อยปุ่มจะถูกส่งจากคีย์บอร์ดไปยังคอมพิวเตอร์และภายในคอมพิวเตอร์ รายละเอียดขึ้นอยู่กับประเภทของฮาร์ดแวร์ ฉันจะไม่อาศัยอยู่ในส่วนนี้มากขึ้นเพราะข้อมูลยังคงเหมือนเดิมตลอดส่วนนี้ของโซ่: มีการกดหรือปล่อยคีย์ที่แน่นอน

         +--------+        +----------+          +-------------+
-------->| kernel |------->| X server |--------->| application |
         +--------+        +----------+          +-------------+
interrupt          scancode             keysym
                   =keycode            +modifiers

เมื่อมีเหตุการณ์ฮาร์ดแวร์เกิดขึ้น CPU จะทริกเกอร์การขัดจังหวะซึ่งทำให้รหัสบางอย่างในเคอร์เนลทำงาน รหัสนี้ตรวจพบว่าเหตุการณ์ฮาร์ดแวร์เป็นการกดปุ่มหรือการเปิดตัวคีย์ที่มาจากแป้นพิมพ์และบันทึกรหัสการสแกนซึ่งระบุรหัส

เซิร์ฟเวอร์ X อ่านเหตุการณ์อินพุตผ่านไฟล์อุปกรณ์ตัวอย่างเช่น/dev/input/eventNNNบน Linux (โดยที่ NNN คือตัวเลข) เมื่อใดก็ตามที่มีเหตุการณ์เคอร์เนลจะส่งสัญญาณว่ามีข้อมูลที่อ่านจากอุปกรณ์นั้น ไฟล์อุปกรณ์ส่งเหตุการณ์สำคัญขึ้น / ลงด้วยรหัสสแกนซึ่งอาจหรืออาจจะไม่เหมือนกันกับค่าที่ส่งโดยฮาร์ดแวร์ (เคอร์เนลอาจแปลรหัสสแกนจากค่าขึ้นอยู่กับคีย์บอร์ดเป็นค่าทั่วไปและ Linux ไม่ ไม่ต้องส่งรหัสสแกนซ้ำที่ไม่ทราบ )

X เรียกสแกนรหัสว่ามันอ่านkeycode เซิร์ฟเวอร์ X เก็บรักษาตารางที่แปลรหัสคีย์เป็นkeysyms (ย่อมาจาก "สัญลักษณ์สัญลักษณ์") การพิมพ์ซ้ำเป็นตัวเลขในขณะที่ keysyms มีชื่อเช่นA, aacute, F1, KP_Add, Control_L, ... ความ keysym อาจแตกต่างกันขึ้นอยู่กับคีย์ตัวปรับแต่งถูกกด ( Shift, Ctrl, ... )

มีสองกลไกในการกำหนดค่าการแมปจากรหัสคีย์เป็น keysyms:

  • xmodmapเป็นกลไกดั้งเดิม มันเป็นรหัสคีย์การแมปตารางอย่างง่าย ๆ ไปยังรายการของ keysyms (ไม่แปร, เปลี่ยน, ... )
  • XKBเป็นกลไกที่ทรงพลังยิ่งขึ้น แต่ซับซ้อนกว่าพร้อมการรองรับตัวดัดแปลงเพิ่มเติมได้ดีขึ้นโดยเฉพาะการกำหนดค่าสองภาษา

แอปพลิเคชันเชื่อมต่อกับเซิร์ฟเวอร์ X และรับการแจ้งเตือนเมื่อกดปุ่มในขณะที่หน้าต่างของแอปพลิเคชันนั้นมีโฟกัส การแจ้งเตือนบ่งชี้ว่ามีการกดหรือปล่อย keysym ที่แน่นอนรวมถึงตัวดัดแปลงใดที่ถูกกดในปัจจุบัน คุณสามารถดู keysyms ได้โดยการรันโปรแกรมxevจากเทอร์มินัล สิ่งที่แอปพลิเคชันทำกับข้อมูลนั้นขึ้นอยู่กับมัน แอปพลิเคชั่นบางตัวมีการเชื่อมโยงคีย์ที่กำหนดค่าได้

ในการกำหนดค่าทั่วไปเมื่อคุณกดปุ่มที่Aไม่มีป้ายโมดิฟายเออร์สิ่งนี้จะส่ง keysym aไปยังแอปพลิเคชัน aถ้าสมัครอยู่ในโหมดที่คุณกำลังพิมพ์ข้อความนี้แทรกตัวอักษร

ความสัมพันธ์ของรูปแบบแป้นพิมพ์และ xmodmapมีรายละเอียดเพิ่มเติมเกี่ยวกับการป้อนข้อมูลด้วยแป้นพิมพ์ เหตุการณ์เมาส์ทำงานใน linux อย่างไร ให้ภาพรวมของการป้อนข้อมูลเมาส์ในระดับที่ต่ำกว่า

เอาท์พุต

+-------------+        +----------+          +-----+         +---------+
| application |------->| X server |---····-->| GPU |-------->| monitor |
+-------------+        +----------+          +-----+         +---------+
               text or              varies          VGA, DVI,
               image                                HDMI, …

มีสองวิธีในการแสดงอักขระ

ดูวัตถุประสงค์ของแบบอักษร XWindows ชนิดต่าง ๆ คืออะไร สำหรับการอภิปรายของการสร้างการแสดงผลข้อความฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์ภายใต้ X11

เกิดอะไรขึ้นระหว่างเซิร์ฟเวอร์ X และหน่วยประมวลผลกราฟิก (โปรเซสเซอร์บนการ์ดจอ) ขึ้นอยู่กับฮาร์ดแวร์เป็นอย่างมาก ระบบที่เรียบง่ายมีเซิร์ฟเวอร์ X วาดอยู่ในขอบเขตหน่วยความจำที่เรียกว่าframebufferซึ่ง GPU เลือกขึ้นมาเพื่อแสดงผล ระบบขั้นสูงเช่นที่พบในพีซีหรือสมาร์ทโฟนศตวรรษที่ 21 อนุญาตให้ GPU ดำเนินการบางอย่างโดยตรงเพื่อประสิทธิภาพที่ดีขึ้น ในท้ายที่สุด GPU ส่งพิกเซลเนื้อหาของหน้าจอเป็นพิกเซลทุกเสี้ยววินาทีไปยังจอภาพ

แอปพลิเคชันโหมดข้อความที่ทำงานในเทอร์มินัล

หากเท็กซ์เอดิเตอร์ของคุณเป็นแอ็พพลิเคชันโหมดข้อความที่รันในเทอร์มินัลแสดงว่าเป็นเทอร์มินัลซึ่งเป็นแอปพลิเคชันสำหรับจุดประสงค์ของส่วนด้านบน ในส่วนนี้ฉันอธิบายอินเตอร์เฟสระหว่างแอปพลิเคชันโหมดข้อความและเทอร์มินัล ก่อนอื่นฉันอธิบายกรณีของเทอร์มินัลอีมูเลเตอร์ที่ทำงานภายใต้ X11 ความแตกต่างที่แน่นอนระหว่าง 'terminal', 'shell', 'tty' และ 'console' คืออะไร? อาจเป็นพื้นหลังที่เป็นประโยชน์ที่นี่ หลังจากอ่านสิ่งนี้แล้วคุณอาจต้องการอ่านรายละเอียดเพิ่มเติมสิ่งที่เป็นความรับผิดชอบของแต่ละองค์ประกอบ Pseudo-Terminal (PTY) (ซอฟต์แวร์ด้านหลักด้านทาส)

อินพุต

      +-------------------+               +-------------+
----->| terminal emulator |-------------->| application |
      +-------------------+               +-------------+
keysym                     character or
                           escape sequence

เทอร์มินัลอีมูเลเตอร์รับเหตุการณ์เช่น“ Leftถูกกดขณะที่ไม่Shiftทำงาน” อินเตอร์เฟสระหว่างเทอร์มินัลอีมูเลเตอร์และแอปพลิเคชันโหมดข้อความคือpseudo-terminal (pty)ซึ่งเป็นอุปกรณ์ตัวอักษรที่ส่งไบต์ เมื่อเทอร์มินัลอีมูเลเตอร์ได้รับเหตุการณ์การกดปุ่มมันจะแปลงสิ่งนี้ให้เป็นหนึ่งไบต์หรือมากกว่านั้นซึ่งแอปพลิเคชันจะอ่านจากอุปกรณ์ pty

ตัวอักษรพิมพ์นอกช่วง ASCII จะถูกส่งเป็นหนึ่งหรือมากกว่าหนึ่งไบต์ขึ้นอยู่กับตัวละครและการเข้ารหัส ตัวอย่างเช่นในการเข้ารหัส UTF-8ของชุดอักขระ Unicodeอักขระในช่วงASCIIจะถูกเข้ารหัสเป็นไบต์เดียวในขณะที่อักขระที่อยู่นอกช่วงนั้นจะถูกเข้ารหัสเป็นหลายไบต์

กดปุ่มที่สอดคล้องกับคีย์ฟังก์ชันหรือตัวอักษรที่พิมพ์ได้มีการปรับเปลี่ยนเช่นCtrlหรือAltจะส่งเป็นลำดับหนี โดยทั่วไปแล้วลำดับ Escape ประกอบด้วยอักขระescape (ค่าไบต์ 27 = 0x1B = \033บางครั้งแทน^[หรือ\e) ตามด้วยอักขระที่พิมพ์ได้หนึ่งตัวหรือมากกว่า คีย์หรือชุดคีย์สองสามตัวมีอักขระควบคุมที่สอดคล้องกับพวกเขาในการเข้ารหัสตาม ASCII (ซึ่งค่อนข้างมากของพวกมันทั้งหมดที่ใช้อยู่ในปัจจุบันรวมถึง Unicode): Ctrl+ letterให้ค่าอักขระในช่วง 1-26 Escคืออักขระ escape เห็นข้างต้นและยังเป็นเช่นเดียวกับCtrl+ [, TabเหมือนกับCtrl+ I,ReturnเหมือนกับCtrl+ Mฯลฯ

เทอร์มินัลที่แตกต่างกันส่ง escape sequences ที่แตกต่างกันสำหรับคีย์ที่ระบุหรือคีย์ผสม โชคดีที่การสนทนาไม่เป็นความจริง: เนื่องจากมีการเรียงลำดับแล้วในทางปฏิบัติจะมีการรวมคีย์หนึ่งชุดที่เข้ารหัส หนึ่งยกเว้นเป็นตัวละคร 127 = = 0x7F \0177ซึ่งมักจะเป็นแต่บางครั้งBackspaceDelete

ในเทอร์มินัลถ้าคุณพิมพ์Ctrl+ Vตามด้วยชุดคีย์นี้จะแทรกไบต์แรกของลำดับ escape จากชุดคีย์อย่างแท้จริง เนื่องจากโดยทั่วไปแล้ว escape sequences จะประกอบด้วยอักขระที่พิมพ์ได้หลังจากตัวแรกเท่านั้นนี่จะเป็นการแทรกลำดับ escape ทั้งหมดอย่างแท้จริง ดูตารางการผูกกุญแจ? สำหรับการสนทนาของ zsh ในบริบทนี้

ขั้วอาจส่งลำดับหนีเหมือนกันสำหรับการผสมปรับปรุงบางอย่าง (เช่นหลายขั้วส่งอักขระช่องว่างสำหรับทั้งสองSpaceและShift+ Space; xterm มีโหมดที่จะแยกแยะความแตกต่างรวมกันปรับปรุงแต่ขั้วบนพื้นฐานของห้องสมุด VTE นิยมทำไม่ได้ ) ไม่กี่คีย์จะไม่ถูกส่งเลยตัวอย่างเช่นปุ่มตัวดัดแปลงหรือคีย์ที่ทริกเกอร์การโยงเทอร์มินัลอีมูเลเตอร์ (เช่นคำสั่งคัดลอกหรือวาง)

มันขึ้นอยู่กับแอพพลิเคชั่นในการแปล escape sequences เป็นชื่อคีย์สัญลักษณ์หากต้องการ

เอาท์พุต

+-------------+               +-------------------+
| application |-------------->| terminal emulator |--->
+-------------+               +-------------------+
               character or
               escape sequence

เอาต์พุตค่อนข้างง่ายกว่าอินพุต หากแอ็พพลิเคชันส่งอักขระไปยังไฟล์อุปกรณ์ pty เทอร์มินัลอีมูเลเตอร์จะแสดงที่ตำแหน่งเคอร์เซอร์ปัจจุบัน (เทอร์มินัลอีมูเลเตอร์รักษาตำแหน่งเคอร์เซอร์และเลื่อนถ้าเคอร์เซอร์จะอยู่ด้านล่างของหน้าจอ) แอปพลิเคชันยังสามารถส่งออกลำดับหนี (ส่วนใหญ่เริ่มต้นด้วย^[หรือ^]) เพื่อบอกเทอร์มินัลเพื่อดำเนินการต่าง ๆ เช่นการย้ายเคอร์เซอร์ การเปลี่ยนคุณสมบัติข้อความ (สี, ตัวหนา, ... ) หรือการลบส่วนหนึ่งของหน้าจอ

Escape sequences ที่สนับสนุนโดยเทอร์มินัลอีมูเลเตอร์ได้อธิบายไว้ในฐานข้อมูลtermcapหรือterminfo ส่วนใหญ่จำลอง terminal ในปัจจุบันมีค่อนข้างใกล้ชิดกับxterm ดูเอกสารประกอบเกี่ยวกับตัวแปร LESS_TERMCAP_ *? สำหรับการอภิปรายนานขึ้นของฐานข้อมูลความสามารถของเทอร์มินัลและวิธีหยุดเคอร์เซอร์จากการกระพริบและฉันสามารถตั้งค่าสีเทอร์มินัลของเครื่องท้องถิ่นของฉันให้ใช้สีของเครื่องที่ฉัน ssh เข้าไปได้หรือไม่? สำหรับตัวอย่างการใช้งานบางอย่าง

แอปพลิเคชันทำงานในคอนโซลข้อความ

หากแอปพลิเคชันทำงานโดยตรงในคอนโซลข้อความเช่นเทอร์มินัลที่เตรียมไว้โดยเคอร์เนลแทนที่จะใช้แอปพลิเคชันเทอร์มินัลอีมูเลเตอร์จะใช้หลักการเดียวกันนี้ อินเตอร์เฟสระหว่างเทอร์มินัลและแอ็พพลิเคชันยังคงเป็นสตรีมไบต์ที่ส่งอักขระโดยใช้คีย์พิเศษและคำสั่งที่เข้ารหัสเป็นลำดับ escape

แอปพลิเคชันระยะไกลเข้าถึงได้ผ่านเครือข่าย

แอปพลิเคชันข้อความระยะไกล

หากคุณรันโปรแกรมบนเครื่องระยะไกลเช่นผ่านSSHโปรโตคอลการสื่อสารเครือข่ายจะถ่ายทอดข้อมูลในระดับ pty

+-------------+           +------+           +-----+           +----------+
| application |<--------->| sshd |<--------->| ssh |<--------->| terminal |
+-------------+           +------+           +-----+           +----------+
               byte stream        byte stream       byte stream
               (char/seq)         over TCP/…        (char/seq)

นี่คือส่วนใหญ่โปร่งใสยกเว้นว่าบางครั้งฐานข้อมูลสถานีระยะไกลอาจไม่ทราบความสามารถทั้งหมดของสถานีท้องถิ่น

แอปพลิเคชั่น X11 ระยะไกล

โปรโตคอลการสื่อสารระหว่างแอปพลิเคชันที่เซิร์ฟเวอร์เป็นตัวเองเป็นไบต์สตรีมที่สามารถส่งผ่านโปรโตคอลเครือข่ายเช่น SSH

+-------------+            +------+        +-----+            +----------+
| application |<---------->| sshd |<------>| ssh |<---------->| X server |
+-------------+            +------+        +-----+            +----------+
               X11 protocol        X11 over       X11 protocol
                                   TCP/…

สิ่งนี้ส่วนใหญ่โปร่งใสยกเว้นว่าคุณลักษณะการเร่งความเร็วบางอย่างเช่นการถอดรหัสภาพยนตร์และการเรนเดอร์ 3D ที่ต้องมีการสื่อสารโดยตรงระหว่างแอปพลิเคชันและจอแสดงผลจะไม่สามารถใช้ได้


ไม่แน่ใจว่าสมบูรณ์ แต่เนื่องจากคำตอบคือโดยทั่วไปค่อนข้างรายละเอียดผมสงสัยว่าถ้าเป็นส่วนหนึ่งที่ระบุว่า "แอพลิเคชันที่ทำงานอยู่ในคอนโซลข้อความ" ไม่อาจมีว่ามีสิ่งที่ต้องการman 5 keymapsจะใช้สำหรับการแปลไปkeycodes scancodesในขณะที่กล่าวถึงคล้ายกันโดยทั่วไป แต่ก็เป็นชุดเครื่องมือ / โปรแกรมที่แตกต่างกันโดยสิ้นเชิง ถัดจากนั้นคำตอบคือ +1 และยอดเยี่ยมเนื่องจากคำถามที่เกี่ยวข้องที่ฝังอยู่
มนุษยชาติ

ฉันพบPgUpและCtrl+PgUpแยกไม่ออกใน tty1 (TERM = linux) การแม็พ keysym -> control สามารถกำหนดค่าได้หรือไม่?
stewbasic

@stewbasic ใช่กับ keymap loadkeysโหลดโดย ค้นหาคำถามที่ติดแท็กลินุกซ์ คอนโซล แป้นพิมพ์รูปแบบ
Gilles

@Gilles ขอบคุณ! มันน่าสังเกตว่า loadkeys จะเปลี่ยนทั้งการแม็พ keycode -> keysym และ keysym -> escape sequence (ตอนนี้ไม่ได้ชัดเจนสำหรับฉัน)
stewbasic

1
ว้าวนี่จะต้องเป็นคำตอบที่ดีที่สุดที่ฉันเคยเห็นใน Stackexchange - การจัดระเบียบอย่างดีตอบคำถามให้บริบทที่เกี่ยวข้องการอ้างอิงโยงคำตอบที่มีประโยชน์อื่น ๆ และแม้จะมีศิลปะ ASCII ที่ดี!
Johntron

4

หากคุณต้องการที่จะเห็นสิ่งนี้ในระบบยูนิกซ์ที่มีขนาดเล็กพอที่จะเข้าใจขุดลงไปในXv6 มันเป็นตำนาน Unix รุ่นที่ 6 มากหรือน้อยที่กลายเป็นฐานของคำวิจารณ์ที่มีชื่อเสียงของ John Lion ที่มีมายาวนานราวกับ samizdat รหัสของมันถูกทำใหม่เพื่อคอมไพล์ภายใต้ ANSI C และนำการพัฒนาที่ทันสมัยเช่นมัลติโปรเซสเซอร์เข้าบัญชี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.